2、密码学基础回顾:对称加密与非对称加密、哈希函数特性、数字签名原理
各位同学好,我是老周。今天咱们聊点基础但绕不开的东西——密码学基础。你可能会说:“这些我早就会了。” 但说实话,我在固件安全这行干了十几年,见过太多因为基础不牢导致翻车的案例。所以咱们还是踏踏实实过一遍,尤其要搞清楚:这些东西跟固件签名验签到底有什么关系。
2.1 对称加密:快,但有个大麻烦
对称加密,说白了就是加密和解密用同一把钥匙。你拿钥匙锁门,拿同一把钥匙开门。典型算法有 AES、DES、SM4(国密)。
核心特点:
- 速度快:硬件加速后,AES-128 能做到每秒几十 GB 的吞吐量。适合加密固件本身。
- 密钥分发难:这是硬伤。你想想看,如果我要给一万台设备更新固件,怎么把密钥安全地送到每台设备里?
我在项目中遇到过:某次做 IoT 网关,工程师直接用硬编码的 AES 密钥加密固件。结果固件被提取后,密钥直接暴露在二进制里。嗯,那批设备后来全部召回重刷。教训就是:对称加密不适合做固件签名验签的根信任。
| 特性 | 对称加密 | 在固件保护中的角色 |
|---|---|---|
| 密钥管理 | 双方共享同一密钥 | 分发困难,易泄露 |
| 性能 | 极高(硬件加速) | 适合加密固件负载 |
| 典型算法 | AES-128/256, SM4 | 用于固件内容加密(非签名) |
| 抗量子 | 弱(Grover 算法减半安全强度) | 需关注后量子迁移 |
2.2 非对称加密:慢,但解决了信任问题
非对称加密,就是一对钥匙:公钥和私钥。公钥可以公开,私钥必须保密。你用私钥签名,别人用公钥验证。反过来,别人用公钥加密,只有你能用私钥解密。
为什么固件签名必须用非对称?
- 私钥只保存在厂商手里,设备里只放公钥。
- 公钥被提取了也没事——它只能验签,不能伪造签名。
- 这就是信任链的根。
我个人习惯:在固件签名流程中,先用哈希摘要固件,再用私钥加密摘要。这样既利用了非对称的安全性,又避免了直接加密大固件的性能开销。后面会细讲。
| 特性 | 非对称加密 | 在固件保护中的角色 |
|---|---|---|
| 密钥管理 | 公钥公开,私钥保密 | 公钥可嵌入设备,私钥离线保存 |
| 性能 | 慢(比对称慢 100-1000 倍) | 只签名摘要,不签名全文 |
| 典型算法 | RSA-2048/4096, ECDSA, SM2 | 固件签名/验签的核心 |
| 抗量子 | RSA/ECDSA 脆弱,SM2 同样脆弱 | 需关注 CRYSTALS-Dilithium 等 |
2.3 哈希函数:固件的“指纹”
哈希函数,就是把任意长度的数据,压缩成固定长度的摘要。比如 SHA-256 输出 256 位,SM3 输出 256 位。
哈希函数必须满足三个特性:
- 抗原像性:给定摘要,无法反推出原文。说白了就是不可逆。
- 抗第二原像性:给定原文和摘要,找不到另一个原文产生相同摘要。
- 抗碰撞性:找不到任意两个不同的原文,产生相同摘要。
我曾经踩过一个坑:某项目用了 MD5 做固件完整性校验。结果攻击者构造了两个不同的固件版本,MD5 摘要完全一样。设备升级了恶意固件,但校验通过了。从那以后,我规定所有项目最低用 SHA-256,国密场景用 SM3。
在固件签名中的角色:
- 对固件全文做哈希,得到摘要。
- 对摘要签名,而不是对固件全文签名。
- 验签时,重新计算固件哈希,再验证签名。
2.4 数字签名原理:签名与验签的完整流程
好了,前面三个概念都铺垫完了。现在咱们把它们串起来,看看数字签名到底怎么工作。
签名过程(厂商侧):
- 计算固件哈希:
digest = SHA256(firmware.bin) - 用私钥签名摘要:
signature = RSA_sign(private_key, digest) - 打包固件 + 签名 + 公钥证书:
firmware_package = firmware.bin || signature || cert
验签过程(设备侧):
- 解包得到固件、签名、公钥。
- 计算固件哈希:
digest' = SHA256(firmware.bin) - 用公钥验签:
result = RSA_verify(public_key, digest', signature) - 如果 result 为真,固件可信;否则拒绝升级。
核心逻辑:哈希保证了固件内容的完整性,非对称签名保证了固件来源的真实性。两者缺一不可。
// 伪代码示例:固件签名与验签
// 签名侧(厂商)
uint8_t firmware[FIRMWARE_SIZE];
uint8_t digest[32]; // SHA-256 输出
SHA256(firmware, sizeof(firmware), digest);
uint8_t signature[256]; // RSA-2048 签名
RSA_sign(private_key, digest, sizeof(digest), signature);
// 验签侧(设备)
uint8_t digest_prime[32];
SHA256(firmware, sizeof(firmware), digest_prime);
bool valid = RSA_verify(public_key, digest_prime, sizeof(digest_prime), signature);
if (valid) {
// 固件可信,执行升级
} else {
// 拒绝升级,记录日志
}
2.5 知识体系总览
下面这张图,把本章的核心逻辑串起来了。你可以看到:哈希函数、对称加密、非对称加密,各自在固件保护中扮演什么角色。
2.6 避坑指南:我见过的常见错误
做固件签名这么多年,有些坑真的是反复出现。我列几个最常见的,你以后遇到了能少走弯路。
- 直接用对称密钥签名:有人觉得 AES 快,就用 AES 加密当签名。但对称密钥没有非对称的“公钥可公开”特性,设备里存密钥等于把信任根暴露了。
- 哈希算法选太弱:MD5、SHA-1 已经可以被碰撞攻击。我见过某厂商用 SHA-1 签固件,结果被构造了碰撞固件,直接绕过验签。
- 签名摘要长度不足:RSA-1024 已经被认为不够安全。我个人建议最低 RSA-2048 或 ECDSA P-256,国密场景用 SM2。
- 公钥硬编码且不校验:设备里的公钥如果被替换,攻击者可以用自己的私钥签名恶意固件。所以公钥本身也要有保护机制(比如 OTP 或安全存储)。
我的建议:如果你刚开始做固件签名,直接选 ECDSA P-256 + SHA-256 组合。性能好,安全性够,生态成熟。国密场景用 SM2 + SM3。别自己造轮子,用现成的库(OpenSSL、mbedTLS、国产的 GmSSL)。
好了,这一章就到这里。密码学基础是固件保护的根基,后面所有章节都会用到这些概念。你把这些搞清楚了,后面的签名验签流程、证书链、安全启动,学起来会轻松很多。