1. 签名基础概念:什么是固件签名、为什么需要签名、签名与校验的基本流程

各位同学,咱们今天聊固件签名。说实话,我刚入行那会儿,对签名这事儿也没太当回事。觉得不就是给固件加个“锁”嘛,能有多重要?直到有一次,我在一个IoT项目里亲眼看到,因为没做签名校验,设备被刷入了恶意固件,整批产品差点召回。嗯,从那以后,我再也不敢小看签名了。

1.1 什么是固件签名

固件签名,说白了就是给固件文件打上一个“数字指纹”。这个指纹是唯一的,而且只有固件的发布者才能生成。你想想看,就像你签合同要手写签名一样,固件签名就是告诉设备:“这个固件是我官方发布的,没被人动过手脚。”

签名过程通常用到两个东西:私钥和公钥。私钥只有发布者自己知道,用来生成签名;公钥是公开的,设备用它来验证签名是否有效。

核心概念速览:

  • 固件签名:用私钥对固件哈希值加密,生成签名数据
  • 签名校验:设备用公钥解密签名,对比哈希值是否一致
  • 哈希算法:把固件内容映射成固定长度的摘要(如SHA-256)
  • 非对称加密:私钥签名,公钥验签,两者不互通

1.2 为什么需要签名

我遇到过不少刚入行的工程师问:“固件烧进去能跑就行,干嘛非要签名?”这个问题问得好。咱们从三个角度来拆解:

  1. 防篡改:固件在传输、存储过程中,可能被恶意修改。签名能保证固件内容没被改过。
  2. 防假冒:第三方可能伪造固件,冒充官方版本。签名能验证发布者身份。
  3. 防回滚:攻击者可能把设备降级到有漏洞的旧版本。签名机制可以配合版本号,拒绝旧固件。

我记得有个项目,客户要求设备必须支持安全启动。当时我们用的MCU支持签名校验,但固件升级流程里没做。结果测试时发现,只要把固件包里的版本号改小,设备就乖乖降级了。后来加上签名校验,这个问题才彻底解决。

避坑指南:我曾经在一个量产项目里,因为签名密钥管理不当,导致私钥泄露。结果第三方用这个私钥签了个恶意固件,所有设备都能刷进去。那次教训让我明白:密钥管理比签名算法本身更重要。私钥必须放在硬件安全模块(HSM)或安全存储区,绝不能明文写在代码里。

1.3 签名与校验的基本流程

咱们来看一个典型的固件签名和校验流程。我习惯把它分成两个阶段:签名阶段(在开发/发布环境做)和校验阶段(在设备端做)。

签名阶段(发布者侧)

  1. 计算固件文件的哈希值(比如SHA-256)
  2. 用私钥对哈希值进行加密,生成签名数据
  3. 把签名数据附加到固件文件里,或者单独存放
  4. 发布带签名的固件包

校验阶段(设备侧)

  1. 设备收到固件包,提取签名数据和原始固件
  2. 用公钥解密签名数据,得到原始的哈希值
  3. 重新计算固件的哈希值
  4. 对比两个哈希值:一致则校验通过,不一致则拒绝

小技巧:实际项目中,我建议把签名数据放在固件包的末尾,并加上固定长度的头部信息。这样设备端解析时,可以先读尾部固定长度的签名数据,再往前读固件内容。效率比从头扫描高得多。

下面这张图,我把整个流程画出来了。你一看就明白:

固件签名与校验流程图 固件签名与校验流程 签名阶段(发布者侧) 原始固件文件 计算SHA-256哈希值 私钥加密 → 签名数据 固件 + 签名 → 发布包 校验阶段(设备侧) 接收固件包 提取签名数据 + 固件 公钥解密 → 原始哈希 重新计算固件哈希 对比两个哈希值 校验失败 → 拒绝 校验通过 → 允许升级 说明:签名阶段使用私钥,校验阶段使用公钥。私钥必须严格保密,公钥可以公开。 哈希算法推荐使用SHA-256或更高强度,避免使用MD5、SHA-1等已不安全的算法。

1.4 常见的签名算法与哈希算法

实际项目中,选什么算法很关键。我整理了一张表,方便你对比:

算法类型 常见算法 密钥长度 安全性 适用场景
哈希算法 SHA-256 256位 高 通用推荐
哈希算法 SHA-384 / SHA-512 384/512位 更高 高安全需求
签名算法 RSA-2048 2048位 高 通用推荐
签名算法 RSA-4096 4096位 更高 高安全需求
签名算法 ECDSA P-256 256位 高 资源受限设备
签名算法 Ed25519 256位 高 高性能场景

我的建议:对于大多数嵌入式项目,我推荐使用 SHA-256 + RSA-2048 的组合。如果MCU资源紧张(比如只有几十KB的Flash),可以考虑 SHA-256 + ECDSA P-256,签名长度更短,计算量也更小。我曾经在一个Cortex-M0+的项目里用ECDSA,签名校验时间从RSA的2秒降到了0.3秒,效果很明显。

1.5 签名在固件升级中的位置

签名不是孤立存在的,它通常嵌入在固件升级流程里。我习惯把升级流程分成这几步:

  1. 固件打包:编译生成固件 → 计算哈希 → 签名 → 打包成升级文件
  2. 固件传输:通过OTA、UART、USB等方式发送到设备
  3. 固件接收:设备接收并存储到临时区域
  4. 签名校验:设备验证签名有效性
  5. 固件烧录:校验通过后,写入正式存储区
  6. 启动验证:设备重启时,再次校验固件签名(安全启动)

你看,签名校验在升级流程里出现了两次:一次在烧录前,一次在启动时。为什么要做两次?我遇到过一种攻击方式:攻击者在固件烧录完成后、设备重启前,篡改存储区的内容。如果只在烧录前校验,启动时不做二次校验,那就防不住这种攻击。

注意:签名校验必须放在设备端的可信执行环境里。如果校验代码本身可以被篡改,那签名就形同虚设。我见过一个项目,校验逻辑放在普通Flash里,攻击者直接跳过了校验函数。后来我们把校验代码放到ROM里,才彻底解决这个问题。

1.6 小结

这一章咱们聊了固件签名的基本概念。说白了,签名就是给固件加一道“防伪标签”,让设备能识别出哪些固件是官方发布的,哪些是被篡改过的。核心流程就两步:发布者用私钥签名,设备用公钥校验。

嗯,这些概念看起来简单,但实际落地时坑不少。比如密钥怎么存、签名数据放哪里、校验失败怎么处理……这些咱们后面章节会一个一个拆解。今天先把基础打牢,后面才能跑得快。