3、OTA升级包制作:差分升级包与全量升级包的概念、制作工具与流程、签名与加密

好,咱们进入第三章。这一章聊的是升级包的制作,说白了就是“你要把什么东西发给设备”。

很多刚入行的朋友觉得升级包制作很简单——把新固件打个包,发过去不就完了?嗯,没那么简单。你想想看,一个设备可能只有2MB的Flash空间,新固件却有3MB,你怎么发?或者设备在偏远山区,用2G网络传输,一个10MB的包要传半小时,用户早把电拔了。

所以,升级包制作是OTA里非常关键的一环。我个人习惯把升级包分为两类:全量升级包差分升级包。咱们一个一个说。

3.1 全量升级包:最笨但最稳的方法

全量升级包,顾名思义,就是把完整的固件镜像打包发给设备。设备收到后,直接擦除旧固件,写入新固件。

优点很明显:

  • 实现简单,不需要知道设备当前跑的是什么版本
  • 可靠性高,只要传输不出错,升级基本不会失败
  • 适合首次烧录或版本跨度很大的升级

缺点也很致命:

  • 包体大,占用带宽多
  • 升级时间长,用户体验差
  • 对设备存储空间要求高(需要同时存放新旧两个固件)

适用场景:

  • 设备首次出厂或恢复出厂后的升级
  • 版本跨度太大(比如从v1.0直接升到v5.0)
  • 设备存储空间充裕,不在乎那点流量

我在一个智能门锁项目里就吃过全量包的亏。当时固件有8MB,设备Flash只有4MB,我天真地以为能直接覆盖升级。结果呢?升级到一半,旧固件被擦除了,新固件还没写完,设备直接变砖。嗯,从那以后我学乖了——全量升级一定要有双备份区,或者确保空间足够。

3.2 差分升级包:省流量、省时间

差分升级包,也叫增量包。它只包含新旧固件之间的差异部分。设备收到后,把差异“打”到旧固件上,生成新固件。

你想想看,如果固件只是改了一行代码,全量包要发几MB,差分包可能只需要几KB。对于物联网设备来说,这省下来的可都是真金白银——流量费、电量、时间。

差分升级的核心原理:

  • 用算法对比新旧两个二进制文件
  • 找出所有不同的字节块
  • 只打包这些差异块,并记录它们在文件中的位置
  • 设备端用“补丁”算法,把差异应用到旧固件上

我个人建议:差分升级虽然好,但别滥用。如果版本跨度超过3个主版本,差分包的体积可能比全量包还大。这时候老老实实用全量包吧。

3.3 制作工具与流程

好,理论说完了,咱们来点实际的。差分升级包怎么做?用什么工具?

目前业界主流的差分工具就几个:

工具 特点 适用场景
bsdiff/bspatch 算法成熟,压缩率高,但内存占用大 Linux/Android设备,固件较大
hdiffpatch 腾讯出品,支持多平台,速度较快 嵌入式设备,资源受限场景
xdelta 基于VCDIFF标准,简单轻量 小固件,快速原型开发
自研差分算法 针对特定硬件优化,但开发成本高 芯片原厂或大厂深度定制

制作流程(以bsdiff为例):

  1. 准备旧固件(old.bin)和新固件(new.bin)
  2. 运行命令:bsdiff old.bin new.bin patch.bin
  3. 得到差分文件patch.bin
  4. 对patch.bin进行压缩(可选,推荐gzip或lzma)
  5. 对压缩后的文件进行签名和加密(后面会讲)
  6. 打包成OTA升级包格式(通常是tar或自定义格式)

避坑指南:我曾经在一个项目里直接用bsdiff对比两个不同编译器编译出来的固件,结果差分包比全量包还大。为什么?因为编译器版本不同,导致二进制布局全变了。所以记住:差分升级要求新旧固件用完全相同的编译环境,否则差分算法会认为“全都不一样”。

3.4 签名与加密:别让你的包被篡改

升级包做好了,直接发出去?不行。你想想看,如果升级包在传输过程中被中间人篡改了,设备刷了一个恶意固件,后果是什么?轻则设备变砖,重则整个网络被攻破。

所以,签名和加密是OTA升级的安全底线

签名 vs 加密,有什么区别?

  • 签名:保证升级包的完整性和来源可信。设备收到包后,验证签名是否匹配。如果不匹配,说明包被篡改过,拒绝升级。
  • 加密:保证升级包的机密性。防止别人抓包分析你的固件内容,窃取你的知识产权。

在实际项目中,我通常的做法是:先签名,再加密。或者只签名不加密(如果固件本身不敏感)。但绝对不要只加密不签名——加密只能防窥探,防不了篡改。

签名流程:

  1. 生成一对公私钥(RSA 2048位或ECC 256位)
  2. 用私钥对升级包的哈希值进行签名
  3. 将签名附加到升级包中
  4. 设备端用公钥验证签名

加密流程:

  1. 生成一个随机的对称密钥(AES-128或256)
  2. 用这个对称密钥加密升级包
  3. 用设备的公钥加密这个对称密钥
  4. 将加密后的密钥和加密后的升级包一起发送
  5. 设备用私钥解密出对称密钥,再用对称密钥解密升级包

重要提醒:私钥一定要保管好!我曾经见过一个团队把私钥直接放在Git仓库里,结果被离职员工下载了。后来那批设备全部需要召回重新烧录公钥。血的教训啊。

3.5 完整的升级包制作流程

好,咱们把上面所有步骤串起来,看看一个完整的升级包是怎么诞生的:

# 1. 生成差分包
bsdiff old_firmware.bin new_firmware.bin delta.bin

# 2. 压缩差分包
gzip -9 delta.bin

# 3. 计算哈希
sha256sum delta.bin.gz > delta.bin.gz.sha256

# 4. 用私钥签名
openssl dgst -sha256 -sign private_key.pem -out delta.bin.gz.sig delta.bin.gz

# 5. 生成随机AES密钥
openssl rand -out aes_key.bin 32

# 6. 用AES密钥加密升级包
openssl enc -aes-256-cbc -in delta.bin.gz -out delta.bin.gz.enc -pass file:aes_key.bin

# 7. 用设备公钥加密AES密钥
openssl rsautl -encrypt -inkey device_public_key.pem -pubin -in aes_key.bin -out aes_key.enc

# 8. 打包成最终OTA包
tar -cvf ota_package.tar delta.bin.gz.enc aes_key.enc delta.bin.gz.sig manifest.json

你看,一个完整的升级包包含了:加密后的差分数据、加密后的密钥、签名文件、以及描述版本信息的manifest.json。

小技巧:manifest.json里除了版本号、硬件型号、包大小这些基本信息外,我建议再加一个“兼容性检查”字段。比如旧固件的最低版本号。这样设备在升级前可以先检查自己是否满足条件,避免升级失败。

好了,这一章的内容就到这儿。总结一下:全量包简单但费流量,差分包省流量但实现复杂。签名保证安全,加密保护隐私。下一章咱们聊聊升级包怎么安全地传到设备上——也就是传输协议的选择。