密码学基础回顾:对称加密(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用在三个地方:

  1. 固件完整性校验:刷写前算一遍哈希,刷完后算一遍,对比一下就知道有没有被篡改。
  2. 密码存储:ECU里存密码的哈希值,不存明文。这样即使Flash被读出来,攻击者也拿不到原始密码。
  3. 消息认证码(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跑起来。到时候我会带大家手写代码,把今天讲的这些理论落到实处。