3、数字签名:RSA签名与ECDSA签名的原理与对比
数字签名这东西,说白了就是现实世界里手写签名的电子版。你签了一份合同,对方能确认是你签的,而且签完之后内容没被人改过。在嵌入式系统里,签名验证是安全启动的基石——芯片上电后先校验固件签名,签名不对直接罢工。
我这些年经手的项目,从车规级MCU到物联网模组,签名方案基本就两派:RSA和ECDSA。今天咱们就把这两个家伙的底裤扒干净。
3.1 RSA签名:大数分解的守护者
RSA签名的数学基础,是「大整数分解困难问题」。给你两个大素数p和q,乘起来得到n很容易;但给你n,想反推出p和q,难如登天。
3.1.1 密钥生成
- 选两个大素数p和q,计算n = p × q
- 计算欧拉函数 φ(n) = (p-1)(q-1)
- 选一个公钥指数e,通常取65537(为什么?因为它是质数,且二进制只有两个1,计算快)
- 计算私钥d,满足 e × d ≡ 1 (mod φ(n))
公钥就是(n, e),私钥就是d。嗯,这里要注意:p和q生成后必须销毁,否则私钥就暴露了。
3.1.2 签名与验签流程
签名过程(用私钥d):
s = hash(m)^d mod n
验签过程(用公钥e):
hash(m) ≡ s^e mod n ?
如果等式成立,签名有效。
核心要点:RSA签名中,私钥签名、公钥验签。公钥可以公开,私钥必须死死守住。我在一个IoT网关项目里见过有人把私钥硬编码在固件里……嗯,那款产品后来被远程控制了,教训深刻。
3.1.3 实际工程中的坑
- 填充方案必须用PSS:老式的PKCS#1 v1.5填充有安全漏洞,我建议新项目一律用RSA-PSS。曾经有个客户拿着旧方案让我审计,我一看还是v1.5,直接建议他们改版。
- 密钥长度别低于2048位:1024位的RSA在2010年左右就被认为不安全了。现在嵌入式芯片算力上来了,2048位是底线,4096位更稳妥。
- 签名速度慢:RSA验签比签名快得多(因为e通常很小),但签名操作涉及大数模幂,在低端MCU上可能耗时几百毫秒。
3.2 ECDSA签名:椭圆曲线上的优雅舞者
ECDSA基于椭圆曲线离散对数问题(ECDLP)。同样是难问题,但椭圆曲线上的「难」比大数分解更「难」——这意味着同等安全强度下,ECDSA的密钥可以短得多。
3.2.1 密钥生成
- 选择一条椭圆曲线(如secp256r1、secp384r1)和基点G
- 随机生成私钥d(一个256位的随机数)
- 计算公钥Q = d × G(椭圆曲线上的点乘)
公钥Q是一个点(x, y),私钥d就是一个大整数。
3.2.2 签名与验签流程
签名过程(用私钥d):
1. 生成随机数k
2. 计算点R = k × G,取r = R.x
3. 计算s = k^(-1) × (hash(m) + d × r) mod n
4. 签名对为(r, s)
验签过程(用公钥Q):
1. 计算w = s^(-1) mod n
2. 计算u1 = hash(m) × w mod n
3. 计算u2 = r × w mod n
4. 计算点P = u1 × G + u2 × Q
5. 验证P.x ≡ r mod n ?
⚠️ 致命陷阱:随机数k绝对不能重复! 如果两次签名用了相同的k,私钥d可以直接被算出来。2010年索尼PS3的签名密钥就是这么泄露的——他们用了固定的k值。我在做安全审计时,一定会检查随机数生成器的实现,这个坑踩不得。
3.3 RSA vs ECDSA:正面硬刚
咱们直接上对比表,一目了然:
| 对比维度 | RSA (2048位) | ECDSA (256位) |
|---|---|---|
| 安全强度 | 112位等效 | 128位等效 |
| 公钥长度 | 256字节 | 32字节(压缩格式) |
| 签名长度 | 256字节 | 64字节 |
| 签名速度 | 慢(大数模幂) | 快(点乘运算) |
| 验签速度 | 快(小指数e) | 较快 |
| 硬件加速 | 需要大数乘法器 | 需要椭圆曲线点乘单元 |
| 抗量子攻击 | 脆弱 | 脆弱(但比RSA稍好) |
你想想看,在嵌入式场景里,签名长度和公钥长度往往比计算速度更关键。固件镜像每大1KB,OTA升级就要多传1KB,对于NB-IoT这种窄带网络,ECDSA的短签名优势非常明显。
3.4 选型建议:什么时候用哪个?
我个人习惯这样选:
- 现有生态兼容优先 → RSA:很多老旧的Bootloader和CA系统只支持RSA。如果你在维护一个已有产品线,别折腾,继续用RSA。
- 资源受限设备 → ECDSA:Cortex-M0/M3这类小芯片,RAM只有几十KB,ECDSA的短密钥和短签名能省下不少空间。我做过一个BLE门锁项目,用ECDSA P-256,签名验签都在50ms内完成。
- 安全启动场景 → 两者皆可:但要注意,安全启动的验签是在Bootloader里做的。Bootloader代码越精简越好,ECDSA的验签逻辑比RSA复杂一些,代码量也大一点。
- 需要抗量子预备 → 都不选:RSA和ECDSA在量子计算机面前都是纸老虎。如果产品生命周期超过10年,建议预留迁移到Lattice-based签名的接口。
💡 我的经验: 新项目我倾向于ECDSA P-384。虽然P-256已经够用,但P-384提供了192位的安全强度,而且对未来的量子攻击有稍强的抵抗力。代价是签名大了12字节,在嵌入式场景里完全可以接受。
3.5 知识图谱:数字签名全景
下面这张图帮你理清RSA签名和ECDSA签名的核心脉络:
3.6 实战避坑清单
最后,我把自己这些年踩过的坑整理成清单,你写代码时对照着检查:
- 随机数质量:ECDSA的k值必须用真随机数生成器(TRNG),别用伪随机。我曾经在一个项目里发现工程师用rand()生成k……后果不敢想。
- 侧信道攻击:RSA和ECDSA都容易受到时序攻击和功耗分析。实现时要用常数时间算法,别让执行时间泄露密钥信息。
- 证书链验证:别只验叶子证书,根证书和中间证书的合法性也要检查。我见过一个设备只验了固件签名,没验证书链,结果被中间人攻击了。
- 哈希算法绑定:签名前一定要先哈希。RSA直接签原文?那签名长度和原文一样长,而且不安全。ECDSA也一样,先SHA-256再签。
- 密钥存储:私钥必须放在安全元件(SE)或TEE里。裸放在Flash里?那和把密码贴在电脑屏幕上没区别。
一句话总结: RSA是成熟稳重的老将,ECDSA是灵活高效的新锐。选哪个取决于你的资源约束和安全需求。但无论选哪个,实现质量决定安全下限——算法再强,实现烂了也是白搭。