密码学基础(上):对称加密与非对称加密、哈希算法、数字签名原理
各位好,我是老周。今天咱们聊点硬核的——密码学基础。别被「基础」两个字骗了,这部分要是没吃透,后面做固件签名联调,你连报错日志都看不懂。
我见过太多工程师,上来就调签名接口,结果验签老失败。一问,连 SHA256 和 RSA 是什么关系都说不清。嗯,这课咱们就从根上捋一遍。
对称加密:一把钥匙开一把锁
对称加密,说白了就是加密和解密用同一把密钥。你想想看,就像你家大门钥匙——用它锁门,也用它开门。
常见的对称加密算法有 AES、DES、3DES。现在工业界基本只用 AES,尤其是 AES-256。DES 太老了,别碰。
核心特点:
- 加解密速度快,适合大数据量
- 密钥分发是最大痛点——怎么安全地把密钥交给对方?
- 密钥数量爆炸:N 个人两两通信,需要 N*(N-1)/2 个密钥
我在一个 IoT 项目里遇到过,设备端用 AES-128 加密固件包,结果密钥硬编码在代码里。嗯,逆向工程师看了直呼内行。记住:对称加密的密钥管理,比算法本身难十倍。
非对称加密:公钥私钥,各司其职
非对称加密就优雅多了。它有一对密钥:公钥公开,私钥自己藏好。公钥加密的数据,只有私钥能解开;反过来,私钥签名的数据,公钥能验证。
这就解决了密钥分发问题——你只管把公钥扔到网上,谁都能用它加密数据发给你,只有你能解密。
| 特性 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1 个 | 2 个(公钥 + 私钥) |
| 速度 | 快(硬件加速可达 Gbps) | 慢(比对称慢 1000 倍以上) |
| 典型算法 | AES, ChaCha20 | RSA, ECDSA, Ed25519 |
| 主要用途 | 数据加密 | 密钥交换、数字签名 |
实际工程中,没人会用非对称加密直接加密大文件。太慢了。正确的做法是「混合加密」:用非对称加密交换对称密钥,再用对称密钥加密实际数据。TLS 就是这么干的。
哈希算法:数据的指纹
哈希算法,就是把任意长度的数据,映射成一个固定长度的摘要。这个摘要就像数据的「指纹」——内容变了,指纹一定变。
固件签名里最常用的就是 SHA256 和 SHA384。SHA256 输出 32 字节,SHA384 输出 48 字节。
我个人习惯:
固件完整性校验用 SHA256 就够了。但如果你的产品要过 FIPS 140-2 Level 2 认证,建议上 SHA384。别问我怎么知道的——有一次送测被打回来,就是因为用了 SHA1。
哈希算法的三个核心性质:
- 抗原像性:给定哈希值,无法反推出原始数据
- 抗第二原像性:给定一个数据,找不到另一个数据哈希值相同
- 抗碰撞性:找不到任意两个数据哈希值相同
SHA1 已经被攻破了碰撞性,Google 在 2017 年就演示了两个不同 PDF 文件有相同 SHA1 哈希。所以,SHA1 赶紧退役吧。
数字签名原理:签名 + 验签
数字签名,是哈希算法和非对称加密的完美结合。它解决三个问题:
- 完整性:固件有没有被篡改?
- 真实性:固件是不是来自声称的发布者?
- 不可否认性:发布者不能抵赖说「这不是我签的」
签名流程很简单:
- 对固件计算哈希值(比如 SHA256)
- 用私钥对哈希值加密,得到签名
- 把签名和固件一起发布
验签流程反过来:
- 接收方对固件计算同样的哈希值
- 用公钥解密签名,得到原始哈希值
- 两个哈希值对比——一致则验签通过
我曾经踩过的坑:
有一次联调,验签总失败。查了两天,发现是签名时用的哈希算法是 SHA256,但验签代码里写死了 SHA384。两边哈希值长度都不一样,怎么可能验过?所以,签名和验签的算法参数必须完全一致——哈希算法、填充方式、密钥长度,一个都不能错。
RSA vs ECDSA:怎么选?
RSA 和 ECDSA 是目前固件签名最主流的两种算法。
| 对比项 | RSA | ECDSA |
|---|---|---|
| 密钥长度 | 2048 / 4096 位 | 256 / 384 位 |
| 签名速度 | 慢 | 快 |
| 验签速度 | 快 | 慢 |
| 签名大小 | 256 / 512 字节 | 64 / 96 字节 |
| 安全性 | 成熟可靠 | 同等安全强度下密钥更短 |
我的建议:
- 如果 MCU 资源紧张(比如 Cortex-M0),选 ECDSA,签名小、省 Flash
- 如果兼容性优先,选 RSA-2048,几乎所有安全芯片都支持
- 如果追求极致性能,选 Ed25519(一种更现代的 ECDSA 变体)
你想想看,一个 256 位的 ECDSA 密钥,安全强度相当于 3072 位的 RSA。这就是椭圆曲线的魅力。
知识体系总览
下面这张图,把本章的核心逻辑串起来了。建议你保存下来,后面联调时对照着看。
从图上你能看明白:对称加密、非对称加密、哈希算法,这三者是数字签名的三大支柱。缺一个,签名体系就塌了。
实战中的几个关键点
最后,分享几个我在联调中反复踩过的坑:
- 密钥格式:PEM、DER、PKCS#8、PKCS#1……不同工具生成的密钥格式可能不一样。OpenSSL 默认输出 PEM,但某些安全芯片只认 DER。转换格式时记得检查头尾标识。
- 填充方式:RSA 签名常用 PKCS#1 v1.5 或 PSS。PSS 更安全,但老设备可能不支持。我建议新项目统一用 PSS。
- 随机数质量:ECDSA 签名需要高质量随机数。如果随机数生成器有问题,私钥可能被恢复。嗯,这事在 2010 年索尼 PS3 上真实发生过——他们用了固定随机数,结果私钥被破解。
- 哈希长度:SHA256 输出 32 字节,SHA384 输出 48 字节。签名时用的哈希长度,必须和验签时一致。别问我怎么知道的。
一个小技巧:
联调时,先用 OpenSSL 命令行把整个签名验签流程跑通,再集成到代码里。这样能快速定位问题是出在算法参数上,还是代码实现上。命令示例:
# 生成私钥
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
# 提取公钥
openssl pkey -in private.pem -pubout -out public.pem
# 签名
openssl dgst -sha256 -sign private.pem -out firmware.sig firmware.bin
# 验签
openssl dgst -sha256 -verify public.pem -signature firmware.sig firmware.bin
好了,密码学基础的上半部分就到这。这些概念你理解了,后面讲固件签名流程、证书链、安全启动,你就能跟上节奏了。记住:算法是工具,参数是细节,密钥管理是灵魂。三者缺一不可。