3、对称加密算法(AES-128/256):ECB/CBC/CTR模式对比、硬件加速器原理、密钥派生函数(KDF)
对称加密,说白了就是加密和解密用同一把钥匙。在ECU里,这把钥匙通常藏在HSM(硬件安全模块)里,软件层根本碰不到。我最早接触AES是在一个T-Box项目里,当时为了省成本没用HSM,结果密钥被OTA抓包分析出来了……嗯,从那以后我再也不敢轻视密钥管理了。
3.1 AES-128 vs AES-256:选哪个?
AES-128和AES-256,区别就在密钥长度上。128位密钥,轮数是10轮;256位密钥,轮数是14轮。多出来的4轮,意味着暴力破解的复杂度从2^128飙升到2^256。
你可能会问:ECU上到底该用哪个?我个人习惯是:
- 安全启动(Secure Boot):用AES-128就够了。启动过程是单向的,攻击者没有机会做大量离线破解。
- 安全通信(SecOC / TLS):用AES-256。通信数据会被反复抓包,256位更稳妥。
- UDS诊断刷写:看OEM要求。我见过的大众、宝马项目,基本都是AES-256。
重要提醒:AES-256虽然更安全,但计算量也更大。如果你的ECU主频只有80MHz,又没有硬件加速器,那AES-256可能会让启动时间增加200ms以上。这个代价,在有些项目里是承受不起的。
3.2 ECB / CBC / CTR 模式对比
AES本身只是个块加密算法,一次处理16字节。怎么处理超过16字节的数据?这就引出了工作模式。我见过不少工程师把模式选错,导致安全漏洞。咱们一个一个说。
3.2.1 ECB模式(电子密码本)
ECB是最简单的模式。每个16字节块独立加密,互不影响。
// ECB加密示意
Ciphertext_Block[i] = AES_Encrypt(Plaintext_Block[i], Key);
优点:可以并行计算,速度快。
致命缺点:相同的明文块,加密后得到相同的密文块。这在图像加密里特别明显——加密后的图片还能看出轮廓。
警告:ECB模式在汽车领域几乎被禁用。我曾经在一个OBD诊断协议里看到有人用ECB加密VIN码,结果VIN码重复的字符在密文里也重复出现,攻击者一眼就能看出规律。千万别这么干。
3.2.2 CBC模式(密码分组链接)
CBC模式引入了IV(初始化向量)。每个明文块先和前一个密文块异或,再加密。
// CBC加密示意
Ciphertext_Block[i] = AES_Encrypt(Plaintext_Block[i] XOR Ciphertext_Block[i-1], Key);
// 第一个块:Ciphertext_Block[0] = AES_Encrypt(Plaintext_Block[0] XOR IV, Key);
优点:相同的明文块,加密后得到不同的密文块。安全性好。
缺点:不能并行加密(解密可以并行)。而且如果IV固定,那第一个块的安全性就大打折扣。
我的经验:CBC模式是ECU里最常用的模式。安全启动、UDS诊断刷写,绝大多数OEM都指定用CBC。但注意:IV绝对不能重复使用。我建议用计数器或者随机数生成IV,每次都不一样。
3.2.3 CTR模式(计数器模式)
CTR模式把AES变成一个流密码。它加密一个计数器值,得到密钥流,然后用密钥流和明文异或。
// CTR加密示意
KeyStream[i] = AES_Encrypt(Counter[i], Key);
Ciphertext_Block[i] = Plaintext_Block[i] XOR KeyStream[i];
优点:可以并行加密和解密。而且不需要填充(padding),数据长度可以任意。
缺点:计数器绝对不能重复。一旦重复,密钥流就一样,两个密文异或就能消掉密钥,直接得到明文。
对比总结:
| 特性 | ECB | CBC | CTR |
|---|---|---|---|
| 安全性 | 低(不推荐) | 高 | 高 |
| 并行加密 | 支持 | 不支持 | 支持 |
| 并行解密 | 支持 | 支持 | 支持 |
| 需要IV | 否 | 是 | 是(计数器) |
| 需要填充 | 是 | 是 | 否 |
| ECU常用场景 | 几乎不用 | 安全启动、刷写 | SecOC、通信加密 |
3.3 硬件加速器原理
纯软件跑AES,在Cortex-M4上大概要200-300个时钟周期加密一个块。如果ECU要加密1MB的固件,那得等好几秒。这显然不行。
硬件加速器,说白了就是一块专门干AES的电路。你把明文和密钥写进寄存器,它几个时钟周期就给你算完。
我拆解过NXP S32K3和Infineon TC3xx的AES加速器,结构大同小异:
- 密钥寄存器:存放128位或256位密钥。通常有多个槽位,可以预存多把密钥。
- 数据寄存器:输入明文/密文,输出结果。
- 控制寄存器:选择模式(ECB/CBC/CTR)、密钥长度、是否自动处理IV等。
- DMA接口:数据量大时,可以直接用DMA搬运,CPU只管触发一下就行。
避坑指南:我曾经在调试TC3xx的AES加速器时,发现加密结果总是不对。查了两天,最后发现是密钥寄存器的字节序(Endianness)没配对。硬件加速器默认是大端,而我的软件数据是小端。嗯,这种坑,遇到一次就记住了。
3.4 密钥派生函数(KDF)
KDF,就是从一根主密钥,派生出多根子密钥。为什么需要这个?
你想想看,ECU里可能有十几把密钥:安全启动一把、SecOC一把、UDS诊断一把、OTA一把……如果全部存进HSM,那HSM的密钥槽位根本不够用。
KDF的典型做法:
// 基于HMAC的KDF(HKDF)
// 输入:主密钥(IKM)、盐值(Salt)、上下文信息(Info)
// 输出:派生密钥(OKM)
// 第一步:提取(Extract)
PRK = HMAC-SHA256(Salt, IKM);
// 第二步:扩展(Expand)
OKM = HMAC-SHA256(PRK, Info || 0x01);
在汽车领域,最常用的KDF是NIST SP 800-108里定义的Counter模式KDF。AUTOSAR的SecOC模块里,就是用这个来派生会话密钥的。
关键点:
- 主密钥必须存储在HSM里,永远不暴露给软件。
- 派生时,Info参数要包含唯一标识(比如ECU的VIN、会话ID),确保每把子密钥都不同。
- KDF的计算最好也在HSM里完成。如果软件层自己算,那主密钥就泄露了。
我记得有一次,一个供应商把KDF的Salt设成了固定值0x0000……结果所有ECU派生出来的子密钥都一样。攻击者破解一台车,就能破解整个车队。这种低级错误,在量产项目里真的出现过。
好了,对称加密这块就聊到这儿。下一章咱们聊聊非对称加密——RSA和ECC在ECU里的那些事儿。