密码学基础(上):对称加密、非对称加密与哈希函数

说实话,很多做IoT的朋友一开始都栽在密码学上。觉得这东西太数学、太抽象。我当年刚入行时也这么想。直到有一次,我负责的一个智能门锁项目,因为用了不合适的加密算法,被安全团队直接打回重做。从那以后,我就明白了——密码学不是选修课,是保命课。

这一章,咱们就聊聊安全启动里最核心的三个密码学工具:AES、RSA/ECC 和 SHA-256。你不需要成为数学家,但得知道它们各自干什么、怎么配合。

安全启动密码学体系 对称加密 (AES) 加密固件镜像 解密运行时数据 非对称加密 (RSA/ECC) 签名固件 分发对称密钥 哈希函数 (SHA-256) 完整性校验 防篡改验证 安全启动流程:哈希校验 → 签名验证 → 解密执行 BootROM 验证签名 解密并执行 三种密码学工具协同工作,缺一不可

1. 对称加密:AES

对称加密,说白了就是加密和解密用同一把钥匙。你想想看,就像你用一把锁锁上箱子,再用同一把钥匙打开。简单直接,速度快。

AES(Advanced Encryption Standard) 是目前最主流的对称加密算法。我做过一个项目,需要在资源受限的MCU上做固件加密,AES-128是首选。为什么?因为它硬件加速支持好,很多芯片都内置了AES引擎。

AES 核心参数:

  • 密钥长度:128位、192位、256位。安全启动里常用AES-128,平衡安全与性能。
  • 分组大小:固定128位(16字节)。
  • 工作模式:ECB、CBC、CTR、GCM等。我个人建议用GCM模式,自带认证,能防篡改。

在安全启动里,AES主要干两件事:

  1. 加密固件镜像:防止别人直接读出Flash里的固件。
  2. 解密运行时数据:有些敏感数据在内存里也是加密的。

我曾经踩过一个坑:用ECB模式加密固件。结果呢?同样的明文块会生成同样的密文块,攻击者能看出固件的结构。后来我全改成CBC模式了,每次加密都加随机IV,安全多了。

// AES-128 CBC 加密示例(伪代码)
uint8_t key[16] = {0x2b, 0x7e, 0x15, 0x16, ...};
uint8_t iv[16]  = {0x00, 0x01, 0x02, 0x03, ...};  // 随机生成

aes_cbc_encrypt(firmware_data, firmware_len, key, iv, encrypted_data);

小提示:密钥不要硬编码在代码里。我习惯把密钥存储在芯片的OTP(一次性可编程)区域或安全元件中。这样即使固件被反编译,密钥也拿不到。

2. 非对称加密:RSA 与 ECC

非对称加密就更有意思了。它有两把钥匙:公钥和私钥。公钥可以公开,私钥自己藏着。用私钥签名,用公钥验证。这正好解决了对称加密里密钥分发的难题。

RSA 是老牌选手,基于大整数分解的数学难题。我刚开始做安全启动时,用的就是RSA-2048。优点是成熟、支持广泛。缺点是密钥长、计算慢,尤其是在低端MCU上。

ECC(椭圆曲线密码学) 是后起之秀。同样的安全强度,ECC的密钥长度只有RSA的十分之一。比如,ECC-256的安全性和RSA-3072差不多,但密钥短得多,计算也快。

特性 RSA-2048 ECC-256
密钥长度 2048位 256位
签名速度 慢 快
验证速度 快 较快
硬件资源 高 低
IoT适用性 适合网关/服务器 适合终端设备

在安全启动里,非对称加密的核心角色是签名验证。流程是这样的:

  1. 固件发布前,用私钥对固件的哈希值签名。
  2. 设备启动时,用公钥验证这个签名。
  3. 验证通过,说明固件是官方发布的,没被篡改。

注意:公钥必须安全地存储在设备里。我见过一个项目,公钥放在Flash的固定地址,结果攻击者直接改写了公钥,用自己的私钥签了个恶意固件。正确的做法是把公钥烧录到一次性可编程(OTP)区域,或者用芯片的硬件信任根保护。

3. 哈希函数:SHA-256

哈希函数是个神奇的东西。它能把任意长度的数据,压缩成一个固定长度的摘要。而且,哪怕你只改了一个比特,摘要都会完全不一样。这就是所谓的雪崩效应。

SHA-256 是SHA-2家族的一员,输出256位(32字节)的哈希值。在安全启动里,它主要用来做完整性校验。

举个例子:

输入: "Hello, IoT!"
SHA-256: 8f7d3b7e5c6a4f1d2e3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f

输入: "Hello, IoT?"  (只改了一个字符)
SHA-256: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2

看到了吗?两个哈希值完全不同。这就是哈希函数的威力。

在安全启动流程中,SHA-256通常和签名配合使用:

  • 先对固件计算SHA-256哈希值。
  • 然后用私钥对这个哈希值签名。
  • 验证时,重新计算固件的哈希值,再用公钥验证签名。

这样做的好处是:签名只需要对32字节的哈希值操作,而不是对整个固件。效率高很多。

安全启动中的典型流程:

  1. BootROM读取固件头部,获取签名和哈希值。
  2. 计算固件实际哈希值,与头部哈希值比对。
  3. 用公钥验证签名是否匹配哈希值。
  4. 全部通过,才允许执行固件。

我曾经调试过一个启动失败的问题。折腾了两天,最后发现是哈希值计算时,把固件末尾的填充字节也算进去了。而签名时没算。嗯,这种细节问题最容易出bug。

4. 三种算法如何协同工作

你可能会问:为什么安全启动需要三种算法?不能只用一种吗?

我跟你分析一下:

  • 只用对称加密:密钥怎么安全地分发给每个设备?总不能把密钥写在固件里吧。
  • 只用非对称加密:签名验证没问题,但固件本身是明文存储的,攻击者可以读出来分析漏洞。
  • 只用哈希:只能检测篡改,不能防止篡改。攻击者改了固件,重新算个哈希值贴上就行了。

所以,实际的安全启动方案是组合拳:

  1. SHA-256 计算固件哈希,保证完整性。
  2. RSA/ECC 对哈希值签名,保证固件来源可信。
  3. AES 加密固件,保证机密性,防止逆向分析。

我的经验:在资源受限的IoT设备上,我通常用ECC做签名验证,AES-128做固件加密。ECC的密钥短,签名验证快;AES-128有硬件加速,加解密效率高。SHA-256基本所有芯片都支持,不用白不用。

好了,这一章的内容就到这儿。密码学基础是安全启动的基石,理解了AES、RSA/ECC和SHA-256的原理和角色,后面的内容你就更容易上手了。