1. 固件签名基础:什么是固件签名、数字签名的工作原理、常见的签名算法

做固件逆向分析,绕不过去的第一道坎就是签名验证。我刚开始接触嵌入式安全那会儿,总觉得签名就是个「加个密」的事儿,后来被现实狠狠教育了一顿——签名不是加密,签名是防篡改和验身份。你想想看,一个设备要是连谁写的固件都验不出来,那跟裸奔有什么区别?

1.1 什么是固件签名

固件签名,说白了就是在固件镜像后面贴一张「数字封条」。这张封条用私钥生成,任何人都能用对应的公钥去验证它是不是真的。

一个典型的签名固件包含两部分:

  • 固件本体——二进制镜像,可能是裸机程序、Linux 内核、或者某个 bootloader
  • 签名值——对固件哈希值进行私钥运算后的结果,通常附加在固件末尾或头部

我在项目中遇到过不少设备,签名值就放在固件偏移 0x100 的位置,连个对齐填充都没做。嗯,这种「裸奔式签名」其实挺常见的,尤其是那些从开源项目改过来的 IoT 设备。

核心要点:固件签名 ≠ 固件加密。签名保证的是「谁写的」和「改没改过」,加密保证的是「别人看不懂」。很多工程师把这两个概念混在一起,调试的时候会出大问题。

1.2 数字签名的工作原理

数字签名的流程其实不复杂,我画个图你就明白了:

数字签名工作流程 固件镜像 哈希运算 (SHA-256) 私钥签名 固件 + 签名值 传输 固件 + 签名值 哈希运算 (SHA-256) 公钥验签 验证通过 / 失败 关键点: • 私钥永远留在签名方,公钥可以公开分发 • 哈希运算是单向的,固件改一个 bit,哈希值完全变样 • 验签失败 = 固件被篡改 或 签名者身份不匹配

流程看着简单,但实际落地的时候坑特别多。我见过一个设备,验签的时候只检查了签名值的前 4 个字节——你猜怎么着?攻击者随便填个 0x00000000 就绕过去了。这种「半吊子验签」在逆向分析里简直就是送人头。

1.3 常见的签名算法

嵌入式世界里,签名算法就那么几种。我按使用频率排个序:

算法 密钥长度 签名长度 典型场景 我的评价
RSA 1024~4096 bit 与密钥等长 Bootloader、固件更新包 老牌选手,资源消耗大
ECDSA 256~521 bit 约 2×密钥长度 IoT 设备、安全芯片 短密钥高强度,我的首选
HMAC 对称密钥 与哈希输出等长 内部通信、轻量验证 不是真正的签名,慎用

RSA 签名

RSA 签名是最早被广泛使用的方案。它的核心逻辑是:私钥加密哈希值,公钥解密比对。我习惯叫它「教科书式签名」——因为几乎所有密码学教材都会拿它举例。

但 RSA 有个硬伤:慢。尤其是在那些主频不到 100MHz 的 MCU 上,验一次 2048 位的 RSA 签名可能要几百毫秒。我曾经在一个 Cortex-M3 的平台上调 RSA 验签,优化了半天才压到 150ms——用户还是嫌开机慢。

避坑指南:我曾经遇到过一个设备,RSA 公钥硬编码在固件里,但验签时没有检查公钥的合法性。攻击者直接替换公钥为自己的公钥,然后用自己生成的私钥签名恶意固件——完美绕过。记住:公钥必须被安全存储和验证,否则签名形同虚设。

ECDSA 签名

ECDSA 基于椭圆曲线密码学,用更短的密钥达到和 RSA 同等级别的安全强度。我个人非常推荐在资源受限的设备上用 ECDSA。

举个例子:

  • RSA 2048 位签名 ≈ 256 字节
  • ECDSA 256 位签名 ≈ 64 字节(r + s 各 32 字节)

签名长度差了 4 倍,这对固件大小和传输带宽的影响是实打实的。我在做智能门锁项目时,固件更新包只有 64KB,用 RSA 的话光签名就占了 256 字节,换成 ECDSA 只占 64 字节——省下来的空间够塞一个功能模块了。

不过 ECDSA 也有坑:随机数质量。如果签名时用的随机数重复或可预测,私钥就能被算出来。嗯,这个漏洞在真实世界里已经出现过好几次了,比如索尼 PS3 的签名密钥泄露事件。

HMAC 签名

HMAC 其实不是真正的「数字签名」,它用的是对称密钥。发送方和接收方共享同一个密钥,对消息计算 HMAC 值,接收方用同样的密钥重新计算并比对。

为什么说它「不是真正的签名」?因为:

  • 无法提供不可否认性——双方都能生成同样的 HMAC,没法证明是谁签的
  • 密钥分发是个大问题——所有验签设备都得存同一个密钥,泄露一个等于全完

但 HMAC 也有它的用武之地。我在一些低成本的蓝牙设备上见过 HMAC 做固件验证——说白了就是防君子不防小人。攻击者只要从一台设备里把密钥 dump 出来,整个产品线就沦陷了。

警告:HMAC 不能用于「你是谁」的验证,只能用于「消息有没有被改过」。如果你的产品需要防固件篡改,请用 RSA 或 ECDSA。HMAC 在逆向分析面前基本等于裸奔——我见过太多用 HMAC 做「签名」的设备,密钥提取出来后整个安全体系瞬间崩塌。

1.4 签名在固件中的存储方式

签名值怎么塞进固件里?常见的做法有三种:

  1. 追加在固件末尾——最简单,bootloader 先读固件再读签名
  2. 嵌入在固件头部——签名放在固定偏移,方便快速定位
  3. 独立签名文件——固件和签名分开存储,更新时一起下发

我个人最讨厌第三种——因为逆向分析的时候,你得先找到签名文件在哪,再找到对应的公钥。有一次我分析一个路由器固件,签名文件藏在文件系统的 /etc 目录下,文件名还伪装成配置文件……找了我整整两天。

1.5 本章小结

固件签名不是什么玄学,它就是一套「谁写的 + 改没改过」的验证机制。RSA 老而弥坚,ECDSA 短小精悍,HMAC 只能算个备胎。理解这些基础,后面讲签名绕过攻击的时候你才能知道——攻击者到底在绕什么。