3. 经典签名算法详解
聊到经典签名算法,我得先坦白一件事。我入行那会儿,RSA 就是签名的代名词。后来 ECDSA 火了,再后来 EdDSA 开始被大家重视。现在要迁移到 PQC,你反而得把这些老家伙彻底搞明白——因为迁移的本质,就是拿新算法去替换它们。你不了解要替换的对象,迁移方案就是空中楼阁。
这一章,我把三个最主流的经典签名算法掰开揉碎了讲。原理、参数、安全强度,一个都不放过。
3.1 RSA-PSS:老将的自我修养
RSA-PSS,全称 RSA Probabilistic Signature Scheme。说白了,它就是 RSA 签名的一个安全补丁版本。
早期的 RSA 签名用的是 PKCS#1 v1.5 填充。那个方案有个毛病——签名是确定性的。同样的消息,每次签名结果一模一样。这给了攻击者可乘之机,比如 Bleichenbacher 攻击就是利用这个特性搞事情。
PSS 的改进思路很直接:引入随机数。每次签名前,往消息里混入一个随机盐值(salt)。这样一来,同样的消息每次签名结果都不同。攻击者想搞选择明文攻击?难度直接翻倍。
原理简述
RSA-PSS 的签名流程大致分三步:
- 消息编码:把原始消息通过哈希函数处理,再跟随机盐值、填充字节拼在一起,形成一个固定长度的编码结果。
- 签名生成:用私钥对编码结果做 RSA 模幂运算,得到签名值。
- 签名验证:用公钥做模幂运算,恢复出编码结果,然后反向解码,比对哈希值是否一致。
嗯,这里要注意:PSS 的编码过程比 v1.5 复杂得多。它用了掩码生成函数(MGF1)来扩散随机性。我当年第一次实现 PSS 时,被 MGF1 的嵌套循环搞得头晕。后来发现,其实只要按标准一步步来,没那么玄乎。
参数选择
RSA-PSS 的参数选择,核心就两个:模数长度和盐值长度。
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 模数长度 | 2048 / 3072 / 4096 位 | 2048 位目前安全,但建议新系统直接上 3072 位 |
| 盐值长度 | 等于哈希输出长度 | 比如 SHA-256 就用 32 字节,别偷懒 |
| 哈希函数 | SHA-256 / SHA-384 | 别用 SHA-1,已经废了 |
我的经验:盐值长度别小于哈希输出长度。我在一个项目里见过有人把盐值设成 0——那跟 PKCS#1 v1.5 有什么区别?安全强度直接打回原形。
安全强度
RSA-PSS 的安全性依赖于大整数分解问题的困难性。目前 2048 位 RSA 大概提供 112 位安全强度,3072 位对应 128 位。但注意,这是经典计算下的评估。量子计算机来了,Shor 算法直接把它秒成渣——这也是我们为什么要迁移到 PQC。
3.2 ECDSA:椭圆曲线上的签名舞者
ECDSA,Elliptic Curve Digital Signature Algorithm。它跟 RSA 走的是完全不同的路子。RSA 靠大整数分解,ECDSA 靠椭圆曲线离散对数问题(ECDLP)。
我个人习惯把 ECDSA 比作「短签名」的代表。同样安全强度下,ECDSA 的签名长度和密钥长度都比 RSA 短得多。256 位 ECDSA 的安全强度约等于 3072 位 RSA。这在 IoT 设备上简直是天大的优势——你想想看,一个传感器芯片的存储空间就那么点,用 RSA 可能连密钥都塞不下。
原理简述
ECDSA 的签名过程涉及椭圆曲线上的点乘运算。大致流程:
- 生成一个随机数 k,计算 k * G(G 是基点),得到点 R。
- 用 R 的 x 坐标计算签名分量 r。
- 用私钥、消息哈希和 r 计算签名分量 s。
- 签名就是 (r, s) 对。
验证时,验证方用公钥、消息哈希和签名 (r, s) 恢复出点 R',然后比对 R' 的 x 坐标是否等于 r。
我曾经踩过的坑:随机数 k 绝对不能重复使用!如果两次签名用了同一个 k,攻击者可以直接算出私钥。2010 年索尼 PS3 的 ECDSA 签名被破解,就是因为 k 是固定的。嗯,这个教训是用真金白银换来的。
参数选择
ECDSA 的参数选择比 RSA 复杂,因为涉及曲线类型。主流选择:
| 曲线 | 密钥长度 | 安全强度 | 适用场景 |
|---|---|---|---|
| P-256 (secp256r1) | 256 位 | 128 位 | 通用,NIST 推荐 |
| P-384 (secp384r1) | 384 位 | 192 位 | 高安全场景 |
| P-521 (secp521r1) | 521 位 | 256 位 | 极高标准 |
| secp256k1 | 256 位 | 128 位 | 区块链场景(比特币) |
我建议 IoT 固件签名优先选 P-256。原因很简单:硬件加速支持最广泛。很多 MCU 芯片内置了 P-256 的硬件加速单元,签名验签速度能快一个数量级。
安全强度
ECDSA 的安全性基于 ECDLP。经典计算下,256 位曲线提供 128 位安全强度。但量子计算来了,情况跟 RSA 一样惨——Shor 算法同样能破解 ECDLP。所以 ECDSA 也在被替换之列。
3.3 EdDSA:后起之秀的优雅设计
EdDSA,Edwards-curve Digital Signature Algorithm。它是 Daniel J. Bernstein 等人设计的,基于扭曲爱德华曲线(Edwards curve)。
说实话,我第一次接触 EdDSA 时,觉得它比 ECDSA 优雅太多了。为什么?因为它解决了 ECDSA 的几个老大难问题:
- 确定性签名:EdDSA 不需要随机数生成器。签名结果是确定性的,但通过哈希私钥和消息来模拟随机性,既安全又省心。
- 侧信道攻击防护:EdDSA 的运算不依赖秘密数据的分支和查表,天然抗时序攻击。
- 批量验证:EdDSA 支持高效的批量签名验证,这在固件更新场景下特别有用。
原理简述
EdDSA 的核心是 Ed25519(基于 Curve25519)。签名过程:
- 用哈希函数处理私钥,得到两个部分:一个用于生成随机数 r,一个用于生成公钥。
- 计算 r * G 得到点 R。
- 用消息哈希、R 和公钥计算挑战值 h。
- 计算签名分量 s = r + h * 私钥。
- 签名就是 (R, s) 对。
验证时,验证方计算 h,然后检查 s * G 是否等于 R + h * 公钥。整个过程干净利落。
关键区别:EdDSA 的签名是 (R, s),而 ECDSA 是 (r, s)。EdDSA 直接传递点 R,省去了从 x 坐标恢复点的步骤。这看起来是小改动,但实际实现时少了很多边界情况处理。
参数选择
EdDSA 的参数选择比 ECDSA 简单得多。主流就两个变种:
| 变种 | 曲线 | 密钥长度 | 安全强度 | 特点 |
|---|---|---|---|---|
| Ed25519 | Curve25519 | 256 位 | 128 位 | 速度极快,签名仅 64 字节 |
| Ed448 | Goldilocks | 448 位 | 224 位 | 更高安全,签名 114 字节 |
我建议 IoT 场景无脑选 Ed25519。签名短、速度快、实现简单。我在一个资源受限的 MCU 上移植过 Ed25519,整个签名库才几 KB,跑起来比 ECDSA P-256 还快 30%。
安全强度
Ed25519 提供 128 位安全强度,Ed448 提供 224 位。同样,量子计算下它们都不安全。但 EdDSA 的设计理念——确定性、抗侧信道、简单实现——对 PQC 签名算法的设计有深远影响。你去看 Dilithium 和 Falcon 的设计,多少都借鉴了 EdDSA 的思路。
3.4 三剑客对比
我把三个算法放在一起对比,方便你选型时参考:
| 特性 | RSA-PSS | ECDSA | EdDSA |
|---|---|---|---|
| 数学基础 | 大整数分解 | 椭圆曲线离散对数 | 爱德华曲线离散对数 |
| 签名长度 | 256 字节 (2048位) | 64 字节 (P-256) | 64 字节 (Ed25519) |
| 公钥长度 | 256 字节 | 32 字节 | 32 字节 |
| 签名速度 | 慢 | 中等 | 快 |
| 验证速度 | 快 | 中等 | 快 |
| 随机数需求 | 需要(盐值) | 需要(k 值) | 不需要(确定性) |
| 抗侧信道 | 中等 | 弱(需额外防护) | 强(设计内置) |
| 硬件加速支持 | 广泛 | 广泛(P-256) | 逐渐普及 |
| 量子安全 | 否 | 否 | 否 |
你看这个表,EdDSA 在 IoT 场景下几乎全面占优。但现实是,很多现有系统用的是 RSA-PSS 或 ECDSA。迁移到 PQC 时,你得考虑兼容性——不能一刀切把老算法全砍了,得逐步过渡。
3.5 知识体系总览
下面这张图把三个算法的核心脉络串起来了。你可以把它当作本章的「导航地图」。
这张图把三个算法的数学基础、核心特性、安全强度和量子安全状态串在了一起。你看最下面那行——不管你现在用哪个,最终都要往 PQC 迁移。区别只是迁移路径和节奏不同。
3.6 迁移视角的思考
讲完这三个算法,我想从迁移视角给你几个建议:
- 别急着全换:如果你的系统还在用 RSA-PSS 2048 位,短期内不用慌。先做兼容性评估,再规划迁移路径。
- 优先考虑 EdDSA:如果系统还没定型,或者正在做架构升级,我建议先切到 EdDSA。它跟 PQC 签名的设计理念更接近,迁移时改动更小。
- 关注混合签名方案:过渡期可以用经典签名 + PQC 签名的组合。比如固件同时携带 RSA-PSS 和 Dilithium 签名,验证方根据能力选择验证。这样既保证向后兼容,又逐步引入量子安全。
我的经验:在 IoT 固件签名场景下,我建议先做「签名算法抽象层」。把签名验证接口封装成统一的 API,底层可以切换算法。这样迁移时只需要换底层实现,上层固件更新逻辑完全不用动。这个抽象层我做了三次迭代才稳定下来——第一次太厚,性能损失大;第二次太薄,灵活性不够。第三次才找到平衡点。