4、签名算法(上):RSA算法原理、密钥生成、签名与验签流程
说到固件签名,RSA 算法是绕不开的基石。我最早接触 RSA 是在做一款 IoT 网关的固件安全升级时,当时被公钥、私钥、模幂运算这些概念搞得晕头转向。后来踩了几个坑,才真正理解它为什么能成为工业界的主流选择。
这一节,咱们就把 RSA 的底裤扒干净。从数学原理到代码实现,一步步走通。
4.1 RSA 算法核心原理
RSA 的安全性建立在「大整数分解」这个数学难题上。说白了就是:两个大质数相乘很容易,但把乘积分解回两个质数,难如登天。
举个例子:13 × 17 = 221,你一秒就能算出来。但给你 221,让你找出 13 和 17,就得花点时间。如果数字大到 2048 位,用目前最快的计算机也要算到宇宙毁灭。
RSA 的核心流程分三步:
- 密钥生成:选两个大质数,算出公钥和私钥
- 签名:用私钥对固件哈希值加密,生成签名
- 验签:用公钥解密签名,比对哈希值
关键点:私钥签名,公钥验签。私钥必须绝对保密,公钥可以公开。
我在项目中见过有人把私钥硬编码在固件里,结果被逆向出来,整个产品线都得召回。嗯,这种坑咱们不能踩。
4.2 密钥生成:手把手走一遍
密钥生成是 RSA 最核心也最容易出错的地方。我习惯用 OpenSSL 来演示,因为它在嵌入式领域最常用。
4.2.1 选择两个大质数 p 和 q
这两个质数要足够大,通常 1024 位以上。实际开发中我们不会自己找质数,而是用工具生成:
# 生成 2048 位 RSA 私钥
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
这条命令背后发生了什么?OpenSSL 会随机选两个 1024 位的质数 p 和 q,然后计算:
- n = p × q(模数,公钥和私钥都包含它)
- φ(n) = (p-1)(q-1)(欧拉函数值)
- e(公钥指数,通常取 65537)
- d = e⁻¹ mod φ(n)(私钥指数,用扩展欧几里得算法计算)
公钥就是 (n, e),私钥就是 (n, d)。
我的习惯:公钥指数 e 固定用 65537。为什么?因为它是一个费马素数,计算效率高,而且安全性经过充分验证。别自作聪明改成 3 或 17,历史上出过不少漏洞。
4.2.2 提取公钥
# 从私钥中提取公钥
openssl rsa -pubout -in private_key.pem -out public_key.pem
公钥文件里只有 (n, e),没有 p、q、d。所以别人拿到公钥也没法反推出私钥——除非他能分解 n。
4.3 签名流程:私钥加密哈希值
固件签名不是直接加密整个固件,那样太慢了。正确的做法是:
- 计算固件的哈希值(比如 SHA-256)
- 用私钥对哈希值进行 RSA 加密,得到签名
- 将签名附加到固件末尾
用 OpenSSL 签名一条固件:
# 计算固件哈希并签名
openssl dgst -sha256 -sign private_key.pem -out firmware.sig firmware.bin
这条命令做了两件事:先算 SHA-256 哈希,再用私钥加密。输出的 firmware.sig 就是签名数据。
我曾经踩过的坑:签名前一定要确认哈希算法。有一次我用了 SHA-1,结果被客户的安全审计卡住,说 SHA-1 已经不安全了。现在行业标准是 SHA-256 起步,推荐 SHA-384 或 SHA-512。
4.4 验签流程:公钥解密比对
验签是签名的逆过程。设备端拿到固件和签名后:
- 用公钥解密签名,得到原始哈希值
- 重新计算固件的哈希值
- 比对两个哈希值是否一致
OpenSSL 验签命令:
# 验签
openssl dgst -sha256 -verify public_key.pem -signature firmware.sig firmware.bin
如果输出 Verified OK,说明固件未被篡改,且确实来自持有私钥的开发者。
你想想看,如果固件被篡改过,重新计算的哈希值就会变,验签必然失败。这就是 RSA 签名能防篡改的根本原因。
4.5 知识体系总览
下面这张图把 RSA 签名验签的完整流程串起来了:
4.6 实际开发中的注意事项
理论讲完了,说点实战中容易翻车的地方:
| 问题 | 后果 | 解决方案 |
|---|---|---|
| 密钥长度太短 | 容易被暴力破解 | 至少 2048 位,推荐 4096 位 |
| 私钥泄露 | 任何人都能伪造签名 | 硬件安全模块(HSM)存储 |
| 哈希算法过时 | 碰撞攻击风险 | 使用 SHA-256 或更高 |
| 签名未校验 | 固件被篡改也不自知 | Bootloader 中强制验签 |
我的建议:在嵌入式设备中,公钥要烧写在只读存储器(如 OTP)里,防止被替换。我曾经见过一个产品,公钥存在可擦写的 Flash 中,攻击者直接替换公钥,然后用自己生成的私钥签名恶意固件,整个安全体系形同虚设。
RSA 的数学原理其实不复杂,难的是在实际工程中把每个环节都做对。密钥生成、签名、验签,每一步都有坑。但只要理解了核心逻辑——私钥签名、公钥验签、哈希比对——你就能搭建起可靠的固件安全体系。
下一节咱们继续聊 RSA 的变种和优化,以及在资源受限的 MCU 上如何高效实现验签。