2、主流签名算法对比:RSA、ECDSA、Ed25519 的原理与性能差异
签名算法选型,是固件安全里最绕不开的一个决策点。我见过不少团队,上来就拍板用 RSA,理由是“大家都这么用”。但说实话,在嵌入式场景下,RSA 未必是最优解。今天咱们就把 RSA、ECDSA、Ed25519 这三兄弟拉出来,从原理到性能,掰开揉碎聊清楚。
2.1 算法核心原理速览
先看一张总览图,把三者的数学根基和签名流程串起来。这样你心里有个框架,后面细节才不会乱。
2.2 RSA:老牌劲旅,但有点“重”
RSA 的原理,说白了就是大整数分解。给你两个大素数 p 和 q,乘起来得到 n 很容易,但给你 n 让你反推出 p 和 q,难如登天。这就是 RSA 的安全根基。
签名过程是这样的:用私钥 (n, d) 对消息哈希做模幂运算,s = hash(m)^d mod n。验签时,用公钥 (n, e) 算 s^e mod n,看结果是否等于 hash(m)。
优点很明显:
- 生态成熟,几乎所有平台都支持
- 验签速度相对快(公钥指数 e 通常取 65537)
- 理解门槛低,文档多
缺点也扎眼:
- 密钥太长。2048 位的 RSA 公钥约 256 字节,私钥更大。在 Flash 和 RAM 紧张的 MCU 上,这很要命。
- 签名慢。私钥指数 d 很大,模幂运算耗时严重。我在一个 STM32F4 项目上测过,RSA-2048 签名一次要 200 多毫秒,用户等得直拍桌子。
- 没有原生抗侧信道能力。需要额外加掩码、盲化,否则功耗分析能直接把私钥扒出来。
避坑提醒: 我曾经在一个 IoT 网关项目里,直接用 OpenSSL 默认参数生成 RSA 密钥对,没注意 p 和 q 的差值太小。结果被同事用 Fermat 分解法在几分钟内算出了私钥。嗯,从那以后我生成 RSA 密钥都会手动检查 |p - q| 是否足够大。
2.3 ECDSA:短密钥,但随机数是个坑
ECDSA 基于椭圆曲线离散对数问题。给定基点 G 和公钥 Q = dG,想反推出私钥 d,目前没有多项式时间算法。所以 256 位的 ECDSA 密钥,安全强度就能对标 3072 位的 RSA。
签名过程生成一对 (r, s)。r 来自一个临时随机数 k 生成的点 R = kG 的 x 坐标,s 则通过私钥和消息哈希计算得出。
优点:
- 密钥短。256 位公钥只有 32 字节,私钥也是 32 字节。对嵌入式存储非常友好。
- 签名速度比 RSA 快不少。同样在 STM32F4 上,ECDSA P-256 签名大约 30~50 毫秒。
致命缺点:
- 随机数 k 必须唯一且不可预测。如果两次签名用了相同的 k,私钥可以直接算出来。这不是理论问题,是真实发生过的大规模安全事故——索尼 PS3 的 ECDSA 签名就因为随机数重复,导致整个签名体系被攻破。
- 验签比 RSA 慢。因为涉及两次点乘运算。
- 实现复杂。曲线参数、点压缩、坐标系统,稍不注意就踩坑。
我的建议: 如果非要用 ECDSA,务必使用 RFC 6979 确定性 ECDSA。它用私钥和消息哈希派生出 k,彻底消除随机数依赖。我在一个车规级固件更新项目里就是这么干的,省心不少。
2.4 Ed25519:后起之秀,我目前的首选
Ed25519 基于扭曲爱德华曲线,是 Bernstein 等人设计的现代签名方案。它用 x² + y² = 1 + dx²y² 这条曲线,配合 Schnorr 签名框架,实现了速度、安全性和实现鲁棒性的三重优势。
签名过程:私钥 a 由种子哈希生成,公钥 A = aB。签名时先计算随机数 r = Hash(seed || message),然后 R = rB,最后 S = r + Hash(R || A || message) * a mod L。签名就是 (R, S),总共 64 字节。
优点突出:
- 签名和验签都极快。在 Cortex-M4 上,Ed25519 签名只需 5~10 毫秒,验签也差不多。比 ECDSA 快 3~5 倍。
- 公钥仅 32 字节,签名 64 字节。比 RSA 小一个数量级。
- 原生抗侧信道。设计时就考虑了常数时间执行,不需要额外防护。
- 没有随机数依赖。所有随机性来自确定性派生,不会重蹈 ECDSA 的覆辙。
缺点:
- 生态不如 RSA 成熟。一些老旧的 Bootloader 或 HSM 可能不支持。
- 专利问题?其实 Ed25519 已经进入公共领域,但有些公司法律部门会多虑。
个人经验: 去年做一个电池管理系统的安全固件升级,MCU 是瑞萨的 RA6M4,Flash 只有 1MB。用 RSA-2048 的话,光密钥存储就占掉 1/4 的剩余空间。换成 Ed25519 后,密钥加签名总共不到 100 字节,签名时间从 200ms 降到 8ms。用户体验直接上了一个台阶。
2.5 性能对比:上数据说话
下面这张表,是我在 Cortex-M4 (STM32F407, 168MHz) 上实际跑出来的数据。硬件加速没开,纯软件实现。
| 指标 | RSA-2048 | ECDSA P-256 | Ed25519 |
|---|---|---|---|
| 公钥长度 | 256 字节 | 32 字节 | 32 字节 |
| 私钥长度 | 512 字节 | 32 字节 | 32 字节 |
| 签名长度 | 256 字节 | 64 字节 | 64 字节 |
| 签名耗时 | ~210 ms | ~35 ms | ~8 ms |
| 验签耗时 | ~8 ms | ~45 ms | ~10 ms |
| 安全强度 | 112 位 | 128 位 | 128 位 |
| 侧信道抗性 | 需额外实现 | 需额外实现 | 原生支持 |
| 随机数依赖 | 无 | 强依赖 | 无 |
看到没?Ed25519 在签名速度上几乎是碾压级的。验签虽然比 RSA 慢一丁点,但 RSA 的验签快是建立在公钥指数很小的前提下的——如果你把 e 改成 3 或 17,确实更快,但安全性会打折扣。
2.6 选型建议:场景决定一切
说了这么多,到底怎么选?我按场景给几个建议:
- 老旧平台或强制合规: 如果 Bootloader 只支持 RSA,或者客户指定要用 RSA,那就用 RSA。但尽量选 3072 位以上,2048 位已经有点悬了。
- 性能敏感且存储紧张: 无脑上 Ed25519。速度快、密钥短、实现安全。我目前 80% 的新项目都选它。
- 需要兼容现有 PKI 体系: 如果公司已经有一套基于 ECDSA 的 CA 和证书链,那就继续用 ECDSA。但记得用确定性 ECDSA 规避随机数风险。
- 量子安全考虑: 三者都不抗量子攻击。如果产品生命周期超过 10 年,建议预留算法切换接口,未来换成 Dilithium 或 Falcon。
重要提醒: 不管你选哪种算法,私钥的存储安全才是真正的短板。签名算法再强,私钥被从 Flash 里读出来也是白搭。我见过一个团队,Ed25519 签名跑得飞起,但私钥明文存在外部 SPI Flash 里……嗯,那还不如不签名。