2. 安全基础

各位同学,咱们今天聊点硬核的。做可信启动和镜像验证,密码学是躲不开的基石。我刚开始接触这块时,也觉得数学公式太多,头大。但后来发现,真正干活时,你只需要理解三个核心工具:哈希算法、非对称加密和数字签名。说白了,它们就是嵌入式安全世界的「三把锁」。

这一章,我会用实战的视角,带你把这三把锁的原理、用法和坑都过一遍。嗯,咱们开始吧。

2.1 哈希算法:数据的「指纹」

哈希算法,也叫散列函数。它的作用很简单:把任意长度的数据,压缩成固定长度的摘要。这个摘要,就是数据的「指纹」。

我个人习惯把哈希算法比作「碎纸机」——你扔进去一份合同,出来一堆纸屑(摘要)。但注意,这堆纸屑是无法还原成原合同的。这就是哈希的单向性。

2.1.1 SHA-256 是怎么工作的?

SHA-256 是 SHA-2 家族的一员,输出 256 位(32 字节)的摘要。它在嵌入式领域用得最多,为什么?因为安全强度够,计算速度也还行。

它的核心流程分三步:

  1. 填充:把消息补到 512 位的整数倍。
  2. 分块:每 512 位一块,共 N 块。
  3. 压缩:每块经过 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)存储器里。这就是硬件信任根。

我习惯的做法是:

  1. 在安全环境中生成密钥对。
  2. 把公钥的 SHA-256 哈希烧进芯片 OTP。
  3. 固件签名时,带上完整的公钥。
  4. 设备启动时,先验证公钥哈希是否匹配 OTP 中的值。
  5. 再用公钥验签。

这样,即使攻击者替换了固件中的公钥,哈希校验也会失败。

2.3 数字签名:防篡改与防抵赖的「电子印章」

数字签名,说白了就是用私钥对数据的哈希值加密。它保证了三件事:

  • 完整性:数据没被改过。
  • 真实性:数据确实来自声称的签名者。
  • 不可抵赖性:签名者事后不能否认。

2.3.1 签名与验签流程

我画个流程图,你一看就明白:

数字签名与验签流程 签名方(私钥) 原始镜像数据 SHA-256 哈希 私钥加密(签名) 数字签名 验签方(公钥) 公钥解密签名 得到哈希值 H1 本地计算哈希 H2 (SHA-256) H1 == H2 ? 通过 : 拒绝 签名方:私钥签名 验签方:公钥验签

流程其实就五步:

  1. 签名方对镜像做 SHA-256,得到哈希 H。
  2. 用私钥对 H 加密,生成签名 S。
  3. 把镜像和签名一起发给设备。
  4. 设备用公钥解密 S,得到 H1。
  5. 设备本地计算镜像哈希 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 里——攻击者直接替换公钥,整个安全体系就崩了。所以,信任根必须硬件保护,密钥管理才是真正的护城河。