一、固件签名基础:从“你是谁”到“你被信任”

各位好,我是老周。做嵌入式安全这些年,我见过太多因为固件被篡改而翻车的项目。今天咱们就从最基础的东西聊起——固件签名。

你可能会问:签名不就是加个校验吗?其实没那么简单。我刚开始接触这个领域时也这么想,直到有一次在产线上发现,明明哈希校验都过了,设备还是跑飞了……嗯,后来才搞明白,哈希和签名是两码事。

什么是固件签名?

固件签名,说白了就是给固件打上一个“数字指纹+身份证明”。它解决两个核心问题:

  • 这个固件是谁发布的?——身份认证
  • 这个固件有没有被改过?——完整性校验

我习惯用一个比喻:固件签名就像你给重要文件盖上公章。别人看到公章就知道是你发的,而且如果文件被涂改过,公章就失效了。

核心概念:固件签名 = 私钥签名 + 公钥验证。私钥只有发布者持有,公钥可以公开。签名过程是“加密”哈希值,验证过程是“解密”并比对。

为什么需要签名?

你想想看,没有签名的固件是什么状态?就像在公共白板上贴了一张纸条,谁都能撕下来改两笔再贴回去。设备拿到固件后,根本不知道它是不是原厂发的。

我在项目中遇到过最典型的场景:

  • OTA升级被劫持——攻击者伪造固件包,设备傻傻地刷进去,直接变砖
  • 供应链攻击——代工厂偷偷替换固件,植入后门
  • 调试接口泄露——未签名的固件被逆向,核心算法被盗

避坑指南:我曾经接手过一个项目,团队觉得“反正产品不联网,签名没必要”。结果客户现场用U盘升级固件,U盘被人动了手脚……从那以后,我坚持所有固件必须签名,不管是否联网。

签名与哈希的区别

这是新人最容易搞混的地方。我画个表你就明白了:

特性 哈希(Hash) 签名(Signature)
作用 校验数据完整性 校验完整性 + 身份认证
密钥 不需要密钥 需要公私钥对
能否伪造 任何人都能计算哈希 只有私钥持有者能签名
抗抵赖性 无 有(非对称加密保证)
典型算法 SHA-256, SHA-384 RSA, ECDSA, Ed25519

简单说:哈希只能告诉你“东西变了没”,签名能告诉你“谁变的”以及“是不是合法的”。

我的经验:很多安全方案只做哈希校验,觉得够了。但你想,如果攻击者同时替换了固件和哈希值,设备根本发现不了。签名就不一样——攻击者没有私钥,伪造不了签名。

常见的签名算法

目前主流的就是RSA和ECDSA。我分别说说它们的脾气。

RSA(Rivest-Shamir-Adleman)

RSA是老牌算法,成熟、稳定、专利已过期。我最早做固件签名时用的就是RSA-2048。

  • 优点:实现简单,硬件支持广泛,很多MCU内置RSA加速器
  • 缺点:密钥太长(2048位),签名慢,占用Flash空间大
  • 典型场景:网关、服务器端签名,资源相对充裕的设备
// RSA-2048 签名示例(伪代码)
// 1. 计算固件哈希
hash = SHA256(firmware.bin)

// 2. 使用私钥签名
signature = RSA_Sign(private_key, hash, PSS_PADDING)

// 3. 将签名附加到固件尾部
firmware_signed = firmware.bin || signature

ECDSA(Elliptic Curve Digital Signature Algorithm)

ECDSA是后起之秀,用更短的密钥达到同等安全强度。我个人现在更倾向用ECDSA,尤其是资源受限的IoT设备。

  • 优点:密钥短(256位 ≈ RSA-3072安全等级),签名快,省Flash
  • 缺点:实现复杂,随机数生成要求高(随机数出问题会泄露私钥)
  • 典型场景:MCU、传感器、蓝牙设备等资源受限场景
// ECDSA P-256 签名示例(伪代码)
// 1. 计算固件哈希
hash = SHA256(firmware.bin)

// 2. 使用私钥签名(注意:随机数k必须安全生成)
signature = ECDSA_Sign(private_key, hash, k_random)

// 3. 将签名附加到固件尾部
firmware_signed = firmware.bin || signature

踩过的坑:ECDSA的随机数生成是个大坑。我曾经见过一个方案,随机数生成器没初始化好,每次签名都用同一个k值。结果攻击者拿到两个签名就反推出了私钥……嗯,从那以后我坚持每次签名前检查随机数熵源。

算法对比表

对比项 RSA-2048 ECDSA P-256 Ed25519
密钥长度 2048位 256位 256位
签名长度 256字节 64字节 64字节
签名速度 慢 快 极快
验证速度 快 慢 快
硬件支持 广泛 较广泛 较少
推荐场景 服务器端、网关 MCU、IoT设备 高性能嵌入式

固件签名流程总览

下面这张图是我自己总结的固件签名标准流程,你可以把它当作模板来用:

固件签名与验证流程 签名端(开发/发布) 1. 计算固件哈希(SHA-256) 2. 使用私钥签名哈希 3. 打包:固件 + 签名 + 证书 传输/存储 OTA / U盘 / 网络 验证端(设备/Bootloader) 4. 提取签名和公钥 5. 用公钥解密签名 → 得到哈希A 6. 计算固件哈希 → 得到哈希B 哈希A == 哈希B? 拒绝启动 允许启动 说明:签名端使用私钥,验证端使用公钥。公钥通常预置在设备BootROM或安全存储中。 哈希A来自签名解密,哈希B来自本地计算,两者一致则固件可信。

小结

固件签名不是可选项,而是安全基线。我见过太多“先上线再说”的项目,最后都回来补签名方案——代价往往是原来的10倍。

记住三个要点:

  • 哈希 ≠ 签名,签名多了身份认证和抗抵赖性
  • RSA适合资源充裕的场景,ECDSA适合资源受限的设备
  • 私钥必须安全存储,公钥可以公开但需要防篡改

个人建议:新项目直接上ECDSA P-256或Ed25519。RSA虽然成熟,但密钥太长,未来趋势是向椭圆曲线迁移。别等到产品定型了再改算法,那滋味……我尝过,不好受。