1. 签名基础概念:什么是固件签名、为什么需要签名、签名与校验的基本流程
各位同学,咱们今天聊固件签名。说实话,我刚入行那会儿,对签名这事儿也没太当回事。觉得不就是给固件加个“锁”嘛,能有多重要?直到有一次,我在一个IoT项目里亲眼看到,因为没做签名校验,设备被刷入了恶意固件,整批产品差点召回。嗯,从那以后,我再也不敢小看签名了。
1.1 什么是固件签名
固件签名,说白了就是给固件文件打上一个“数字指纹”。这个指纹是唯一的,而且只有固件的发布者才能生成。你想想看,就像你签合同要手写签名一样,固件签名就是告诉设备:“这个固件是我官方发布的,没被人动过手脚。”
签名过程通常用到两个东西:私钥和公钥。私钥只有发布者自己知道,用来生成签名;公钥是公开的,设备用它来验证签名是否有效。
核心概念速览:
- 固件签名:用私钥对固件哈希值加密,生成签名数据
- 签名校验:设备用公钥解密签名,对比哈希值是否一致
- 哈希算法:把固件内容映射成固定长度的摘要(如SHA-256)
- 非对称加密:私钥签名,公钥验签,两者不互通
1.2 为什么需要签名
我遇到过不少刚入行的工程师问:“固件烧进去能跑就行,干嘛非要签名?”这个问题问得好。咱们从三个角度来拆解:
- 防篡改:固件在传输、存储过程中,可能被恶意修改。签名能保证固件内容没被改过。
- 防假冒:第三方可能伪造固件,冒充官方版本。签名能验证发布者身份。
- 防回滚:攻击者可能把设备降级到有漏洞的旧版本。签名机制可以配合版本号,拒绝旧固件。
我记得有个项目,客户要求设备必须支持安全启动。当时我们用的MCU支持签名校验,但固件升级流程里没做。结果测试时发现,只要把固件包里的版本号改小,设备就乖乖降级了。后来加上签名校验,这个问题才彻底解决。
避坑指南:我曾经在一个量产项目里,因为签名密钥管理不当,导致私钥泄露。结果第三方用这个私钥签了个恶意固件,所有设备都能刷进去。那次教训让我明白:密钥管理比签名算法本身更重要。私钥必须放在硬件安全模块(HSM)或安全存储区,绝不能明文写在代码里。
1.3 签名与校验的基本流程
咱们来看一个典型的固件签名和校验流程。我习惯把它分成两个阶段:签名阶段(在开发/发布环境做)和校验阶段(在设备端做)。
签名阶段(发布者侧)
- 计算固件文件的哈希值(比如SHA-256)
- 用私钥对哈希值进行加密,生成签名数据
- 把签名数据附加到固件文件里,或者单独存放
- 发布带签名的固件包
校验阶段(设备侧)
- 设备收到固件包,提取签名数据和原始固件
- 用公钥解密签名数据,得到原始的哈希值
- 重新计算固件的哈希值
- 对比两个哈希值:一致则校验通过,不一致则拒绝
小技巧:实际项目中,我建议把签名数据放在固件包的末尾,并加上固定长度的头部信息。这样设备端解析时,可以先读尾部固定长度的签名数据,再往前读固件内容。效率比从头扫描高得多。
下面这张图,我把整个流程画出来了。你一看就明白:
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 签名在固件升级中的位置
签名不是孤立存在的,它通常嵌入在固件升级流程里。我习惯把升级流程分成这几步:
- 固件打包:编译生成固件 → 计算哈希 → 签名 → 打包成升级文件
- 固件传输:通过OTA、UART、USB等方式发送到设备
- 固件接收:设备接收并存储到临时区域
- 签名校验:设备验证签名有效性
- 固件烧录:校验通过后,写入正式存储区
- 启动验证:设备重启时,再次校验固件签名(安全启动)
你看,签名校验在升级流程里出现了两次:一次在烧录前,一次在启动时。为什么要做两次?我遇到过一种攻击方式:攻击者在固件烧录完成后、设备重启前,篡改存储区的内容。如果只在烧录前校验,启动时不做二次校验,那就防不住这种攻击。
注意:签名校验必须放在设备端的可信执行环境里。如果校验代码本身可以被篡改,那签名就形同虚设。我见过一个项目,校验逻辑放在普通Flash里,攻击者直接跳过了校验函数。后来我们把校验代码放到ROM里,才彻底解决这个问题。
1.6 小结
这一章咱们聊了固件签名的基本概念。说白了,签名就是给固件加一道“防伪标签”,让设备能识别出哪些固件是官方发布的,哪些是被篡改过的。核心流程就两步:发布者用私钥签名,设备用公钥校验。
嗯,这些概念看起来简单,但实际落地时坑不少。比如密钥怎么存、签名数据放哪里、校验失败怎么处理……这些咱们后面章节会一个一个拆解。今天先把基础打牢,后面才能跑得快。