密码学基础(上):对称加密、非对称加密、哈希函数在固件更新中的应用
各位同学,咱们今天聊聊固件更新里最核心的东西——密码学。说实话,我刚开始做嵌入式安全那会儿,觉得密码学就是一堆数学公式,离实际工程很远。直到有一次,我负责的一个IoT设备因为固件签名没做好,被黑客注入了恶意固件,整批产品差点召回。从那以后,我再也不敢小看这些基础算法了。
这一章,咱们就聚焦三个最常用的工具:AES(对称加密)、RSA/ECC(非对称加密)、SHA-256(哈希函数)。它们在固件更新里各司其职,缺一不可。
1. 对称加密:AES在固件加密传输中的应用
对称加密,说白了就是加密和解密用同一把钥匙。你想想看,就像你家门锁,用一把钥匙锁上,也用同一把钥匙打开。在固件更新场景里,我们经常用AES来加密固件镜像,防止传输过程中被窃听或篡改。
我个人习惯用AES-128-GCM模式。为什么选GCM?因为它不光加密,还能做完整性校验。我在项目中遇到过,有人只用了AES-CBC模式,结果固件被篡改了都不知道——因为CBC模式不提供认证。嗯,这里要注意,GCM模式会额外生成一个认证标签(tag),你解密的时候必须验证这个tag,否则等于没防篡改。
来看一个典型的固件加密流程:
// 伪代码:固件加密
uint8_t key[16] = {0x2b, 0x7e, 0x15, 0x16, ...}; // 128位密钥
uint8_t iv[12] = {0x00, 0x01, 0x02, ...}; // 12字节随机数
uint8_t firmware[] = {...}; // 原始固件
uint8_t ciphertext[sizeof(firmware)];
uint8_t tag[16];
aes_gcm_encrypt(key, iv, firmware, ciphertext, tag);
// 将 ciphertext + iv + tag 打包发送给设备
设备端收到后,先解密,再验证tag。如果tag不匹配,直接拒绝更新。我曾经见过一个产品,解密后没验证tag,结果攻击者把固件里的某个字节改了,设备照样跑起来——后果很严重。
2. 非对称加密:RSA/ECC在固件签名验证中的应用
对称加密有个硬伤——密钥分发。你想想,如果我把AES密钥也通过同样的网络发给设备,那攻击者截获了怎么办?所以,固件更新里真正用来做身份认证的,是非对称加密。
非对称加密,就是一对钥匙:公钥和私钥。私钥你藏好,公钥公开。我用私钥给固件签名,设备用公钥验证签名。这样,就算公钥被攻击者拿到,他也伪造不了签名。
我个人更倾向于ECC(椭圆曲线密码学),而不是RSA。为什么?ECC在同等安全强度下,密钥更短、计算更快。比如,256位的ECC相当于3072位的RSA。在嵌入式设备上,这点性能差异非常明显。我记得有一次,在一个只有几十KB RAM的MCU上跑RSA-2048签名验证,耗时超过2秒,换成ECC-256后,降到200毫秒以内。
固件签名验证的典型流程:
// 签名端(服务器)
uint8_t private_key[] = {...}; // 私钥
uint8_t firmware_hash[32]; // 固件的SHA-256哈希
sha256(firmware, firmware_hash);
ecdsa_sign(private_key, firmware_hash, signature);
// 验证端(设备)
uint8_t public_key[] = {...}; // 公钥(烧录在设备中)
uint8_t firmware_hash[32];
sha256(received_firmware, firmware_hash);
if (ecdsa_verify(public_key, firmware_hash, signature) == SUCCESS) {
// 签名验证通过,可以更新
} else {
// 签名无效,拒绝更新
}
3. 哈希函数:SHA-256在固件完整性校验中的应用
哈希函数,说白了就是给数据算一个「指纹」。不管你的固件有多大,SHA-256都能算出一个256位的固定长度哈希值。只要固件里有一个比特变了,哈希值就会完全不一样。
在固件更新里,SHA-256有三个典型用途:
- 完整性校验:下载完固件后,算一下哈希,跟服务器给的哈希对比。不一样?说明传输过程中出错了,或者被人动过手脚。
- 签名的基础:非对称签名不是直接对固件签名,而是对固件的哈希签名。因为固件可能很大,直接签名太慢。
- 版本防回滚:把固件版本号也参与哈希计算,防止攻击者把固件回滚到有漏洞的旧版本。
我曾经在一个项目中,只做了签名验证,没做哈希完整性校验。结果有一次,固件在传输过程中因为网络丢包损坏了几个字节,签名验证居然通过了(因为签名只验证了哈希,而哈希恰好没变?不,其实是因为签名验证本身没问题,但固件损坏了,设备刷进去就变砖了)。从那以后,我坚持「签名+哈希」双重校验。
来看一个完整的固件更新校验流程:
// 设备端校验流程
1. 接收固件镜像和元数据(哈希值、签名、版本号)
2. 计算接收到的固件的SHA-256哈希
3. 对比计算出的哈希与元数据中的哈希
- 不一致 → 丢弃,报错
- 一致 → 继续
4. 用公钥验证签名
- 验证失败 → 丢弃,报错
- 验证通过 → 继续
5. 检查版本号是否大于当前版本
- 否 → 拒绝更新(防回滚)
- 是 → 执行更新
4. 三种算法如何协同工作
你可能会问:这三种算法到底怎么配合?我画个简单的流程图给你看:
| 步骤 | 服务器端 | 设备端 |
|---|---|---|
| 1 | 用SHA-256计算固件哈希 | 接收加密固件+签名+哈希 |
| 2 | 用私钥对哈希签名 | 用AES密钥解密固件 |
| 3 | 用AES密钥加密固件 | 计算解密后固件的SHA-256 |
| 4 | 打包发送:加密固件+签名+哈希 | 对比哈希,验证签名 |
| 5 | — | 全部通过 → 执行更新 |
你看,AES负责加密传输,防止固件内容泄露;RSA/ECC负责身份认证,确保固件来自合法来源;SHA-256负责完整性校验,确保固件没有被篡改。三者缺一不可。
好了,这一章的内容就到这里。下一章咱们会深入讲数字证书和PKI体系,看看如何用证书链来管理公钥信任。到时候我会分享一个我踩过的坑——关于证书过期导致设备无法更新的真实案例。