4. 核心算法:RSA 算法原理与 ECC 简介
聊到嵌入式签名验签,绕不开 RSA。这玩意儿虽然年纪不小了,但至今仍是工业界的扛把子。我个人习惯把 RSA 比作一个「单向门」——从这边过去容易,想从那边翻回来?门儿都没有。
咱们先把这个门的结构拆开看。你理解了密钥生成、加解密、签名验签这三块,基本就能应付 90% 的嵌入式场景了。
4.1 RSA 密钥生成:找两个大质数
RSA 的安全性,说白了就建立在「大数分解很难」这个数学事实上。我当年刚入行时,总觉得这步很简单,直到有一次在资源受限的 MCU 上生成 2048 位密钥……嗯,那感觉就像用计算器算圆周率,慢得让人怀疑人生。
密钥生成的步骤其实很固定:
- 选两个大质数 p 和 q。实际中通常用 512 位以上,乘积 n = p × q 就是密钥长度(比如 1024 位、2048 位)。
- 计算欧拉函数 φ(n) = (p-1)(q-1)。这一步是数学核心,但代码里就是个乘法。
- 选一个公钥指数 e。常用 65537(0x10001),为什么?因为它二进制只有两个 1,模幂运算快。
- 计算私钥 d,满足 e × d ≡ 1 (mod φ(n))。说白了就是求 e 的模逆元。
关键点:p 和 q 必须随机生成,且不能太接近。我在项目中见过有人直接用固定质数表,结果被侧信道攻击一把梭——千万别偷懒。
生成完,公钥就是 (n, e),私钥是 (n, d)。p、q、φ(n) 这些中间值,用完最好立刻擦掉。嵌入式环境里,内存残留是安全大忌。
4.2 RSA 加密与解密:数学魔术
加密和解密,其实就是两个模幂运算:
- 加密:密文 c = m^e mod n(m 是明文,必须小于 n)
- 解密:明文 m = c^d mod n
你想想看,为什么能还原?因为 e 和 d 互为逆元,模幂运算的交换律保证了 m^(e×d) ≡ m (mod n)。
但这里有个坑——直接对数据做 RSA 加密是不安全的。为什么?因为 RSA 是确定性算法,同样的明文每次加密结果都一样。攻击者可以搞字典攻击。
避坑指南:我曾经在一个 IoT 设备固件升级方案里,看到有人直接用 RSA 加密固件块。结果每个块的前几个字节固定(文件头),攻击者直接通过密文比对就猜出了固件版本。正确的做法是使用 OAEP 或 PKCS#1 v1.5 填充。
嵌入式里,RSA 加密用得少,签名才是主流。因为公钥加密太慢,通常只用来加密对称密钥(比如 AES 密钥),这叫「混合加密」。
4.3 RSA 签名与验签:反过来用
签名验签,其实就是把加解密反过来:
- 签名:用私钥 d 对哈希值做模幂运算,生成签名 s = hash(m)^d mod n
- 验签:用公钥 e 对签名做模幂运算,得到 hash' = s^e mod n,然后比对 hash' 和原始哈希
为什么能验?因为只有私钥持有者能生成合法的 s,而公钥任何人都能验证。这就是「不可否认性」的来源。
实际工程中,签名流程是这样的:
// 伪代码:RSA 签名流程
1. 计算消息哈希:h = SHA256(message)
2. 对哈希做 DER 编码(填充算法标识)
3. 做 PKCS#1 v1.5 或 PSS 填充
4. 模幂运算:signature = padded_hash^d mod n
5. 输出签名(通常和消息一起发送)
// 验签流程
1. 从消息计算哈希:h = SHA256(message)
2. 模幂运算:padded_hash' = signature^e mod n
3. 解填充,提取哈希值
4. 比对 h 和提取出的哈希值
我的经验:填充方案选 PSS 更安全,但 PKCS#1 v1.5 兼容性更好。如果设备要跟云端通信,先确认对方支持哪种。我曾经因为填充不匹配,调了三天接口……
4.4 RSA 在嵌入式中的性能考量
RSA 的运算量主要在模幂上。2048 位 RSA 签名,在 Cortex-M4 上大概需要几百毫秒到几秒。这个速度够不够?看场景:
| 场景 | RSA 操作 | 典型耗时(Cortex-M4 @ 100MHz) | 是否可接受 |
|---|---|---|---|
| 固件启动验签 | 验签一次 | 200-500ms | ✅ 可以(启动一次) |
| OTA 包签名 | 签名一次 | 1-3s | ✅ 可以(后台操作) |
| 每包数据签名 | 频繁签名 | 秒级 | ❌ 不行(换 ECC 或 HMAC) |
如果 MCU 没有硬件加速器,RSA 的模幂运算就是纯软件算。我建议:能上硬件加速就上,比如 NXP 的 i.MX RT 系列自带 RSA 引擎,速度能快 10 倍以上。
4.5 ECC 算法简介:小而美
ECC(椭圆曲线密码学)是 RSA 的替代者。它用更短的密钥达到同等安全强度:
| 安全等级 | RSA 密钥长度 | ECC 密钥长度 | 优势 |
|---|---|---|---|
| 80 位 | 1024 | 160-223 | ECC 短 5-6 倍 |
| 112 位 | 2048 | 224-255 | ECC 短 8 倍 |
| 128 位 | 3072 | 256-383 | ECC 短 10 倍 |
| 256 位 | 15360 | 512+ | ECC 短 30 倍 |
为什么 ECC 这么强?因为它基于「椭圆曲线离散对数问题」——比大数分解难得多。说白了,同样的破解算力,ECC 能扛更久。
ECC 的核心操作是标量乘法:k × G,其中 G 是曲线上的基点,k 是私钥。这个运算比 RSA 的模幂快不少,尤其适合资源受限的嵌入式设备。
实际选型建议:
- 如果设备有硬件加速器,RSA 2048 仍然够用,生态成熟
- 如果追求性能或密钥存储空间有限,选 ECC P-256(secp256r1)
- 如果考虑量子安全,RSA 和 ECC 都不行,得换后量子密码(但那是另一门课了)
4.6 RSA vs ECC:一张图看懂
下面这张图,是我自己画的核心逻辑对比。你一看就明白两者的定位差异:
4.7 嵌入式签名验签的工程要点
最后,我总结几个实际项目里踩过的坑:
- 随机数生成器:RSA 和 ECC 都依赖高质量随机数。嵌入式里别用 rand(),用硬件 TRNG 或 DRBG。我曾经见过用系统 tick 做种子的……那安全性约等于零。
- 侧信道防护:模幂运算的时间、功耗、电磁辐射都可能泄露密钥。加「盲化」或「恒定时间」实现,别裸奔。
- 密钥存储:私钥别明文放 Flash。用安全元件(SE)或 TEE 保护。如果 MCU 没有这些,至少做 XOR 混淆或烧断熔丝。
- 证书链:别只验根证书。中间证书也要验,否则攻击者可以伪造子证书。我在一个网关项目里就因为这个被攻破过……
一句话总结:RSA 是老兵,可靠但笨重;ECC 是新锐,灵活但要注意曲线选择。嵌入式里,选哪个取决于你的硬件资源、性能需求和生态兼容性。没有银弹,只有权衡。