2. 密码学基础回顾:非对称加密、哈希函数与数字签名
各位好,我是老周。这一章咱们聊聊密码学基础。你可能会问:“做安全启动,为什么还要回头啃密码学?”
我直接告诉你答案:安全启动的每一行代码、每一个签名,底层都是靠这些数学原理撑着的。不懂这些,你配的密钥可能就是纸糊的。
咱们不搞数学推导,只讲工程里怎么用、有什么坑。开始吧。
2.1 非对称加密:RSA 与 ECC
非对称加密,说白了就是两把钥匙:公钥随便发,私钥自己藏。公钥加密的数据,只有私钥能解开;反过来,私钥签名的数据,公钥能验真伪。
在安全启动里,我们主要用它的签名能力,而不是加密。为什么?因为固件镜像通常是公开的,我们关心的是“谁签的”,而不是“能不能看”。
2.1.1 RSA:老牌劲旅
RSA 基于大整数分解难题。密钥越长越安全,但计算也越慢。
| 密钥长度 | 安全等级 | 签名速度 | 典型场景 |
|---|---|---|---|
| 1024 位 | 已不推荐 | 快 | 旧设备兼容 |
| 2048 位 | 当前标准 | 中等 | 大多数安全启动 |
| 4096 位 | 高安全 | 慢 | 根密钥、CA 密钥 |
我的经验: 2048 位 RSA 是目前性价比最高的选择。我在一个 IoT 项目里用过 4096 位,结果 BootROM 验签花了将近 2 秒,产品经理差点没把我吃了。后来换回 2048 位,0.3 秒搞定,安全等级也够。
2.1.2 ECC:后起之秀
ECC 基于椭圆曲线离散对数难题。同样的安全等级,ECC 的密钥比 RSA 短得多。
- P-256(secp256r1):等效于 3072 位 RSA,是目前安全启动的主流选择。
- P-384:等效于 7680 位 RSA,用于对安全性要求极高的场景。
- Curve25519:性能极佳,但部分 BootROM 不支持。
注意: 不是所有芯片的 BootROM 都支持 ECC。我曾经在一个项目里选了 ECC P-256,结果发现芯片的 ROM 代码只支持 RSA。最后只能硬着头皮在启动流程里加了一段软件验签代码,启动时间多了 100 毫秒。选型前,一定先查芯片手册!
2.2 哈希函数:SHA-256
哈希函数,就是把任意长度的数据,压缩成一个固定长度的“指纹”。这个指纹是唯一的,哪怕原数据只改了一个比特,指纹也会完全变样。
在安全启动里,哈希函数干两件事:
- 完整性校验:验证固件有没有被篡改。
- 签名加速:先对固件做哈希,再对哈希值签名。因为哈希值很短(比如 32 字节),签名速度会快很多。
2.2.1 SHA-256 的特点
- 输出长度:256 位(32 字节)。
- 抗碰撞性:找到两个不同输入,但哈希值相同,在计算上不可行。
- 雪崩效应:输入微小变化,输出变化巨大。
核心原则: 永远不要用 MD5 或 SHA-1 做安全启动。我在 2017 年审计过一个项目,他们还在用 SHA-1 做固件校验。结果我用一个公开的碰撞工具,30 分钟就构造出了两个不同固件但哈希值相同的镜像。那个项目后来全部返工,损失惨重。
2.3 数字签名原理
数字签名,就是把哈希函数和非对称加密结合起来。流程如下:
- 签名方(开发者):
- 对固件做 SHA-256 哈希,得到摘要 H。
- 用私钥对 H 加密(签名),得到签名值 S。
- 将固件 + S 一起发布。
- 验证方(设备):
- 对收到的固件做 SHA-256 哈希,得到摘要 H'。
- 用公钥对 S 解密,得到摘要 H''。
- 比较 H' 和 H''。如果相等,签名有效;否则,固件被篡改或签名无效。
你想想看,这个流程保证了什么?
- 完整性:固件没被改过。
- 真实性:固件确实来自持有私钥的开发者。
- 不可否认性:开发者不能抵赖自己签过这个固件。
避坑指南: 我曾经见过一个团队,他们直接把整个固件用私钥加密,然后设备用公钥解密。这其实是加密,不是签名。加密后的固件体积会变大,而且验签速度极慢。正确的做法是先哈希,再签名。记住:签名是对哈希值操作,不是对原始数据操作。
2.4 知识体系总览
下面这张图,把这一章的核心逻辑串起来了。你仔细看,安全启动的签名流程,其实就是这张图的工程化实现。
2.5 工程中的常见误区
最后,我列几个我在实际项目中踩过的坑,你遇到了可以少走弯路。
| 误区 | 错误做法 | 正确做法 |
|---|---|---|
| 哈希算法过时 | 用 MD5 或 SHA-1 做固件校验 | 至少用 SHA-256 |
| 签名对象错误 | 对整个固件做 RSA 加密 | 先哈希,再对哈希值签名 |
| 密钥长度不足 | 用 1024 位 RSA | 至少 2048 位 RSA 或 P-256 ECC |
| 公钥未校验 | 直接从外部加载公钥 | 公钥必须烧录在芯片 OTP 或 ROM 中 |
血的教训: 我曾经在一个项目里,公钥是从外部 Flash 加载的。结果攻击者替换了公钥,用自己的私钥签了一个恶意固件。设备照常启动,整个产品线被攻破。从那以后,我坚持公钥必须硬件固化,谁也别想改。