3、数字签名基础:非对称加密(RSA/ECC)、哈希函数(SHA-256)、签名与验签流程
各位好,我是老周。今天咱们聊点硬核的——数字签名。你想想看,安全启动链里,每一级固件凭什么相信上一级是“自己人”?靠的就是数字签名。说白了,签名就是给代码盖个章,验签就是检查这个章是不是真的。
我刚开始做嵌入式安全时,总觉得签名验签是软件工程师的事,硬件只管跑就行。直到有一次,我在一个IoT项目里发现Bootloader被篡改,整批设备差点报废……嗯,从那以后,我再也不敢轻视签名验签的每一个细节了。
3.1 非对称加密:公钥与私钥的“夫妻档”
非对称加密,核心就是一对密钥:公钥和私钥。私钥自己藏好,公钥公开出去。用私钥签名的东西,只有对应的公钥能验证;用公钥加密的东西,只有对应的私钥能解密。
我个人习惯把这对密钥比作“印章”和“印泥样本”。私钥是印章,只有你自己有;公钥是印泥样本,谁都可以拿。你盖个章(签名),别人拿你的印泥样本一对(验签),就知道是不是你盖的。
核心原则:私钥签名,公钥验签。私钥永远不能泄露,公钥可以随便发。
3.1.1 RSA:老牌劲旅
RSA 是目前最常用的非对称加密算法之一。它的安全性基于大整数分解的难度——给你两个大质数相乘的结果,想反推出是哪两个质数,非常困难。
RSA 的密钥长度通常有 2048 位、4096 位。我在项目中遇到过,有些老旧的芯片只支持 1024 位 RSA,但现在已经不推荐了,容易被破解。我个人建议,新项目至少用 2048 位。
| 特性 | RSA-2048 | RSA-4096 |
|---|---|---|
| 密钥长度 | 2048 位 | 4096 位 |
| 安全强度 | 112 位对称等效 | 128 位对称等效 |
| 签名速度 | 较快 | 较慢 |
| 验签速度 | 快 | 较快 |
| 推荐场景 | 大多数嵌入式设备 | 高安全要求场景 |
3.1.2 ECC:后起之秀
ECC(椭圆曲线密码学)是近年来越来越流行的选择。它的优势在于:更短的密钥长度,提供同等级别的安全强度。比如,256 位的 ECC 密钥,安全强度相当于 3072 位的 RSA。
你想想看,在嵌入式设备里,存储空间和计算资源都很宝贵。ECC 的密钥更短,签名也更短,这对我们做安全启动来说,简直是福音。我曾经在一个资源受限的 MCU 上,用 ECC-256 替代 RSA-2048,签名存储空间直接省了 70%。
我的建议:如果芯片支持硬件加速,优先用 ECC。如果不支持,RSA 的软件实现更成熟,也不差。
3.2 哈希函数:数据的“指纹”
哈希函数,就是把任意长度的数据,压缩成一个固定长度的“摘要”。这个摘要就像数据的指纹——内容变了,指纹一定变;内容相同,指纹一定相同。
在安全启动里,我们不会对整个固件做签名(太慢了),而是先对固件算一个哈希值,再对这个哈希值签名。验签时,先算固件的哈希,再验签这个哈希。
3.2.1 SHA-256:当前的主流选择
SHA-256 是 SHA-2 家族的一员,输出 256 位的哈希值。它的碰撞概率极低,目前没有已知的有效攻击方法。
我记得有一次,团队里有人问:“MD5 行不行?”我直接否了。MD5 已经被证明有碰撞攻击,安全启动里用 MD5,等于给攻击者留后门。SHA-1 也不行,虽然比 MD5 强,但也被攻破了。现在业界公认的最低标准就是 SHA-256。
避坑指南:我曾经见过一个产品,为了省性能,用了 SHA-1 做固件校验。结果被安全团队一测,几分钟就伪造了一个合法签名的固件。从那以后,我定了个规矩:哈希函数至少 SHA-256,谁用 MD5 或 SHA-1,谁自己负责。
3.3 签名与验签流程:从理论到实践
好了,理论讲完了,咱们看看实际怎么操作。我画了一张流程图,帮你理清签名和验签的完整链路。
3.3.1 签名流程(生产端)
- 计算哈希:对原始固件做 SHA-256 哈希,得到 32 字节的摘要。
- 私钥签名:用私钥对这个摘要进行签名,生成签名数据(RSA-2048 下是 256 字节,ECC-256 下是 64 字节)。
- 打包分发:将原始固件和签名数据打包在一起,分发给设备。
3.3.2 验签流程(设备端)
- 接收数据:设备收到固件 + 签名。
- 计算哈希:对收到的固件部分做 SHA-256 哈希,得到摘要。
- 公钥验签:用预置的公钥,对签名和摘要进行验签。
- 判断结果:验签通过,固件可信;验签失败,固件被篡改,拒绝启动。
关键点:验签时,公钥必须提前安全地存储在设备中。如果公钥被篡改,整个信任链就崩塌了。这就是为什么安全启动的第一级公钥通常烧死在 ROM 或 OTP 里,不可更改。
3.4 实际项目中的避坑指南
做安全启动这么多年,我踩过不少坑。分享几个典型的,你们以后遇到了能少走弯路。
- 哈希和签名顺序搞反:我曾经见过有人先签名再哈希,结果验签时怎么都对不上。记住:先哈希,再签名。
- 公钥存储位置不对:公钥放在可擦写的 Flash 里,攻击者一改,你的签名就废了。公钥必须放在一次性写入的区域,比如 OTP 或 ROM。
- 签名算法不匹配:RSA 的签名和验签算法必须一致。有的芯片只支持 PKCS#1 v1.5,有的支持 PSS,搞混了验签必失败。
- 哈希长度截断:有些老库默认只取哈希的前 16 字节,安全强度直接减半。务必确认哈希输出是完整的 32 字节。
我曾经踩过的坑:在一个量产项目中,我发现签名验签偶尔失败。查了三天,最后发现是固件末尾有多余的填充字节,导致哈希值不一致。从那以后,我定了个规矩:签名前必须对固件做严格的长度校验和去填充处理。
3.5 小结
数字签名是安全启动的基石。非对称加密(RSA/ECC)提供签名能力,哈希函数(SHA-256)提供数据完整性校验,两者结合,才能实现“谁签的、有没有被改”的双重验证。
记住:私钥是命根子,公钥要锁死,哈希不能省,验签不能跳。这些基础打牢了,后面的信任链传递才能站得住脚。