4、数字签名基础:非对称加密原理

聊到固件完整性校验,数字签名是绕不开的核心技术。说白了,它就是给固件贴上一张「防伪标签」,谁要是敢篡改,一验就知道。

我记得刚入行那会儿,总觉得数字签名是个黑盒子——公钥、私钥、签名、验签,听着就头大。后来亲手调过几回签名验证的代码,踩过坑,才真正理解这东西到底怎么工作的。

4.1 非对称加密:公钥与私钥

传统对称加密,好比一把钥匙开一把锁。加密和解密用同一个密钥,问题来了——你怎么安全地把这把钥匙交给对方?

非对称加密就不一样了。它用一对密钥:公钥和私钥。

  • 私钥:自己死死藏好,谁都不给。签名用的就是它。
  • 公钥:公开出去,谁要都行。验签用的就是它。

你想想看,私钥签名,公钥验签。私钥只有你自己有,所以签名只有你能生成。别人拿到公钥,只能验证签名是不是你签的,但伪造不了。

核心原则:私钥签名,公钥验签。私钥永远不离开你的安全环境。

我在项目里见过有人把私钥硬编码在固件里,结果固件被反编译,私钥直接暴露。嗯,这属于「教科书级」的失误,千万别学。

4.2 数字签名流程:签名与验签

数字签名到底怎么做的?我拆成两步讲清楚。

4.2.1 签名过程(发送方)

  1. 对固件数据计算哈希值(比如 SHA-256)。
  2. 用私钥对哈希值加密,生成签名。
  3. 把固件 + 签名一起发出去。

你看,签名不是对整个固件加密,那太慢了。实际是对固件的「指纹」(哈希值)加密。这样既保证效率,又保证唯一性。

4.2.2 验签过程(接收方)

  1. 收到固件和签名后,先对固件算一遍哈希值。
  2. 用公钥解密签名,得到原始的哈希值。
  3. 对比两个哈希值。一致 → 固件完整且来源可信;不一致 → 固件被篡改或签名无效。

我的习惯:验签失败时,不要只弹个警告就继续运行。直接拒绝加载,或者进入安全恢复模式。我曾经见过一个设备,验签失败后只是记了条日志,结果被攻击者利用这个漏洞刷入了恶意固件。

为什么会这样?因为签名验证是固件安全的最后一道防线。一旦跳过或忽略,前面做的所有防护都白费了。

4.3 RSA 与 ECDSA 算法简介

目前主流签名算法就两种:RSA 和 ECDSA。我分别说说它们的脾气。

特性 RSA ECDSA
安全性基础 大整数分解 椭圆曲线离散对数
密钥长度 2048 / 4096 位 256 / 384 位
签名速度 较慢 较快
验签速度 较快 较慢
签名体积 较大(256 字节 @2048位) 较小(64 字节 @256位)
典型场景 PC、服务器、网关 IoT 设备、嵌入式系统

4.3.1 RSA

RSA 是「老大哥」,1997 年就标准化了。算法成熟,硬件支持广泛。很多安全芯片都内置了 RSA 加速引擎。

但它的缺点也很明显:密钥太长。2048 位的 RSA 密钥,签名有 256 字节。对于资源受限的 IoT 设备,传输和存储都是负担。

我建议:如果你的设备有专用安全芯片,或者对性能要求不高,RSA 是稳妥的选择。毕竟它经过了二十多年的攻击考验。

4.3.2 ECDSA

ECDSA 是「后起之秀」。同样的安全强度,密钥长度只有 RSA 的十分之一。256 位的 ECDSA 密钥,安全等级相当于 3072 位的 RSA。

这对嵌入式设备太友好了。签名体积小,传输快,存储省。我最近做的几个 IoT 项目,全部换成了 ECDSA。

注意:ECDSA 依赖随机数质量。如果随机数生成器有缺陷,私钥可能被恢复。我曾经调试过一个设备,因为硬件随机数发生器坏了,ECDSA 签名总是失败。后来加了软件熵池才解决。

选哪个?我个人倾向:新项目优先 ECDSA,尤其是资源受限的嵌入式环境。如果项目有历史包袱,或者需要兼容已有 PKI 体系,RSA 也没问题。

4.4 数字签名流程总览

下面这张图,把签名和验签的完整流程串起来了。我建议你多看几遍,直到能在脑子里「跑通」整个流程。

数字签名流程总览 数字签名流程总览 签名方(私钥签名) 固件数据 SHA-256 哈希 私钥签名 私钥 固件 + 签名 传输 验签方(公钥验签) 接收固件 + 签名 计算固件哈希 公钥解密签名 公钥 比较两个哈希值 一致 → 可信 不一致 → 篡改 私钥签名,公钥验签。私钥永远不离开签名方,公钥可以公开分发。 验签失败时,拒绝加载固件,进入安全恢复模式。

这张图把签名和验签的完整路径画清楚了。左边是签名方,右边是验签方。中间那条虚线代表传输过程。你仔细看,两个哈希值在最后一步比较,这就是整个安全机制的「命门」。

避坑指南:我曾经在项目里犯过一个低级错误——验签时忘了比较哈希值,只检查了签名能不能用公钥解开。结果攻击者随便改个数据,签名照样能解开(虽然解出来是乱码),但我的代码没做哈希比对,直接通过了。嗯,从那以后我写验签代码,第一件事就是确认哈希比较逻辑有没有写对。