密码学基础(上):对称加密与非对称加密、哈希算法、数字签名原理

各位好,我是老周。今天咱们聊点硬核的——密码学基础。别被「基础」两个字骗了,这部分要是没吃透,后面做固件签名联调,你连报错日志都看不懂。

我见过太多工程师,上来就调签名接口,结果验签老失败。一问,连 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。

哈希算法的三个核心性质:

  1. 抗原像性:给定哈希值,无法反推出原始数据
  2. 抗第二原像性:给定一个数据,找不到另一个数据哈希值相同
  3. 抗碰撞性:找不到任意两个数据哈希值相同

SHA1 已经被攻破了碰撞性,Google 在 2017 年就演示了两个不同 PDF 文件有相同 SHA1 哈希。所以,SHA1 赶紧退役吧。

数字签名原理:签名 + 验签

数字签名,是哈希算法和非对称加密的完美结合。它解决三个问题:

  • 完整性:固件有没有被篡改?
  • 真实性:固件是不是来自声称的发布者?
  • 不可否认性:发布者不能抵赖说「这不是我签的」

签名流程很简单:

  1. 对固件计算哈希值(比如 SHA256)
  2. 用私钥对哈希值加密,得到签名
  3. 把签名和固件一起发布

验签流程反过来:

  1. 接收方对固件计算同样的哈希值
  2. 用公钥解密签名,得到原始哈希值
  3. 两个哈希值对比——一致则验签通过

我曾经踩过的坑:

有一次联调,验签总失败。查了两天,发现是签名时用的哈希算法是 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。这就是椭圆曲线的魅力。

知识体系总览

下面这张图,把本章的核心逻辑串起来了。建议你保存下来,后面联调时对照着看。

固件签名密码学知识体系 对称加密 AES / ChaCha20 非对称加密 RSA / ECDSA 哈希算法 SHA256 / SHA384 数字签名 完整性 + 真实性 + 不可否认性 签名方 固件 → SHA256 → 私钥加密 → 签名 验签方 固件 → SHA256 → 公钥解密 → 对比 ⚠ 关键约束 签名与验签的哈希算法、填充方式、密钥长度必须完全一致

从图上你能看明白:对称加密、非对称加密、哈希算法,这三者是数字签名的三大支柱。缺一个,签名体系就塌了。

实战中的几个关键点

最后,分享几个我在联调中反复踩过的坑:

  • 密钥格式: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

好了,密码学基础的上半部分就到这。这些概念你理解了,后面讲固件签名流程、证书链、安全启动,你就能跟上节奏了。记住:算法是工具,参数是细节,密钥管理是灵魂。三者缺一不可。