密码学基础回顾:哈希算法、非对称加密与数字签名
各位同学,咱们今天聊点硬核的。做可信启动和镜像验证,密码学是躲不开的基石。我刚开始接触这块时,也觉得数学公式太多,头大。但后来发现,真正干活时,你只需要理解三个核心工具:哈希算法、非对称加密和数字签名。说白了,它们就是嵌入式安全世界的「三把锁」。
这一章,我会用实战的视角,带你把这三把锁的原理、用法和坑都过一遍。嗯,咱们开始吧。
2.1 哈希算法:数据的「指纹」
哈希算法,也叫散列函数。它的作用很简单:把任意长度的数据,压缩成固定长度的摘要。这个摘要,就是数据的「指纹」。
我个人习惯把哈希算法比作「碎纸机」——你扔进去一份合同,出来一堆纸屑(摘要)。但注意,这堆纸屑是无法还原成原合同的。这就是哈希的单向性。
2.1.1 SHA-256 是怎么工作的?
SHA-256 是 SHA-2 家族的一员,输出 256 位(32 字节)的摘要。它在嵌入式领域用得最多,为什么?因为安全强度够,计算速度也还行。
它的核心流程分三步:
- 填充:把消息补到 512 位的整数倍。
- 分块:每 512 位一块,共 N 块。
- 压缩:每块经过 64 轮迭代,最终输出 256 位。
你想想看,哪怕输入只差一个比特,输出的摘要也会天差地别。这就是雪崩效应。
关键特性:
- 单向性:从摘要反推原始数据,计算上不可行。
- 抗碰撞性:找到两个不同输入,产生相同摘要,几乎不可能。
- 固定输出:无论输入多大,输出都是 32 字节。
我的经验: 在嵌入式设备上做镜像校验时,SHA-256 是首选。我曾经在一个项目里试过 MD5,结果被客户的安全审计直接打回。从那以后,我所有新设计都只用 SHA-256 或更高。
2.1.2 哈希在可信启动中的角色
在可信启动里,哈希用来做两件事:
- 度量:计算每个启动阶段的镜像哈希值。
- 校验:把计算出的哈希和「预期值」对比,看是否被篡改。
举个例子,你烧录固件时,会预先存一个「黄金哈希值」。启动时,BootROM 计算 Flash 中第一级 Bootloader 的 SHA-256,如果匹配,才继续执行。不匹配?直接死循环或报警。
// 伪代码:计算一段内存的 SHA-256
uint8_t hash[32];
sha256_calculate((uint8_t*)bootloader_addr, bootloader_size, hash);
// 与预存黄金哈希比较
if (memcmp(hash, golden_hash, 32) == 0) {
// 信任,跳转执行
jump_to(bootloader_addr);
} else {
// 篡改,进入安全模式
enter_safe_mode();
}
2.2 非对称加密:公钥与私钥的「双人舞」
非对称加密,也叫公钥密码学。它用一对密钥:公钥(公开)和私钥(保密)。
你想想看,对称加密就像一把钥匙开一把锁,双方得提前商量好密码。但在嵌入式场景里,设备成千上万,你怎么安全地把密钥分发出去?非对称加密解决了这个问题:公钥随便给,私钥自己藏好。
2.2.1 RSA 与 ECC 的对比
目前主流的是 RSA 和 ECC(椭圆曲线密码学)。我直接给你一张对比表,一目了然:
| 特性 | RSA | ECC |
|---|---|---|
| 安全强度 | 2048 位 ≈ 112 位对称 | 256 位 ≈ 128 位对称 |
| 密钥长度 | 2048 位(256 字节) | 256 位(32 字节) |
| 签名速度 | 慢(私钥操作) | 快(私钥操作) |
| 验签速度 | 快(公钥操作) | 慢(公钥操作) |
| 资源消耗 | 高(大数运算) | 低(椭圆曲线运算) |
| 典型应用 | 传统 PKI、代码签名 | IoT 设备、资源受限系统 |
避坑指南: 我曾经在一个低功耗 MCU 项目里选了 RSA-2048 做签名验签,结果发现一次验签要 2 秒,功耗直接超标。后来换成 ECC-256,验签时间降到 200 毫秒。所以,资源受限的设备,优先考虑 ECC。
2.2.2 公钥分发与信任根
在可信启动里,公钥怎么安全地放到设备上?答案是:在芯片制造时,把公钥哈希烧进一次性可编程(OTP)存储器里。这就是硬件信任根。
我习惯的做法是:
- 在安全环境中生成密钥对。
- 把公钥的 SHA-256 哈希烧进芯片 OTP。
- 固件签名时,带上完整的公钥。
- 设备启动时,先验证公钥哈希是否匹配 OTP 中的值。
- 再用公钥验签。
这样,即使攻击者替换了固件中的公钥,哈希校验也会失败。
2.3 数字签名:防篡改与防抵赖的「电子印章」
数字签名,说白了就是用私钥对数据的哈希值加密。它保证了三件事:
- 完整性:数据没被改过。
- 真实性:数据确实来自声称的签名者。
- 不可抵赖性:签名者事后不能否认。
2.3.1 签名与验签流程
我画个流程图,你一看就明白:
流程其实就五步:
- 签名方对镜像做 SHA-256,得到哈希 H。
- 用私钥对 H 加密,生成签名 S。
- 把镜像和签名一起发给设备。
- 设备用公钥解密 S,得到 H1。
- 设备本地计算镜像哈希 H2,对比 H1 和 H2。
如果相等,镜像就是可信的。否则,直接拒绝启动。
2.3.2 签名算法选型建议
在实际项目中,我一般这样选:
- 高性能 SoC(如 ARM Cortex-A 系列):RSA-2048 或 RSA-4096,验签快,兼容性好。
- 资源受限 MCU(如 Cortex-M 系列):ECC-256(NIST P-256),密钥短,签名快。
- 极端低功耗设备:Ed25519(基于 Curve25519),性能更优,但需要硬件加速。
我的习惯: 新项目我基本都上 ECC 了。RSA 虽然成熟,但密钥太长,在嵌入式里传输和存储都是负担。而且,NIST 已经在推动向 ECC 迁移了。
2.4 本章小结
好了,咱们把密码学三件套过了一遍:
- SHA-256:给数据打指纹,保证完整性。
- RSA / ECC:公钥私钥配对,解决密钥分发问题。
- 数字签名:哈希 + 非对称加密,保证真实性和防篡改。
这些概念,在后续的可信启动链、镜像验签、安全固件更新中,会反复出现。你先把它们刻在脑子里,后面咱们动手写代码时,就不会慌了。
最后提醒一句: 密码学算法本身是安全的,但实现方式可能全是漏洞。我曾经见过一个产品,签名验签都做了,但公钥竟然存在可读写的 Flash 里——攻击者直接替换公钥,整个安全体系就崩了。所以,信任根必须硬件保护,密钥管理才是真正的护城河。