3、密码学基础(上):对称加密与非对称加密、哈希函数、数字签名原理
各位同学,欢迎来到密码学基础的上半部分。说实话,很多做OTA的工程师一听到「密码学」三个字就头大,觉得那是数学家的事。我刚开始也这么想,直到有一次在项目里因为签名算法选错,差点让整个升级流程重做……嗯,从那以后我老老实实把基础补上了。
今天咱们不讲复杂的数学公式,就聊聊OTA升级里最常用的几个密码学工具:对称加密、非对称加密、哈希函数、数字签名。你想想看,这些说白了就是几把锁和几把钥匙,没那么玄乎。
3.1 对称加密:一把钥匙开一把锁
对称加密,顾名思义,加密和解密用的是同一把密钥。就像你家的门锁,用同一把钥匙锁门和开门。
我在项目中用得最多的对称加密算法是 AES(Advanced Encryption Standard)。为什么选它?因为快,而且硬件支持好。很多MCU和SoC都内置了AES硬件加速模块,加解密一个128位的数据块只需要几个时钟周期。
核心要点:
- 加密和解密使用同一个密钥
- 常见算法:AES、DES(已淘汰)、SM4(国密)
- 优点:速度快,适合大数据量加密
- 缺点:密钥分发困难——你怎么把密钥安全地交给对方?
举个例子,OTA升级包通常有几十MB甚至几百MB。如果用非对称加密去加密整个包,性能会惨不忍睹。所以实际项目中,我们通常用对称加密来加密固件本身。
// 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);
我的经验:对称加密的密钥不能硬编码在固件里。我曾经见过一个产品,密钥就写在源码的全局变量里,反编译一下就拿到了。正确的做法是:密钥由安全芯片生成并存储,或者通过密钥协商协议动态派生。
3.2 非对称加密:公钥私钥,各司其职
非对称加密解决了对称加密的密钥分发难题。它使用一对密钥:公钥(公开)和私钥(保密)。公钥加密的数据只能用私钥解密,反之亦然。
你想想看,这就像是一个带锁的邮箱。任何人都可以把信投进去(用公钥加密),但只有邮箱主人能打开(用私钥解密)。
OTA升级里,非对称加密主要用在两个地方:
- 数字签名验证(后面会细讲)
- 密钥交换:用非对称加密来传输对称加密的密钥
| 算法 | 密钥长度 | 安全强度 | 典型应用 |
|---|---|---|---|
| RSA | 2048/4096位 | 高 | 签名、密钥交换 |
| ECC(椭圆曲线) | 256位 | 高(同等安全下密钥更短) | 签名、密钥交换 |
| SM2(国密) | 256位 | 高 | 国内合规场景 |
注意:非对称加密非常慢。RSA 2048位加密一个256字节的数据块,在普通MCU上可能需要几十毫秒。所以千万别用它加密整个固件,那是灾难。
我个人习惯的做法是「混合加密」:用非对称加密保护对称密钥,用对称密钥加密固件数据。这样既解决了密钥分发问题,又保证了加解密性能。
3.3 哈希函数:数据的指纹
哈希函数,说白了就是给数据算一个「指纹」。不管你的数据是1KB还是1GB,哈希函数都会输出一个固定长度的摘要(比如SHA-256输出32字节)。而且,只要数据改动一个比特,哈希值就会完全不一样。
哈希函数有三个核心特性:
- 单向性:从哈希值无法反推出原始数据
- 抗碰撞性:很难找到两个不同数据有相同的哈希值
- 雪崩效应:输入微小变化,输出天翻地覆
OTA升级里,哈希函数最常见的用途是完整性校验。下载完固件后,计算它的哈希值,跟服务器下发的哈希值对比。如果一致,说明固件没被篡改也没损坏。
// 计算固件SHA-256哈希
uint8_t hash[32];
sha256_calculate(firmware_data, firmware_len, hash);
// 对比服务器下发的哈希
if (memcmp(hash, expected_hash, 32) == 0) {
// 固件完整,可以继续
} else {
// 固件被篡改或损坏,拒绝升级
}
避坑指南:我曾经遇到过一个案例,工程师只用了CRC32做完整性校验。结果攻击者构造了一个恶意固件,CRC32碰巧跟原固件一样……嗯,从那以后我坚持用SHA-256或更高强度的哈希算法。CRC32只适合检测传输错误,不适合安全场景。
3.4 数字签名:防伪+防抵赖
数字签名,你可以把它理解为「电子印章」。它结合了哈希函数和非对称加密,解决了三个问题:
- 身份认证:确认固件确实来自合法的发布者
- 完整性:固件没有被篡改
- 不可抵赖:发布者不能否认自己签过这个固件
签名过程是这样的:
- 签名方:先对固件算哈希,然后用私钥加密这个哈希,得到签名
- 验证方:用公钥解密签名得到哈希值A,再自己算一遍固件的哈希值B,对比A和B是否相等
为什么这样能防篡改?因为攻击者没有私钥,他改了固件后无法生成新的有效签名。而公钥是公开的,任何人都可以验证。
OTA升级中的典型流程:
- 服务器用私钥对固件哈希签名
- 设备下载固件 + 签名
- 设备用预置的公钥验证签名
- 验证通过 → 升级;验证失败 → 拒绝
// 签名验证伪代码
uint8_t firmware_hash[32];
sha256_calculate(firmware, firmware_len, firmware_hash);
// 用公钥验证签名
if (ecdsa_verify(public_key, firmware_hash, signature) == SUCCESS) {
// 签名有效,固件可信
start_upgrade();
} else {
// 签名无效,可能是恶意固件
reject_upgrade();
}
关键提醒:公钥的存储位置至关重要。如果攻击者能替换设备里的公钥,那整个签名体系就形同虚设。我建议把公钥烧录在一次性可编程(OTP)区域或安全芯片里,确保不可篡改。
3.5 小结:这些工具怎么配合?
讲到这里,你可能已经猜到了。一个完整的OTA升级安全方案,通常是这些工具的组合拳:
- 哈希函数:计算固件指纹,用于完整性校验
- 数字签名:用私钥签名哈希,确保固件来源可信
- 对称加密:加密固件本身,防止被逆向分析
- 非对称加密:保护对称密钥的分发
下一节我们会深入讲这些工具在OTA升级中的具体落地细节,包括密钥生命周期管理、安全启动链、以及如何应对常见的攻击手法。到时候我会分享几个我踩过的坑,保证让你少走弯路。
今天就到这里。记住一句话:密码学不是银弹,但不懂密码学,你的OTA升级就是裸奔。