4. 固件包的签名与验签:非对称加密基础与数字签名流程

这一章,我们来聊聊OTA升级里最核心的安全防线——签名与验签。

你想想看,固件包从云端飞到设备端,中间要经过多少网络节点?万一被人篡改了怎么办?设备怎么知道收到的固件是官方发布的,还是黑客塞进来的恶意程序?

答案就是数字签名。说白了,就是给固件包盖一个「防伪章」。这个章谁也伪造不了,设备收到后一验就知道真假。

4.1 非对称加密基础:RSA 与 ECC

数字签名的底层依赖非对称加密。它跟咱们平时用的对称加密(比如AES)不一样,对称加密是「一把钥匙开一把锁」,加密解密用同一个密钥。而非对称加密,用的是「一对钥匙」——公钥和私钥。

  • 私钥:自己死死藏好,谁也不能给。用来签名。
  • 公钥:公开出去,谁都可以拿。用来验签。

目前主流的非对称算法就两个:RSA 和 ECC。我个人的习惯是,如果设备算力够、存储空间大,用 RSA 更省心;如果资源紧张,ECC 是更好的选择。

对比项 RSA ECC(椭圆曲线)
安全性基础 大整数分解难题 椭圆曲线离散对数难题
密钥长度(同等安全强度) 2048位 / 4096位 256位 / 384位
签名速度 较慢 较快
验签速度 较快 较慢
资源占用 高(内存、Flash) 低
典型应用场景 PC、服务器、网关 IoT终端、MCU、智能卡
我的经验: 在资源受限的MCU上(比如Cortex-M0+,只有几十KB RAM),RSA 2048位的签名验签可能会跑不动。这时候 ECC 的 P-256 曲线几乎是唯一选择。我在一个智能门锁项目里就吃过这个亏,后来全切成了 ECC。

4.2 数字签名流程:到底是怎么签的?

数字签名不是直接把固件包扔给私钥加密就完事了。那样效率太低,而且固件包动辄几十MB,非对称加密根本算不过来。

真正的流程分两步走:先算摘要,再签摘要。

  1. 计算固件包的哈希值(摘要):用 SHA-256 这类哈希算法,把整个固件包算出一个固定长度的「指纹」。哪怕固件里改了一个 bit,这个指纹都会变得面目全非。
  2. 用私钥加密这个哈希值:加密后的结果,就是数字签名。
  3. 打包发布:把「固件包 + 数字签名 + 签名算法标识」一起发布出去。

设备端验签的时候,流程反过来:

  1. 用同样的哈希算法,计算收到的固件包的哈希值。
  2. 用公钥解密数字签名,得到原始的哈希值。
  3. 比较两个哈希值。如果一致,说明固件包没被篡改,确实是私钥持有者签发的。
核心要点: 签名保护的不是「内容不能被看到」,而是「内容不能被篡改」。固件包本身可以是明文传输的,但签名保证了它的完整性和来源可信。

下面这张图,把整个流程串起来了:

数字签名与验签流程 数字签名与验签流程 签名方(云端/开发者) 固件包(Firmware.bin) SHA-256 计算哈希值 私钥加密哈希值 → 数字签名 打包:固件 + 签名 + 算法标识 网络传输 验签方(设备端) 收到:固件 + 签名 + 算法标识 SHA-256 计算哈希值A 公钥解密签名 → 哈希值B 比较 哈希值A == 哈希值B ? ✅ 一致 → 验签通过 ❌ 不一致 → 验签失败 说明:私钥签名只有云端持有,公钥验签预置在设备中。设备永远不接触私钥。

4.3 验签失败的处理策略:不能直接拒绝就完事

验签失败,说明固件包有问题——要么被篡改了,要么来源不对。但设备该怎么处理?直接扔掉?还是报个错就完事?

这里面的门道不少。我见过不少产品,验签失败后只是打印一条日志,然后继续执行升级。这等于把安全防线直接拆了。

正确的处理策略,应该分几个等级:

策略等级 处理方式 适用场景
严格拒绝 立即终止升级流程,删除已下载的固件包,恢复系统到升级前状态 所有OTA升级场景(默认策略)
告警 + 重试 记录失败日志,尝试重新下载(最多3次),如果仍然失败则进入严格拒绝 网络不稳定可能导致传输损坏的场景
降级回滚 如果验签失败时系统已经部分升级,必须触发回滚机制,恢复到上一个可用版本 双分区(A/B)升级架构
安全锁定 连续多次验签失败(比如5次),锁定升级功能,需要管理员手动解锁 防止暴力攻击或恶意固件注入
避坑指南: 我曾经在一个项目中,设备验签失败后只是返回了一个错误码,上层应用没做任何处理。结果攻击者伪造了一个固件包,设备验签失败但继续运行了旧固件,看起来没问题。但攻击者利用这个漏洞,反复发送恶意包,最终导致设备进入了不可恢复的异常状态。记住:验签失败必须是一个「硬错误」,不能软处理。

4.4 公钥的存储:最容易被忽视的环节

签名算法再强,如果公钥被篡改了,一切白搭。攻击者只要把自己的公钥写进设备,然后用自己私钥签名的固件包就能通过验签。

所以,公钥的存储是整条安全链的「根信任」。我个人的建议是:

  • 硬件隔离:把公钥烧录到芯片的一次性可编程(OTP)区域或安全元件(SE)中,软件无法修改。
  • 代码固化:如果硬件不支持,至少把公钥编译到Bootloader的只读代码段,并加上写保护。
  • 证书链:不要只存一个公钥,而是存一个根证书。固件包携带由根证书签发的次级证书,设备用根证书验次级证书,再用次级证书验固件。这样根证书可以永远不变,次级证书可以灵活更新。
我的习惯: 在量产时,我会把公钥的哈希值也存一份在设备里。每次验签前,先校验公钥本身是否被篡改。虽然多了一步操作,但能有效防止公钥被替换的攻击。

4.5 小结

数字签名是OTA升级安全的基石。RSA和ECC各有优劣,选型时要根据设备资源来定。签名流程的核心是「哈希 + 非对称加密」,验签失败必须严格处理,公钥存储必须安全可靠。