3、密码学基础(下):数字签名原理,RSA与ECDSA算法对比
好,咱们接着聊。上一节我们把哈希函数和对称加密讲透了,这一节轮到数字签名了。说白了,数字签名就是给固件盖个章,证明这东西确实是你写的,而且没人动过手脚。
我在做嵌入式安全那几年,见过太多因为签名没做好导致固件被篡改的案例。有的直接把私钥硬编码在代码里,有的签名算法选错了还在那沾沾自喜。嗯,今天咱们就把这事彻底捋清楚。
3.1 数字签名到底在解决什么问题?
你想想看,固件从开发到烧录,中间要经过多少人的手?编译服务器、测试环境、发布平台、OTA服务器……任何一个环节被渗透,固件都可能被替换成恶意版本。
数字签名要解决的就是两个核心问题:
- 身份认证:这个固件到底是谁签发的?
- 完整性校验:固件内容有没有被篡改过?
这两个问题,靠哈希函数只能解决一半——哈希能校验完整性,但没法证明是谁签的。数字签名把哈希和公钥密码结合起来,才真正把事办成了。
核心逻辑:私钥签名,公钥验签。私钥只有你一个人有,公钥可以公开给全世界。只要验签通过,就证明这个固件确实是用你的私钥签的,而且内容没变过。
3.2 数字签名的工作流程
我习惯把签名流程拆成三步,这样好记:
- 计算哈希:对固件二进制做一次哈希运算,得到固定长度的摘要。
- 签名:用私钥对哈希摘要进行加密,生成签名值。
- 打包:把固件原文 + 签名值 + 公钥证书(可选)一起发布出去。
验签流程反过来:
- 用公钥解密签名值,得到原始哈希摘要。
- 对收到的固件重新计算哈希。
- 两个哈希对比,一致则验签通过。
这里有个细节要注意——签名不是对整个固件加密,那太慢了。签名只对哈希摘要操作,效率高得多。
我的经验:实际项目中,签名值通常放在固件末尾,或者单独放在一个签名文件中。我见过有人把签名值放在固件头部,结果验签时把签名值自己也算了进去,导致永远验不过……这种坑,踩过一次就记住了。
3.3 RSA签名算法
RSA,全称Rivest-Shamir-Adleman,三个发明人的名字。这算法1983年就申请了专利,到现在还在广泛使用,生命力确实强。
RSA签名的核心原理基于大整数分解难题。给你两个大素数p和q,乘起来得到n很容易,但给你n让你分解出p和q,那就难了。私钥就是基于p和q生成的,公钥就是n加上一个指数e。
签名过程说白了就是:
签名值 = 哈希摘要 ^ d mod n (d是私钥指数)
验签过程:
哈希摘要 = 签名值 ^ e mod n (e是公钥指数)
看着简单吧?但实际工程里坑不少。
避坑指南:我曾经接手过一个项目,RSA签名用的密钥长度只有1024位。当时觉得够用了,结果没过两年就被学术界攻破了。现在行业标准是2048位起步,我建议直接上4096位。别嫌慢,安全第一。
3.4 ECDSA签名算法
ECDSA,全称Elliptic Curve Digital Signature Algorithm,基于椭圆曲线离散对数难题。说白了,就是椭圆曲线上点的加法运算,正向好算,逆向难求。
ECDSA的优势在哪?一个字——短。
同样安全强度下,ECDSA的密钥长度和签名长度都比RSA短得多。举个例子:
| 安全强度(位) | RSA密钥长度 | ECDSA密钥长度 | 签名长度 |
|---|---|---|---|
| 80 | 1024 | 160 | 320 |
| 112 | 2048 | 224 | 448 |
| 128 | 3072 | 256 | 512 |
| 192 | 7680 | 384 | 768 |
| 256 | 15360 | 521 | 1042 |
看到没?128位安全强度下,RSA要3072位密钥,ECDSA只要256位。这对嵌入式设备来说太重要了——存储空间、传输带宽、计算资源都省了一大截。
3.5 RSA vs ECDSA:实战对比
我在项目中两种算法都用过,说说我的真实感受:
| 对比维度 | RSA | ECDSA |
|---|---|---|
| 签名速度 | 较慢(私钥操作) | 较快 |
| 验签速度 | 较快(公钥操作) | 较慢 |
| 密钥长度 | 长(2048+位) | 短(256位) |
| 签名长度 | 等于密钥长度 | 约2倍密钥长度 |
| 硬件支持 | 广泛 | 逐渐普及 |
| 抗量子攻击 | 弱 | 弱(两者都弱) |
你可能会问,那到底选哪个?
我的建议是:
- 如果设备资源紧张(比如IoT传感器、蓝牙设备),选ECDSA。密钥短、签名短,省空间。
- 如果验签频率远高于签名频率(比如服务器验签),RSA的验签速度优势就体现出来了。
- 如果硬件已经集成了RSA加速器,别折腾,直接用RSA。
个人习惯:我现在做新项目,默认选ECDSA with P-256曲线。原因很简单——NIST推荐、硬件支持好、性能均衡。除非客户明确要求RSA,否则我不换。
3.6 签名算法在固件中的实际应用
说了这么多理论,咱们看看实际代码长什么样。下面是一个用Python做ECDSA签名的示例:
from ecdsa import SigningKey, NIST256p
import hashlib
# 生成私钥
sk = SigningKey.generate(curve=NIST256p)
# 导出公钥
vk = sk.verifying_key
# 固件数据
firmware = b"Hello, this is my firmware binary..."
# 签名
signature = sk.sign(firmware, hashfunc=hashlib.sha256)
# 验签
try:
vk.verify(signature, firmware, hashfunc=hashlib.sha256)
print("验签通过!固件未被篡改。")
except:
print("验签失败!固件可能被篡改。")
这段代码看着简单,但实际工程里要考虑的事多着呢:
- 密钥怎么安全存储?不能硬编码。
- 签名格式怎么定义?DER还是PEM?
- 验签失败后怎么处理?是拒绝启动还是降级运行?
这些细节,咱们后面的章节会一个一个拆解。
3.7 知识体系总览
为了让你对整个数字签名体系有个全局认识,我画了张图:
这张图把数字签名的核心要素都串起来了。你从上往下看,先理解数字签名要解决什么问题,再看两种主流算法怎么选,最后落到实际应用场景。
3.8 小结
数字签名是固件安全的第一道防线。RSA和ECDSA各有千秋,没有绝对的好坏。关键是根据你的设备资源、性能需求和硬件支持来选。
我个人更倾向ECDSA,尤其是做IoT设备的时候。但如果你在做服务器端的固件验签服务,RSA的验签速度优势确实明显。
嗯,这一节就到这。记住一句话:私钥藏好,公钥公开,签名验签,缺一不可。