3. 密码学基础(上):对称加密(AES)、非对称加密(RSA/ECC)、哈希函数(SHA256)的原理与选型
各位同学,欢迎来到密码学基础的第一部分。说实话,很多做嵌入式开发的兄弟,一听到「密码学」三个字就头大,觉得那是数学博士才搞的东西。其实不然。你想想看,我们做物联网MCU的,每天跟传感器数据、固件升级、设备认证打交道,密码学就是我们的看门狗——平时不觉得,一旦丢了钥匙,那才叫欲哭无泪。
我个人习惯把密码学分成三大块:对称加密、非对称加密和哈希函数。今天咱们就把这三兄弟挨个捋一遍,重点讲清楚它们「是什么、怎么用、选哪个」。
3.1 对称加密:AES 的前世今生
对称加密,说白了就是「一把钥匙开一把锁」。加密和解密用同一个密钥。你想想看,这就像你家的门锁,出门用钥匙锁上,回家用同一把钥匙打开。简单粗暴,效率高。
在物联网领域,AES(Advanced Encryption Standard) 是绝对的主角。为什么?因为它在硬件实现上极其高效,很多MCU甚至内置了AES硬件加速模块。我在项目中遇到过用软件模拟AES的情况,那叫一个慢——一个128字节的数据包加密要花几十毫秒,这在实时控制场景下根本没法用。
3.1.1 AES 的核心参数
| 参数 | 说明 | 我的建议 |
|---|---|---|
| 密钥长度 | 128 / 192 / 256 位 | MCU上优先选128位,平衡安全与性能 |
| 分组大小 | 固定128位(16字节) | 注意数据填充,PKCS7最常用 |
| 工作模式 | ECB / CBC / CTR / GCM 等 | 千万别用ECB!CBC或GCM更安全 |
这里我要特别强调一下工作模式的选择。我曾经接手过一个智能门锁的项目,前任工程师用了AES-ECB模式。结果呢?同样的明文块会产生同样的密文块,攻击者只要看到重复的密文模式,就能猜出你按了哪个密码键。嗯,这就是典型的「看起来加密了,实际上等于没加密」。
3.1.2 AES 在MCU上的实现
如果你的MCU有硬件AES,那直接用寄存器操作就好。如果没有,那就得用软件实现了。这里给出一段伪代码示例,展示AES-CBC加密的典型流程:
// AES-128 CBC 加密示例(伪代码)
uint8_t key[16] = {0x2b, 0x7e, ...}; // 128位密钥
uint8_t iv[16] = {0x00, 0x01, ...}; // 随机IV
uint8_t plaintext[32] = {...}; // 待加密数据
// 第一步:初始化AES引擎
aes_init(key, AES_128);
// 第二步:CBC模式加密
aes_cbc_encrypt(plaintext, 32, iv, ciphertext);
// 第三步:发送IV + 密文
uart_send(iv, 16);
uart_send(ciphertext, 32);
你可能会问:「为什么要把IV也发出去?」因为接收端需要同样的IV才能解密。IV本身不需要保密,但必须保证每次加密都不同。这就像你每次出门前换一把新锁——锁本身可以公开,但钥匙必须保密。
3.2 非对称加密:RSA 与 ECC 的较量
对称加密有个致命弱点:密钥分发。你想想看,如果我要给一万台设备分发密钥,总不能派人挨个去烧录吧?这时候就需要非对称加密登场了。
非对称加密使用一对密钥:公钥和私钥。公钥可以公开,私钥必须保密。用公钥加密的数据只能用私钥解密,反之亦然。这就像你家的信箱——任何人都可以把信塞进去(用公钥加密),但只有你有钥匙打开(用私钥解密)。
3.2.1 RSA:老当益壮
RSA 基于大整数分解的数学难题。简单说就是:两个大质数相乘很容易,但把乘积分解回两个质数极难。RSA 的密钥长度通常为 1024、2048 或 4096 位。
但在MCU上,RSA 有个大问题:慢。我记得有一次做 OTA 固件升级签名验证,用 RSA-2048 验签一次要花 2 秒钟。对于电池供电的设备来说,这简直是灾难。而且 RSA 的密钥和签名长度都很长,2048 位的密钥意味着 256 字节的签名,这在窄带物联网场景下传输成本很高。
3.2.2 ECC:后起之秀
ECC(椭圆曲线密码学)是近年来在物联网领域大放异彩的方案。它基于椭圆曲线离散对数难题,在同等安全强度下,密钥长度远小于RSA。
| 安全等级 | RSA密钥长度 | ECC密钥长度 |
|---|---|---|
| 80位 | 1024位 | 160位 |
| 112位 | 2048位 | 224位 |
| 128位 | 3072位 | 256位 |
| 256位 | 15360位 | 512位 |
看到没?128位安全等级下,ECC只需要256位密钥,而RSA需要3072位。这意味着什么?意味着ECC在MCU上运算更快、占用内存更少、传输带宽更低。我在一个LoRaWAN终端项目中,用ECC-256做密钥交换,整个握手过程只用了不到100毫秒,而如果用RSA-2048,至少需要1秒以上。
3.3 哈希函数:SHA256 的不可逆魔法
哈希函数,说白了就是「指纹提取器」。它能把任意长度的数据,压缩成一个固定长度的摘要。而且这个摘要是不可逆的——你无法从摘要反推出原始数据。更重要的是,哪怕原始数据只改了一个比特,摘要也会面目全非。
SHA256 是 SHA-2 家族的一员,输出256位(32字节)的哈希值。它在物联网中主要有三个用途:
- 固件完整性校验:下载固件后计算SHA256,与官方公布的哈希值对比,确保固件没被篡改。
- 密码存储:不存明文密码,只存密码的哈希值。即使数据库泄露,攻击者也拿不到原始密码。
- 数字签名的一部分:先对消息做哈希,再对哈希值做签名,效率更高。
这里我要提醒一句:SHA256 不是加密。加密是可逆的,哈希是不可逆的。我见过有新手把哈希函数当加密用,结果数据存进去就再也取不出来了——嗯,那场面相当尴尬。
3.3.1 SHA256 在MCU上的实现
大多数现代MCU都内置了SHA256硬件加速。如果没有,也可以用软件实现,但要注意性能。下面是一个典型的SHA256计算流程:
// SHA256 哈希计算示例
uint8_t data[] = "Hello, IoT World!";
uint8_t hash[32]; // 256位 = 32字节
// 初始化SHA256上下文
sha256_context_t ctx;
sha256_init(&ctx);
// 更新数据(可以分多次调用)
sha256_update(&ctx, data, strlen(data));
// 计算最终哈希
sha256_final(&ctx, hash);
// 打印哈希值(十六进制)
for(int i = 0; i < 32; i++) {
printf("%02x", hash[i]);
}
你可能会问:「为什么要有 update 和 final 两步?」因为实际应用中,数据可能是分片到达的。比如从网络接收固件,一次只能收 1KB,但固件有 1MB。这时候就可以每收到一片就调用一次 update,最后再 final 得到完整的哈希值。这比把所有数据攒齐再计算要灵活得多。
3.4 选型决策:到底该用哪个?
好了,三种密码学工具都介绍完了。你可能会问:「那我到底该用哪个?」别急,我根据实际项目经验,给你一个简单的决策树:
- 需要加密大量数据? → 用 AES-128-CBC 或 AES-128-GCM。GCM模式自带认证,能防篡改。
- 需要安全分发密钥? → 用 ECC-256 做密钥交换。如果必须兼容旧系统,才考虑 RSA-2048。
- 需要校验数据完整性? → 用 SHA256。简单、高效、安全。
- 需要数字签名? → 用 ECDSA(基于ECC的签名算法)。签名短、验签快。
最后说一句:不要自己发明密码算法。我见过太多「我觉得这个算法不够安全,我改一下」的案例,结果无一例外都出了问题。用标准算法、用成熟库、用硬件加速——这才是嵌入式工程师该做的事。
下一节我们会讲密码学基础的下半部分:密钥管理、随机数生成和侧信道攻击防护。到时候我会分享一个我在智能电表项目中踩过的坑——嗯,那个坑让我加了一个月的班。咱们下节课见。