密码学基础回顾:哈希、非对称加密与数字签名
各位同学,咱们今天聊点实在的。做固件安全启动,说白了就是跟密码学打交道。你不需要成为密码学专家,但得把几个核心概念吃透。我刚开始接触这块时,也踩过不少坑,今天就把这些经验掰开揉碎了讲给你听。
2.1 哈希算法:数据的“指纹”
哈希算法,你可以把它想象成给数据盖个章。不管你的固件是1KB还是1GB,经过哈希运算后,都会得到一个固定长度的摘要。这个摘要就像人的指纹,独一无二。
我个人习惯用SHA256,它输出256位(32字节)的哈希值。为什么选它?因为碰撞概率极低——你想找到两个不同的固件,却算出相同的SHA256值,理论上几乎不可能。
核心特性:
- 单向性:从哈希值无法反推出原始数据。你想想看,如果固件被篡改,哈希值一定会变。
- 抗碰撞性:很难找到两个不同输入,产生相同输出。
- 雪崩效应:输入改一个比特,输出就面目全非。
我在项目中遇到过一件事:有个同事把固件哈希值打印在日志里,用于校验。结果发现每次烧录后哈希值都不一样。排查了半天,原来是固件里嵌了个时间戳。嗯,这里要注意——哈希的对象必须完全一致,否则校验就是白搭。
// 计算固件哈希的示例(伪代码)
uint8_t firmware_hash[32];
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, firmware_data, firmware_size);
sha256_final(&ctx, firmware_hash);
// 打印哈希值
for (int i = 0; i < 32; i++) {
printf("%02x", firmware_hash[i]);
}
避坑指南:我曾经在项目里直接用MD5做固件校验,结果被安全审计打回来了。现在SHA256是底线,千万别图省事用MD5或SHA1。
2.2 非对称加密:公钥与私钥
非对称加密,说白了就是两把钥匙:一把公开(公钥),一把私藏(私钥)。公钥加密的数据,只有私钥能解开;反过来,私钥签名的数据,公钥能验证。
常用的算法有两种:RSA和ECC。我做个对比,你一看就明白:
| 特性 | RSA | ECC(椭圆曲线) |
|---|---|---|
| 密钥长度 | 2048位起步 | 256位即可 |
| 计算速度 | 签名慢,验签快 | 签名快,验签也快 |
| 资源消耗 | 较高 | 较低 |
| 典型应用 | 传统固件签名 | IoT设备、资源受限场景 |
我个人更倾向于ECC,尤其是在嵌入式设备上。为什么?因为256位的ECC,安全强度相当于3072位的RSA。你想想看,固件空间就那么点,省下来的字节可以放更多功能代码。
注意:RSA的密钥长度不能低于2048位,否则有被破解的风险。我见过有人用1024位RSA做产品,结果被安全团队直接打回重做。
2.3 数字签名:证明“你是谁”
数字签名,就是给固件加上一个“防伪标签”。它解决了三个问题:
- 完整性:固件有没有被改过?
- 真实性:这个固件是不是你声称的那个人签的?
- 不可否认性:签名者不能抵赖说“我没签过”。
流程其实很简单:
- 对固件做SHA256哈希,得到摘要。
- 用私钥对摘要加密,生成签名。
- 把签名附加到固件上。
- 验签时,用公钥解密签名,得到原始摘要。
- 重新计算固件哈希,比对两个摘要。
如果一致,说明固件没被篡改,且确实是私钥持有者签的。
核心逻辑:签名 ≠ 加密。签名用的是私钥,验证用的是公钥。加密正好反过来。
我曾经在调试安全启动时,发现签名总是验证失败。查了半天,原来是签名时用的哈希算法和验签时不一致——一个用SHA256,一个用SHA384。这种低级错误,排查起来最费时间。
2.4 知识体系总览
下面这张图,把今天讲的核心逻辑串起来了。你仔细看看,就能明白哈希、非对称加密、数字签名是怎么配合的。
2.5 实际项目中的选择建议
做固件签名时,算法选型很关键。我根据经验,给你几个参考:
| 场景 | 推荐算法 | 理由 |
|---|---|---|
| 高性能MCU(如Cortex-A系列) | RSA-2048 + SHA256 | 验签速度快,生态成熟 |
| 资源受限MCU(如Cortex-M0) | ECC-256 + SHA256 | 密钥短,省空间,计算快 |
| 安全等级要求极高 | RSA-4096 或 ECC-384 | 抗量子计算攻击(远期) |
我的习惯:先在PC上用OpenSSL生成密钥对,然后把公钥硬编码到Bootloader里。私钥放在离线机器上,签名时才拿出来。这样即使固件泄露,攻击者也拿不到私钥。