密码学基础(上):对称加密、非对称加密、哈希与消息认证码

各位同学,咱们直接进入正题。密码学这东西,听着玄乎,其实在车规设备里就是几把锁和几把钥匙的事。我做了这么多年嵌入式安全,见过太多因为密码选型翻车的案例——嗯,今天咱们就把最核心的四个工具讲透。

本章核心脉络:对称加密(AES)解决批量数据加密速度问题;非对称加密(RSA/ECC)解决密钥分发信任问题;哈希函数(SHA-256)解决数据完整性校验问题;HMAC 解决带密钥的认证问题。四者缺一不可。

车规设备密码学基础四件套 密码学基础 对称加密 AES-128/256 非对称加密 RSA / ECC 哈希函数 SHA-256 消息认证码 HMAC 各工具在车规设备中的典型应用场景 • AES:ECU 间批量数据加密传输、固件存储加密 • RSA/ECC:数字签名验签、安全启动、密钥协商 • SHA-256:固件完整性校验、密码哈希存储 • HMAC:CAN 总线消息认证、OTA 包完整性验证

1. 对称加密:AES 是车规的标配

对称加密,说白了就是加密和解密用同一把钥匙。你想想看,两个人通信,事先得商量好一个密码本——这就是对称加密的本质。

在车规领域,AES(Advanced Encryption Standard)几乎是唯一的选择。DES 太老,3DES 太慢,SM4 国内用得多但国际通用性差。我个人习惯,新项目一律上 AES-256,除非硬件加速器只支持 AES-128。

我的经验:曾经有个项目,ECU 之间用 CAN FD 传输诊断数据,工程师图省事用了 XOR 加密。结果呢?被我用逻辑分析仪抓了几条报文,三分钟就破解了。从那以后,我要求所有车载通信必须用 AES,别自己发明密码。

AES 的核心参数就三个:

  • 密钥长度:128 / 192 / 256 bit。256 安全余量最大,但计算量也大。
  • 工作模式:ECB(不推荐)、CBC(常用)、CTR(适合流式)、GCM(带认证,强烈推荐)。
  • 填充方式:PKCS7 最通用,NoPadding 要求数据长度是 16 字节整数倍。

这里我重点说一下模式选择。ECB 模式,千万别用。为什么?同样的明文块会生成同样的密文块,这在车规场景里是致命的——攻击者可以通过模式识别推断出报文含义。CBC 模式需要 IV(初始化向量),每次加密必须用随机 IV,这个坑我踩过。

避坑指南:我曾经在一个 OTA 项目中,工程师把 IV 写死在代码里。结果固件加密等于没加密——同样的明文永远产生同样的密文。正确的做法是:IV 随机生成,随密文一起传输,或者用密钥派生函数生成。

来看一个 AES-CBC 加密的代码示例(伪代码风格,实际项目请用硬件加速):

// AES-256 CBC 加密示例
uint8_t key[32] = {0x2b, 0x7e, 0x15, 0x16, ...};  // 256位密钥
uint8_t iv[16]  = {0x00, 0x01, 0x02, ...};         // 随机IV
uint8_t plaintext[] = "ECU诊断请求报文";
uint8_t ciphertext[64];

// 初始化AES上下文
AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CBC_encrypt_buffer(&ctx, plaintext, sizeof(plaintext));

// 输出:ciphertext 即为加密结果
// 传输时需附带 iv,接收方用相同 key + iv 解密

2. 非对称加密:RSA 与 ECC 的抉择

非对称加密解决了一个根本问题:两个人不需要事先共享密钥也能安全通信。公钥公开,私钥保密——这个模型在车规里太重要了。

目前主流方案就两个:RSA 和 ECC(椭圆曲线密码学)。

对比项 RSA ECC
安全强度 2048 bit ≈ ECC 224 bit 256 bit ≈ RSA 3072 bit
密钥长度 2048~4096 bit 224~521 bit
签名速度 较慢(私钥操作) 快(尤其签名)
验签速度 快(公钥操作) 较慢
车规适用场景 安全启动验签(公钥在ROM) V2X 通信、轻量级设备

我个人更倾向于 ECC,尤其是在资源受限的 MCU 上。你想想看,一个 Cortex-M4 内核的 ECU,要存储 RSA 2048 的密钥对需要 512 字节,而 ECC 256 只需要 64 字节——差了 8 倍。而且 ECC 的签名生成速度比 RSA 快一个数量级。

关键认知:非对称加密从不用于加密大量数据。它只做两件事:数字签名(证明身份)和密钥协商(交换对称密钥)。车规里最常见的用法是:用 ECC 签名固件,用 AES 加密固件内容。

ECC 的曲线选择也很重要。国际上通用的是 NIST P-256(secp256r1),国内常用 SM2。我建议车规项目优先用 NIST P-256,因为硬件加速器支持最广泛。曾经有个项目选了 Brainpool 曲线,结果发现硬件不支持,只能软件实现,性能直接掉了 70%。

3. 哈希函数:SHA-256 是底线

哈希函数,说白了就是数据指纹。不管输入多长,输出固定长度(SHA-256 输出 256 bit)。而且不可逆——你没法从哈希值反推出原始数据。

在车规里,SHA-256 的用途太多了:

  • 固件完整性校验:刷写前计算哈希,对比官方发布的哈希值。
  • 密码存储:绝不存明文密码,只存哈希值。
  • 数字签名的一部分:先对消息做哈希,再对哈希值签名。
  • 随机数生成:用硬件熵源 + SHA-256 生成高质量随机数。

我的习惯:所有涉及数据完整性的地方,我都用 SHA-256。MD5 和 SHA-1 已经被证明有碰撞攻击,虽然实际攻击成本很高,但车规设备生命周期长(10~15年),必须考虑未来风险。SHA-256 目前没有实际可行的碰撞攻击。

SHA-256 的计算过程大致分三步:

  1. 填充:在消息末尾补 bit,使长度满足 512 bit 的整数倍。
  2. 分块:每 512 bit 为一个消息块。
  3. 压缩:每个块经过 64 轮迭代,更新 256 bit 的状态值。

代码示例(使用 mbedTLS 库,车规常用):

#include "mbedtls/sha256.h"

uint8_t hash[32];
mbedtls_sha256_context ctx;

mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts(&ctx, 0);  // 0 = SHA-256, 1 = SHA-224
mbedtls_sha256_update(&ctx, data, data_len);
mbedtls_sha256_finish(&ctx, hash);
mbedtls_sha256_free(&ctx);

// hash[0..31] 即为 256 bit 哈希值

避坑指南:我曾经见过一个项目,用 SHA-256 做密码哈希,但没有加盐(salt)。结果呢?两个用户密码相同,哈希值也相同。攻击者只要拿到一个哈希,就能知道所有相同密码的用户。正确的做法是:password_hash = SHA256(password + random_salt)。

4. 消息认证码:HMAC 解决「谁发的」问题

哈希函数只能保证数据没被改,但保证不了数据是谁发的。攻击者可以篡改数据后重新计算哈希——你根本发现不了。这时候就需要 HMAC(Hash-based Message Authentication Code)。

HMAC 的本质是:带密钥的哈希。只有知道密钥的人才能生成正确的 MAC 值。接收方用同样的密钥和消息重新计算 MAC,对比一致则认证通过。

HMAC 的数学定义很简单:

HMAC(K, m) = H( (K' ⊕ opad) || H( (K' ⊕ ipad) || m ) )

其中:
K'  = 对密钥 K 做哈希或填充到块长度
opad = 0x5c 重复块长度次
ipad = 0x36 重复块长度次
H   = 底层哈希函数(如 SHA-256)

在车规里,HMAC 最常见的应用场景是 CAN 总线消息认证。CAN 报文只有 8 字节数据域,你不可能塞一个完整的数字签名。但 HMAC 可以截断到 4 字节,配合新鲜值(counter)防止重放攻击。

实战经验:我在做 T-Box 安全通信时,要求每条 CAN 消息都带一个 4 字节的 HMAC 截断值。密钥由 HSM(硬件安全模块)管理,每次上电由主密钥派生。这样即使攻击者能监听总线,也无法伪造合法消息。

HMAC 相比普通哈希的优势:

  • 抗长度扩展攻击:普通哈希(如 SHA-256)存在长度扩展漏洞,HMAC 没有。
  • 密钥隔离:即使哈希算法被攻破,密钥也不会泄露。
  • 标准统一:HMAC-SHA256 是 NIST 和 ISO 都推荐的标准。

代码示例(HMAC-SHA256 计算):

#include "mbedtls/md.h"

uint8_t key[16] = {0x01, 0x02, ...};
uint8_t message[] = "CAN_MSG_ID=0x123 DATA=0xAABBCCDD";
uint8_t hmac_result[32];

mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
mbedtls_md_hmac_starts(&ctx, key, sizeof(key));
mbedtls_md_hmac_update(&ctx, message, sizeof(message));
mbedtls_md_hmac_finish(&ctx, hmac_result);
mbedtls_md_free(&ctx);

// 取前4字节作为CAN消息认证码
uint32_t mac_short = (hmac_result[0] << 24) | (hmac_result[1] << 16) | 
                     (hmac_result[2] << 8)  | hmac_result[3];

小技巧:HMAC 的密钥不要硬编码。我习惯的做法是:用设备唯一序列号 + 主密钥派生,每个设备的 HMAC 密钥都不同。这样即使一个设备被物理破解,也不会影响整个车队。

5. 四种工具如何协同工作

讲完了四个工具,咱们看看它们在实际车规场景里怎么配合。以安全启动(Secure Boot)为例:

  1. 固件签名(离线):用 ECC 私钥对固件哈希值(SHA-256)签名。
  2. 固件加密(可选):用 AES 密钥加密固件内容,AES 密钥用 ECC 公钥加密传输。
  3. 启动验证(设备端):解密固件 → 计算 SHA-256 → 用 ECC 公钥验签 → 通过则启动。
  4. 运行时通信:用 HMAC 保护 CAN 消息,用 AES 加密诊断数据。

你看,四种工具各司其职,缺一不可。对称加密管速度,非对称加密管信任,哈希管完整性,HMAC 管认证。这就是车规设备身份安全的基石。

总结一句话:密码学不是选最牛的算法,而是选最合适的组合。AES + ECC + SHA-256 + HMAC,这套组合拳打好了,车规设备的安全基线就立住了。