3、密码学基础(上):对称加密(AES)、非对称加密(RSA/ECC)、哈希函数(SHA-256)在升级中的应用
做固件升级安全,说白了就是跟三件事打交道:加密、签名、校验。这三件事背后站着三大类密码学工具——对称加密、非对称加密、哈希函数。很多工程师觉得密码学是数学家的活儿,自己会用库就行。但我做了这么多年嵌入式安全,见过太多「会用库但用错」的翻车现场。
这一章,咱们就聊聊这三种工具在固件升级里的真实用法。不扯复杂的数学公式,只讲你写代码时真正需要知道的东西。
3.1 对称加密:AES 在固件加密传输中的应用
对称加密,就是加密和解密用同一把钥匙。你想想看,这像什么?像你家大门钥匙——你自己能开门,给室友配一把也能开。优点是快,特别快;缺点嘛,钥匙怎么安全地交给对方,是个大问题。
在固件升级场景里,AES 主要用来加密固件镜像本身。我习惯用 AES-256-GCM 模式,原因很简单:它不光加密,还能做完整性校验(GCM 模式自带认证标签)。
核心要点:固件升级中,AES 只负责「加密传输」,不负责「身份验证」。也就是说,它能防止别人偷看你的固件,但没法证明这个固件是谁发的。
AES 的几种工作模式,我该怎么选?
| 模式 | 特点 | 固件升级推荐度 |
|---|---|---|
| ECB | 简单,但相同明文块产生相同密文块,有模式泄露风险 | ❌ 不推荐 |
| CBC | 需要 IV,加密串行,解密可并行 | ⚠️ 可用,但需配合 HMAC |
| CTR | 可并行,无填充,但无认证 | ⚠️ 可用,但需配合 HMAC |
| GCM | CTR + GMAC 认证,一次完成加密和完整性校验 | ✅ 强烈推荐 |
我个人项目中几乎只用 GCM 模式。有一次,我在一个 IoT 设备上用了 CBC 模式,结果忘了加 HMAC,固件在传输过程中被篡改了一个字节,设备刷完直接变砖。嗯,从那以后,我再也不敢省掉认证这一步了。
实战建议:在资源受限的 MCU 上,AES-128 通常够用,而且比 AES-256 快 40% 左右。如果你的设备有硬件 AES 加速器,那用 AES-256 也没问题。
3.2 非对称加密:RSA 与 ECC 在签名验证中的对决
非对称加密,就是加密和解密用不同的钥匙——公钥和私钥。公钥可以公开,私钥自己藏好。这解决了对称加密「钥匙怎么安全传递」的难题。
在固件升级里,非对称加密主要干一件事:数字签名。服务器用私钥给固件签名,设备用公钥验证签名。只要私钥不泄露,谁也别想伪造固件。
RSA vs ECC:谁更适合嵌入式设备?
这个问题我经常被问到。直接说结论:ECC 在嵌入式里更有优势。
| 对比项 | RSA-2048 | ECC P-256 |
|---|---|---|
| 密钥长度 | 2048 位 | 256 位 |
| 签名长度 | 256 字节 | 64 字节 |
| 签名速度 | 较慢 | 快 |
| 验证速度 | 快 | 较快 |
| 安全等级 | 112 位 | 128 位 |
| 存储占用 | 大 | 小 |
你看,ECC P-256 在安全等级更高的情况下,密钥和签名都短得多。这对嵌入式设备来说太重要了——Flash 和 RAM 都是钱啊。
不过,RSA 也有它的优势:兼容性好。很多老旧的 Bootloader 只支持 RSA 验签。我遇到过一家客户,他们的设备用了 10 年的 RSA-1024,想升级到 ECC,结果 Bootloader 不支持,只能整个换芯片。所以,选什么算法,还得看你现有的硬件和软件生态。
避坑指南:我曾经在一个项目里用了 ECC 签名,但没注意设备上的随机数生成器质量太差,导致每次签名验证都失败。后来发现是 ECC 签名算法需要高质量的随机数来做「nonce」。如果你的设备没有硬件 TRNG,建议用确定性 ECDSA(RFC 6979),避免随机数问题。
3.3 哈希函数:SHA-256 如何保证固件完整性
哈希函数,就是把任意长度的数据,压缩成一个固定长度的「指纹」。这个指纹有个特点:原文改一个比特,指纹就完全变了。而且,从指纹反推原文,理论上不可能。
在固件升级里,哈希函数主要用在两个地方:
- 固件完整性校验:下载完固件后,算一下哈希值,跟官方公布的对比,就知道固件有没有被篡改。
- 数字签名的一部分:先对固件算哈希,再对哈希值签名。这样签名速度快,而且签名长度固定。
SHA-256 是目前最主流的选择。它输出 256 位(32 字节)的哈希值,碰撞概率极低,安全性足够。
一个常见的误解:很多人以为哈希函数能「加密」数据。不对,哈希是单向的,不可逆的。它只能用来验证数据有没有被改过,不能用来隐藏数据内容。
哈希在固件升级中的典型流程
// 伪代码:固件完整性校验流程
uint8_t firmware_hash[32];
sha256_calculate(firmware_data, firmware_size, firmware_hash);
// 从安全存储中读取官方哈希值
uint8_t expected_hash[32];
read_from_secure_storage(expected_hash);
// 比较
if (memcmp(firmware_hash, expected_hash, 32) == 0) {
// 固件完整,可以刷写
start_firmware_update();
} else {
// 固件被篡改,拒绝升级
report_error("Firmware integrity check failed");
}
这段代码看起来简单,但实际项目中坑不少。比如,memcmp 是时间不安全的——攻击者可以根据比较时间推断出哈希值。我建议用 timing_safe_memcmp 或者自己实现一个恒定时间的比较函数。
3.4 三种密码学工具如何协同工作?
单独看每种工具,功能都很明确。但在实际固件升级系统里,它们是配合使用的。下面这张图展示了典型的协同流程:
这个流程看起来步骤多,但每个环节都有它的意义。你想想看,如果只用 AES 加密,攻击者虽然看不到固件内容,但可以篡改密文,设备解密后刷入损坏的固件,照样变砖。如果只用签名,固件内容在传输过程中是明文,任何人都能拿到你的知识产权。
所以,加密 + 签名 + 哈希,三者配合,才能构建一个完整的固件升级安全体系。
我的个人习惯:在资源允许的情况下,我会把公钥直接编译进 Bootloader 的只读区域,并在芯片出厂前锁定。这样即使攻击者拿到了 Flash 镜像,也无法替换公钥。另外,AES 的密钥我通常用 ECDH 密钥交换来协商,而不是写死在固件里——写死密钥的做法,我见过太多翻车的案例了。
3.5 小结:选型决策树
最后,给你一个简单的选型决策思路:
- 你的 MCU 有硬件加密引擎吗? 有 → 优先用 AES-256-GCM + ECC P-256。没有 → 考虑 AES-128-GCM + RSA-2048(RSA 验签可以纯软件实现,速度还行)。
- 你的固件大小超过 1MB 吗? 是 → 建议分块计算哈希,避免一次性加载到 RAM。否 → 一次性计算即可。
- 你的设备需要支持远程升级吗? 是 → 必须用非对称签名,因为对称密钥无法安全分发。否 → 可以用预共享密钥的 HMAC 做完整性校验,更简单。
密码学基础这部分,咱们先聊到这儿。记住一句话:密码学工具本身没有错,错的是用错场景的人。选对工具,用对模式,你的固件升级就能安全一大半。