3、签名算法基础:哈希算法(SHA256)原理、非对称加密(RSA/ECC)基础、数字签名生成与验证流程
做MCU Boot安全,绕不开签名算法。说白了,签名就是给固件贴个「防伪标签」。你想想看,如果Bootloader不验签名,那随便谁写段代码都能跑在板子上——这在产品量产阶段就是灾难。
我个人习惯把签名拆成三块来理解:哈希、非对称加密、签名流程。咱们一个一个说。
3.1 哈希算法:SHA256 到底在算什么?
哈希算法,也叫散列函数。它的作用是把任意长度的数据,压缩成固定长度的「指纹」。SHA256 的输出是256位,也就是32字节。
我在项目中遇到过一个问题:有同事问「SHA256 是不是加密?」不是。加密可以解密,哈希不行。它是单向的,你从哈希值推不出原始数据。这是它的核心特性。
SHA256 有几个关键性质:
- 确定性:同样的输入,永远得到同样的输出。
- 抗碰撞:几乎找不到两个不同的输入,得到相同的哈希值。
- 雪崩效应:输入改一个比特,输出变化一半左右的比特。
在MCU上跑SHA256,我建议用硬件加速模块。很多Cortex-M系列芯片内置了哈希加速器,算一次256位哈希只需要几千个时钟周期。如果用软件纯算,那可就慢了——尤其在大固件上,几兆字节算下来,Bootloader启动时间会明显变长。
3.2 非对称加密:RSA 与 ECC 的核心差异
非对称加密,说白了就是两把钥匙:公钥加密,私钥解密;或者私钥签名,公钥验签。在Boot签名场景里,我们只用签名和验签,不用加密。
RSA 和 ECC 是目前最主流的两种算法。它们的数学原理不同,但目标一致:保证私钥持有者才能生成有效签名。
| 对比项 | RSA | ECC |
|---|---|---|
| 数学基础 | 大整数分解 | 椭圆曲线离散对数 |
| 密钥长度(安全等价) | 2048位 | 256位 |
| 签名长度 | 256字节 | 64字节 |
| 计算速度(签名) | 较慢 | 较快 |
| 计算速度(验签) | 较快 | 较慢 |
| MCU资源占用 | ROM/RAM需求大 | 相对较小 |
我个人更倾向在MCU Bootloader里用ECC。为什么?因为签名验证是在Bootloader里做的,而Bootloader的代码空间通常被限制在几十KB。ECC的密钥和签名都短,代码量也小。RSA 2048位的签名有256字节,在Flash里存一堆公钥也挺占地方。
但ECC也有坑。它的验签比RSA慢。我记得在一个项目里,用NIST P-256曲线验一次签,在72MHz的Cortex-M3上跑了大约80ms。RSA 2048位验签只要不到10ms。所以,如果Bootloader对启动时间极其敏感,RSA反而是更好的选择。
3.3 数字签名生成与验证流程
签名流程其实不复杂。我画个图你就明白了。
流程其实就三步:
- 计算哈希:对固件做SHA256,得到32字节的摘要。
- 签名:用私钥对摘要做签名运算,生成签名数据。
- 验签:Bootloader用公钥验证签名是否匹配。
这里有个细节:为什么不对整个固件直接签名?因为非对称加密处理大块数据很慢。先哈希压缩,再签名,效率高得多。
3.4 签名验证的常见陷阱
做签名验证,有几个地方容易翻车。我列一下:
- 哈希计算范围不一致:签名时算了整个固件,验签时却漏了头部几个字节。结果永远验不过。
- 字节序问题:MCU是小端,PC是大端。签名数据在传输过程中字节序搞反了,验签失败。
- 公钥存储安全:公钥虽然公开,但如果被篡改,攻击者可以用自己的私钥签名恶意固件。所以公钥要放在只读区域,或者用芯片的OTP(一次性可编程)存储。
- 签名算法填充方式:RSA签名需要填充(如PKCS#1 v1.5或PSS)。填充方式不匹配,验签必败。
3.5 小结
签名算法这块,说白了就是三件事:哈希压缩、私钥签名、公钥验签。SHA256负责生成固定长度的指纹,RSA或ECC负责用密钥对做签名运算。Bootloader只做验签,不存私钥。
我个人建议,新项目优先考虑ECC P-256。密钥短、签名短、代码量小,适合MCU环境。如果启动时间要求苛刻,再考虑RSA。
嗯,这一章就到这里。记住:签名验证是Boot安全的第一道防线,也是最重要的一道。