密码学基础回顾:对称加密(AES-128)、非对称加密(ECC)、哈希算法(SHA-256)
各位同学,咱们今天聊点实在的。密码学这东西,听起来高大上,其实在ECU里就是几套固定的数学把戏。我做了这么多年嵌入式安全,见过太多人把算法背得滚瓜烂熟,一到真刀真枪部署就翻车。今天咱们就掰开揉碎,把AES、ECC、SHA-256这三样讲透。
对称加密:AES-128,ECU里的老黄牛
先说AES。这玩意儿在ECU里用得最多,为啥?因为它快。你想想看,发动机每毫秒都在喷油点火,哪有时间等你慢慢算。AES-128的密钥长度128位,分组大小也是128位,说白了就是一把钥匙开一把锁。
我个人习惯把AES的工作模式分成两类:一类是ECB,一类是其他。ECB模式我基本不用,为什么?因为同样的明文会生成同样的密文,这在ECU里是致命的。举个例子,你刷写固件时,如果某个数据块重复出现,攻击者一眼就能看出来。
我在项目中遇到过最坑的事,就是有人用ECB模式加密CAN报文。结果呢?攻击者通过统计报文频率,直接还原了控制逻辑。嗯,从那以后我定了个规矩:ECU里但凡涉及通信加密,一律用CBC或CTR模式。
来看一段AES-128的CBC模式伪代码,这是我在实际项目中用过的框架:
// AES-128 CBC 加密示例(伪代码)
uint8_t key[16] = {0x2B, 0x7E, 0x15, 0x16, ...}; // 128位密钥
uint8_t iv[16] = {0x00, 0x01, 0x02, ...}; // 初始化向量
void aes_cbc_encrypt(uint8_t *plaintext, uint8_t *ciphertext, uint32_t len) {
uint8_t buffer[16];
// 第一块与IV异或
for (int i = 0; i < 16; i++) buffer[i] = plaintext[i] ^ iv[i];
aes_encrypt_block(buffer, ciphertext); // 核心加密
// 后续块与前一密文异或
for (int j = 1; j < len/16; j++) {
for (int i = 0; i < 16; i++)
buffer[i] = plaintext[j*16+i] ^ ciphertext[(j-1)*16+i];
aes_encrypt_block(buffer, &ciphertext[j*16]);
}
}
实战小贴士:ECU里用AES,密钥存储是关键。我建议把密钥放在HSM(硬件安全模块)里,别直接写在Flash里。曾经有个项目,密钥就明文放在代码段,结果被调试器一读就出来了——那叫一个尴尬。
非对称加密:ECC,小而美的选择
说到非对称加密,很多人第一反应是RSA。但在ECU里,我更推荐ECC。为什么?因为ECC在同等安全强度下,密钥长度更短,计算量更小。你想想看,ECU的算力就那么点,用RSA-2048做个签名,CPU得喘半天。
ECC的核心是椭圆曲线上的离散对数问题。说白了,就是给你一个点P,再给你一个点Q=kP,你想算出k,难得很。我常用的曲线是secp256r1,也叫P-256,这是NIST推荐的标准曲线。
我曾经踩过一个坑:用ECC做密钥交换时,没有验证对方公钥是否在曲线上。结果呢?攻击者塞进来一个不在曲线上的点,直接导致密钥协商失败,还泄露了部分私钥信息。嗯,从那以后我每次做ECDH,都会先调用一个点验证函数。
ECC在ECU里的典型应用场景有两个:
- 安全启动:用ECC签名验证固件镜像。Bootloader里只存公钥,私钥放在产线服务器上。
- 密钥协商:ECU和诊断仪之间用ECDH交换会话密钥,后续通信改用AES。
注意:ECC的随机数生成一定要用真随机数发生器(TRNG)。我曾经见过有人用伪随机数做ECC签名,结果两次签名用了同一个随机数——私钥直接就被算出来了。这在密码学里叫"随机数重用攻击",是致命的。
哈希算法:SHA-256,数据的指纹
哈希算法,说白了就是给数据算个"指纹"。SHA-256输出256位,也就是32字节。它的特点是:输入稍微变一点,输出就天翻地覆。这特性在ECU里太有用了。
我一般把SHA-256用在三个地方:
- 固件完整性校验:刷写前算一遍哈希,刷完后算一遍,对比一下就知道有没有被篡改。
- 密码存储:ECU里存密码的哈希值,不存明文。这样即使Flash被读出来,攻击者也拿不到原始密码。
- 消息认证码(HMAC):用SHA-256结合密钥,生成MAC,确保消息没被篡改。
来看一个实际项目中用过的SHA-256计算流程:
// SHA-256 计算示例(伪代码)
void sha256_calculate(uint8_t *data, uint32_t len, uint8_t *hash_out) {
sha256_context ctx;
sha256_init(&ctx); // 初始化上下文
sha256_update(&ctx, data, len); // 喂数据
sha256_final(&ctx, hash_out); // 取结果
// 输出32字节哈希值
}
这里有个细节要注意:SHA-256对输入长度敏感。如果你要算的数据是分多次收到的,一定要用update接口,别自己拼接。我见过有人把两段数据拼成字符串再算哈希,结果因为拼接方式不对,哈希值完全对不上。
核心要点:在ECU里,SHA-256通常和AES搭配使用。比如用AES加密数据,用SHA-256算MAC。这样既保证了机密性,又保证了完整性。我管这叫"加密+认证"双保险。
三种算法的对比与选择
说了这么多,咱们来总结一下。这三种算法各有各的脾气:
| 算法 | 用途 | 速度 | 安全强度 | ECU典型场景 |
|---|---|---|---|---|
| AES-128 | 数据加密 | 快 | 128位 | 通信加密、数据存储 |
| ECC (P-256) | 签名/密钥交换 | 中等 | 128位等效 | 安全启动、密钥协商 |
| SHA-256 | 哈希/完整性 | 快 | 256位 | 固件校验、密码存储 |
我个人建议的搭配方案是这样的:用ECC做身份认证和密钥协商,用AES做大量数据的加密,用SHA-256做完整性校验。这三者配合起来,基本能覆盖ECU里90%的安全需求。
最后说一句:算法本身是公开的,安全的关键在于实现和密钥管理。你想想看,就算用了最牛的算法,密钥被人偷了,那跟没加密有什么区别?所以,咱们做嵌入式安全的,不光要懂算法,更要懂怎么把算法安全地部署到硬件里去。
好,今天就聊到这儿。下一章咱们讲实战——怎么在AURIX TC3xx上把AES跑起来。到时候我会带大家手写代码,把今天讲的这些理论落到实处。