密码学基础(下):非对称加密与数字签名
好,咱们接着聊密码学。上一章我们把对称加密、哈希函数这些基础概念过了一遍。这一章,我重点讲非对称加密——也就是 RSA 和 ECC 这套体系。说实话,在 MCU 安全启动这个领域,非对称加密才是真正的核心。为什么?因为你要在 Bootloader 里验证固件的合法性,手里拿的是公钥,私钥永远锁在开发者的保险柜里。这个模型,只有非对称加密能实现。
非对称加密的核心思想
非对称加密,说白了就是「两把钥匙」。一把公开,叫公钥;一把私密,叫私钥。公钥加密的数据,只有私钥能解开;反过来,私钥签名的数据,公钥能验证。这个特性,决定了它在安全启动中的位置。
我刚开始做嵌入式安全时,有个误区——总觉得非对称加密比对称加密「高级」。其实不是。RSA 和 ECC 的运算量比 AES 大得多,在 MCU 上跑一次 RSA-2048 签名验证,可能要几百毫秒甚至几秒。所以实际工程里,我们通常用「混合方案」:用非对称加密传递会话密钥,用对称加密加密实际数据。嗯,这个后面会细讲。
| 特性 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1 个(共享密钥) | 2 个(公钥 + 私钥) |
| 密钥分发 | 困难(需要安全通道) | 公钥可公开分发 |
| 运算速度 | 快(硬件加速常见) | 慢(大数运算) |
| 典型算法 | AES, ChaCha20 | RSA, ECDSA, Ed25519 |
| MCU 适用场景 | 固件加密传输 | 签名验证、密钥协商 |
RSA 与 ECC:选哪个?
RSA 和 ECC 是当前最主流的两种非对称算法。我在项目里两个都用过,说说我的感受。
RSA 基于大整数分解难题。密钥越长越安全,但运算量也越大。MCU 上常用 RSA-2048,签名验证大概需要 200~500ms(取决于芯片有没有硬件加速器)。RSA 的优点是成熟、工具链完善,几乎所有安全芯片都支持。缺点是密钥和签名都比较大——2048 位的密钥,光存储就要 256 字节。
ECC(椭圆曲线密码学)基于椭圆曲线离散对数难题。在同等安全强度下,ECC 的密钥长度远小于 RSA。比如 ECC-256 的安全等级约等于 RSA-3072。这意味着什么?签名更短、运算更快、存储更省。我最近几个项目都转向了 ECC,尤其是 Ed25519 曲线,在 Cortex-M4 上跑一次验证只要 10~30ms。
我的建议:
- 如果芯片有 RSA 硬件加速器,且兼容性要求高(比如要对接 PC 端工具),选 RSA-2048。
- 如果追求性能、存储空间有限,或者芯片较新,优先考虑 ECC(特别是 Ed25519 或 NIST P-256)。
- 千万别在 MCU 上用 RSA-4096——验证一次可能要好几秒,用户等不起。
公钥与私钥的管理
密钥管理,是安全启动里最容易出问题的地方。我见过不止一个项目,固件签名做得很好,但私钥被开发人员随手放在 Git 仓库里……嗯,那签名就形同虚设了。
私钥管理原则:
- 私钥必须离线存储,不能出现在任何编译脚本、CI/CD 流水线或代码仓库中。
- 建议使用 HSM(硬件安全模块)或加密 U 盘存储私钥。小团队至少也要用密码保护的加密文件。
- 每个产品线或客户使用独立的私钥。一旦某个私钥泄露,不至于全盘皆输。
公钥管理原则:
- 公钥需要固化在 Bootloader 中。通常放在芯片的一次性可编程(OTP)区域或安全存储区。
- 公钥的完整性必须保护——如果攻击者替换了 Bootloader 里的公钥,就能用自己的私钥签名恶意固件。
- 我习惯在公钥存储前计算一次哈希,并在启动时校验这个哈希。这叫「公钥锚定」。
避坑指南:
我曾经在一个客户现场排查问题,发现 Bootloader 验证固件签名总是失败。查了两天,最后发现——公钥在烧录时被字节序搞反了。RSA 公钥的模数是大端格式,但芯片默认是小端读取。这种低级错误,一旦踩到,排查起来非常痛苦。所以,建议在密钥烧录后,先做一次自检:用私钥签名一段已知数据,再用公钥验证,确保流程通得过。
数字签名生成与验证流程
数字签名,是安全启动的核心机制。它的流程其实不复杂,我画了一张图,你看完就明白了。
流程其实就三步:
- 计算哈希:对固件镜像做一次 SHA-256 哈希,得到一个固定长度的摘要。
- 签名:用私钥对这个哈希加密,生成签名。签名和固件一起发布。
- 验证:Bootloader 收到固件后,自己算一次哈希,再用公钥解密签名得到另一个哈希。两个哈希一致,说明固件没被篡改,且确实来自持有私钥的开发者。
工程小技巧:
实际项目中,签名验证不一定要验证整个固件。如果固件很大(比如几 MB),每次启动都算一次哈希会拖慢启动速度。我常用的做法是:只对固件的「头部元数据」签名,头部里包含固件哈希。这样 Bootloader 只需要验证头部签名,再校验固件哈希即可。既保证安全,又提升性能。
MCU 上的实现要点
在 MCU 上实现签名验证,有几个坑需要特别注意。
1. 大数运算库的选择
RSA 和 ECC 都依赖大数运算。MCU 上常用的库有 mbedTLS、OpenSSL(裁剪版)、MicroECC 等。我个人偏爱 mbedTLS,因为它模块化做得好,可以只编译需要的算法,节省 Flash 空间。一个只包含 SHA-256 + ECDSA 验证的 mbedTLS,在 Cortex-M4 上大概占 20~30KB Flash。
2. 内存管理
RSA-2048 的签名是 256 字节,公钥也是 256 字节。在只有 64KB RAM 的 MCU 上,这不算大。但 ECC 的签名更短(64 字节),对内存更友好。不过要注意,大数运算需要临时缓冲区,有些库会动态分配内存。在裸机环境下,我建议用静态分配,避免堆碎片。
3. 侧信道攻击防护
这个可能有点超前,但我觉得有必要提一下。如果攻击者能测量 MCU 的功耗或电磁辐射,可能通过分析运算时间推断出私钥信息。正规的安全芯片会内置防护措施。如果你用的是普通 MCU,至少要做到:签名验证的时间不依赖于输入数据(常数时间实现)。mbedTLS 的 RSA 和 ECDSA 实现默认是常数时间的,但要注意编译优化选项不能破坏这一点。
核心结论:
非对称加密是安全启动的基石。你不需要在 MCU 上做签名生成(那是开发环境的事),只需要做签名验证。验证流程固定:哈希 → 公钥解密 → 比较。选算法时,优先考虑 ECC(性能好、省空间);选库时,mbedTLS 是嵌入式领域的工业标准。密钥管理是安全链上最薄弱的一环——私钥泄露,一切归零。