密码学基础回顾:哈希、非对称加密与数字签名

各位同学,咱们今天聊点实在的。做固件安全启动,说白了就是跟密码学打交道。你不需要成为密码学专家,但得把几个核心概念吃透。我刚开始接触这块时,也踩过不少坑,今天就把这些经验掰开揉碎了讲给你听。

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 数字签名:证明“你是谁”

数字签名,就是给固件加上一个“防伪标签”。它解决了三个问题:

  • 完整性:固件有没有被改过?
  • 真实性:这个固件是不是你声称的那个人签的?
  • 不可否认性:签名者不能抵赖说“我没签过”。

流程其实很简单:

  1. 对固件做SHA256哈希,得到摘要。
  2. 用私钥对摘要加密,生成签名。
  3. 把签名附加到固件上。
  4. 验签时,用公钥解密签名,得到原始摘要。
  5. 重新计算固件哈希,比对两个摘要。

如果一致,说明固件没被篡改,且确实是私钥持有者签的。

核心逻辑:签名 ≠ 加密。签名用的是私钥,验证用的是公钥。加密正好反过来。

我曾经在调试安全启动时,发现签名总是验证失败。查了半天,原来是签名时用的哈希算法和验签时不一致——一个用SHA256,一个用SHA384。这种低级错误,排查起来最费时间。

2.4 知识体系总览

下面这张图,把今天讲的核心逻辑串起来了。你仔细看看,就能明白哈希、非对称加密、数字签名是怎么配合的。

数字签名与验证流程 固件数据 SHA256哈希 私钥加密 生成签名 固件 + 签名 固件数据 SHA256哈希 公钥解密 比对哈希 关键点: 1. 发送方用私钥签名,接收方用公钥验签。 2. 哈希保证完整性,签名保证真实性。 3. 公钥是公开的,私钥必须保密。 4. 签名验证失败,固件必须被拒绝加载。

2.5 实际项目中的选择建议

做固件签名时,算法选型很关键。我根据经验,给你几个参考:

场景 推荐算法 理由
高性能MCU(如Cortex-A系列) RSA-2048 + SHA256 验签速度快,生态成熟
资源受限MCU(如Cortex-M0) ECC-256 + SHA256 密钥短,省空间,计算快
安全等级要求极高 RSA-4096 或 ECC-384 抗量子计算攻击(远期)

我的习惯:先在PC上用OpenSSL生成密钥对,然后把公钥硬编码到Bootloader里。私钥放在离线机器上,签名时才拿出来。这样即使固件泄露,攻击者也拿不到私钥。