2. 固件签名原理:哈希、非对称加密与数字签名

这一章,我们来聊聊固件签名的核心原理。说白了,就是回答一个问题:你怎么证明你手里的固件是“真”的,而且没被人动过手脚?

我在做嵌入式安全的头几年,见过太多产品因为没做签名校验,被人在 Flash 里塞了后门。嗯,那滋味可不好受。所以,理解签名原理,是固件安全的第一道防线。

2.1 哈希算法:固件的“指纹”

先说说哈希。哈希算法,比如 SHA256,它干的事很简单:不管你的固件有多大——几十 KB 也好,几 MB 也好——它都能算出一个固定长度的“摘要”。这个摘要,就像人的指纹一样,是唯一的。

哈希算法的两个关键特性:

  • 不可逆:从摘要反推原始数据,理论上不可能。你只能正向算,不能反向解。
  • 抗碰撞:几乎不可能找到两个不同的固件,算出相同的 SHA256 值。我见过有人想用 MD5 做签名,结果被碰撞攻击搞得焦头烂额。所以,现在业界标准就是 SHA256。

举个例子,你写了一段固件,内容是 Hello, World!。用 SHA256 算出来是一串 64 位的十六进制数。哪怕你只改了一个字母,改成 Hello, world!,算出来的哈希值就完全不一样了。这就是哈希的“雪崩效应”。

我的习惯:在项目里,我通常会在固件编译完成后,自动计算一次 SHA256 值,并把它记录在构建日志里。这样,后续做版本追溯时,能快速确认固件是否被意外修改过。

2.2 非对称加密:公钥与私钥的“锁与钥匙”

哈希能保证完整性,但没法保证“谁”生成的。这时候就需要非对称加密了。它有两把钥匙:一把私钥(自己藏着),一把公钥(公开出去)。

常见的算法有两种:RSA 和 ECC。我个人的经验是,如果芯片资源紧张,优先选 ECC。为什么?因为 ECC 在同等安全强度下,密钥更短,计算更快。比如,256 位的 ECC 密钥,安全性和 3072 位的 RSA 差不多。

特性 RSA ECC
密钥长度(同等安全) 2048 / 3072 位 224 / 256 位
签名速度 较慢 较快
验签速度 较快 较慢(但可接受)
资源占用 高 低
典型应用 PC / 服务器端 嵌入式 / IoT 设备

避坑指南:我曾经在一个项目里,为了省成本,用了 1024 位的 RSA。结果产品上市不到一年,就被爆出密钥可被暴力破解。从那以后,我坚持:嵌入式设备至少用 2048 位 RSA 或 256 位 ECC。别在这上面省钱,不值得。

2.3 数字签名的生成与验证流程

好了,把哈希和非对称加密结合起来,就是数字签名。流程其实不复杂,我画了一张图,你一看就明白。

固件数字签名生成与验证流程 固件数字签名生成与验证流程 原始固件 (Firmware.bin) 输入 SHA256 哈希计算 生成 256 位摘要 私钥加密 (签名) RSA / ECC 私钥 签名后的固件 固件 + 数字签名 传输 / 烧录 接收到的固件 固件 + 签名 SHA256 哈希计算 生成摘要 H1 公钥解密 (验签) 得到摘要 H2 比较 H1 == H2 ? 相等则通过,否则拒绝 关键点: • 私钥签名,公钥验签。私钥永远不能泄露,公钥可以公开。 • 哈希保证完整性,非对称加密保证身份真实性。两者缺一不可。

流程其实就两步:

  1. 签名生成(在安全环境,比如你的编译服务器上):
    • 对固件算 SHA256,得到摘要 H。
    • 用私钥对 H 加密,得到签名 S。
    • 把固件和签名打包在一起,发布出去。
  2. 签名验证(在设备上,比如 MCU 启动时):
    • 设备收到固件后,先对固件本体算 SHA256,得到 H1。
    • 用公钥解密签名 S,得到 H2。
    • 比较 H1 和 H2。如果相等,固件就是可信的;否则,拒绝启动或升级。

为什么这样设计?你想想看,如果直接对固件本体做非对称加密,那计算量太大了。哈希算法很快,先把固件“浓缩”成一小段摘要,再对摘要签名,效率高得多。我在一个 STM32 项目上实测过,SHA256 算 1MB 固件大概只要几十毫秒,而 RSA 2048 签名一次要几百毫秒。所以,先哈希再签名,是工程上的最优解。

2.4 实际项目中的注意事项

理论说完了,聊点实战中容易踩的坑。

  • 密钥管理:私钥一定要放在离线环境,比如专用的 HSM(硬件安全模块)或加密的 U 盘里。我见过有人把私钥直接放在 Git 仓库里,结果被内部员工泄露。嗯,那场面,很尴尬。
  • 公钥存储:公钥要烧死在芯片的 OTP(一次性可编程)区域,或者放在安全存储区。如果公钥能被篡改,那签名就形同虚设。
  • 签名算法选择:如果芯片支持硬件加速,优先用硬件支持的算法。比如,有些芯片内置了 ECC 加速器,用起来比纯软件快 10 倍以上。

我曾经踩过的坑:有一次,我在做 OTA 升级时,忘了在 Bootloader 里做签名校验。结果测试时发现,只要有人抓包篡改固件,设备就能被刷入恶意代码。从那以后,我定了个规矩:所有 Bootloader 和固件升级流程,必须强制校验签名,否则不允许启动。