3、升级包制作与签名:差分升级包、全量升级包、签名与校验机制
升级包怎么做?签名又是什么?很多刚入行的朋友觉得这步就是打个包、签个名,没什么技术含量。其实不然。我在项目里见过因为签名算法选错、差分算法边界没处理好,导致整批设备变砖的案例。今天咱们就把这块彻底讲透。
3.1 全量升级包 vs 差分升级包
先搞清楚两个概念。全量包,就是把完整的固件镜像打包下发。差分包,只包含新旧版本之间的差异部分。
| 对比项 | 全量升级包 | 差分升级包 |
|---|---|---|
| 包体大小 | 大(完整固件) | 小(仅差异部分) |
| 生成复杂度 | 低(直接打包) | 高(需差分算法) |
| 适用场景 | 首次烧录、版本跨度大 | 小版本迭代、带宽受限 |
| 升级成功率 | 高(独立镜像) | 依赖基线版本一致性 |
| 存储要求 | 高 | 低 |
我个人习惯,在项目初期先用全量包跑通流程。等OTA链路稳定了,再切到差分升级。一来降低调试复杂度,二来万一出问题,排查范围小。
3.2 差分升级包制作
差分升级的核心算法,主流的有bsdiff、hdiffpatch、xdelta3。我用的最多的是bsdiff,它在二进制差异检测上表现不错。
基本流程是这样的:
- 获取旧版本固件(base.hex)和新版本固件(new.hex)
- 运行差分工具,生成patch文件
- 将patch文件打包成升级包
- 设备端接收patch后,与本地旧固件合并,还原新固件
# 使用 bsdiff 生成差分补丁
bsdiff old_firmware.bin new_firmware.bin upgrade.patch
# 设备端使用 bspatch 还原
bspatch old_firmware.bin new_firmware.bin upgrade.patch
3.3 全量升级包制作
全量包就简单多了。说白了就是把编译好的固件镜像,加上头部信息、版本号、校验值,打包成一个文件。
一个标准的全量升级包结构:
+----------------------------+
| Magic Header (4字节) | // 固定魔数,如 0xOTA1
| Version (4字节) | // 固件版本号
| Image Size (4字节) | // 固件大小
| CRC32/Checksum (4字节) | // 校验值
| Signature (256/512字节) | // 数字签名
| Firmware Data (变长) | // 固件本体
+----------------------------+
嗯,这里要注意:头部字段的字节序一定要和MCU的架构匹配。小端CPU和大端CPU混用,读出来的版本号、大小全是错的。我见过有人把ARM的包直接丢给RISC-V设备,结果解析失败。
3.4 签名与校验机制
签名是OTA安全的最后一道防线。没有签名的升级包,就像没锁的门——谁都能往里塞东西。
常用的签名算法:
- RSA:成熟、广泛支持,但签名体积大、验签慢
- ECDSA:签名短、性能好,适合资源受限设备
- Ed25519:现代算法,安全性和性能都优秀
我个人倾向在IoT设备上用ECDSA。签名长度只有64字节左右,验签速度也快。RSA 2048的签名要256字节,对flash紧张的设备不太友好。
签名流程:
- 对升级包内容做哈希(SHA256)
- 用私钥对哈希值签名
- 将签名附加到升级包尾部
- 设备端用公钥验签
# 生成密钥对
openssl ecparam -genkey -name prime256v1 -out private.pem
openssl ec -in private.pem -pubout -out public.pem
# 对升级包签名
openssl dgst -sha256 -sign private.pem -out upgrade.sig upgrade.bin
# 设备端验签(伪代码)
if (ecdsa_verify(public_key, sha256_hash, signature) == OK) {
apply_update();
} else {
reject_update();
}
3.5 升级包制作与签名流程总览
下面这张图,把整个流程串起来了。你想想看,从固件编译完成,到最终设备安全升级,中间经历了哪些环节。
3.6 校验机制与安全加固
签名只是校验的一部分。完整的校验链应该包含:
- 完整性校验:CRC32或SHA256,确保传输过程中没丢包、没篡改
- 签名校验:验证升级包来源是否可信
- 版本号校验:防止回滚到有漏洞的旧版本
- 硬件绑定校验:升级包只能用于指定型号的设备
核心原则: 校验必须在Bootloader阶段执行,不能在应用层做。为什么?因为应用层可能已经被攻击者替换了。Bootloader是信任根,它验签通过,才允许升级。
我记得有一次做安全审计,发现某款设备的签名校验放在应用层。攻击者只要刷一个假的应用程序,就能绕过签名检查,直接写任意固件。这就是典型的信任根没守住。
最后说一句:升级包制作不是一锤子买卖。版本迭代过程中,密钥轮换、算法升级都要提前规划。别等到产品出货了,才发现签名算法太弱、密钥没法更新——那时候就晚了。