4. 实现AES-256-GCM认证加密
任务说明
本案例基于HSM(硬件安全模块)的AES-256-GCM引擎,实现带关联数据(AAD)的认证加密与解密验证。GCM模式同时提供机密性(加密)、完整性(密文校验)与真实性(AAD绑定),适用于车规通信中ECU间安全报文传输。完成本案例后,你将获得一组可直接调用的加解密接口,以及对应的验证方法。
HSM GCM引擎特性
HSM内部集成AES-256-GCM硬件加速器,支持密钥存储在安全密钥槽(非易失)中,明文密钥不出HSM边界。GCM操作需要以下输入参数:
- 密钥槽ID:指向HSM内已烧录的256位密钥
- IV(96位):每次加密必须唯一,推荐使用计数器或随机数
- AAD:需要认证但不加密的关联数据(如报文头、CAN ID)
- 明文/密文:待保护的数据载荷
- Tag(128位):认证标签,用于完整性校验
代码实现
以下代码基于HSM标准驱动接口(HAL风格),实现GCM加密与解密验证的完整流程。代码中定义了必要的结构体、初始化函数以及加解密函数,并附带一个自测用例用于验证功能正确性。
#include "hsm_driver.h"
#include <string.h>
/* HSM密钥槽ID(需预先通过安全烧录流程写入) */
#define AES256_GCM_KEY_SLOT 0x04
/* GCM参数定义 */
#define GCM_IV_LEN 12 /* 96位IV */
#define GCM_TAG_LEN 16 /* 128位认证标签 */
#define GCM_AAD_MAX_LEN 64
#define GCM_DATA_MAX_LEN 256
/* 返回状态 */
typedef enum {
GCM_OK = 0,
GCM_ERR_KEY_SLOT,
GCM_ERR_IV_NULL,
GCM_ERR_TAG_MISMATCH,
GCM_ERR_HSM_OP_FAIL
} gcm_status_t;
/* GCM操作上下文 */
typedef struct {
uint8_t iv[GCM_IV_LEN];
uint8_t aad[GCM_AAD_MAX_LEN];
uint32_t aad_len;
uint8_t tag[GCM_TAG_LEN];
} gcm_ctx_t;
/* HSM底层驱动接口(由芯片厂商提供) */
extern int32_t hsm_aes_gcm_encrypt(uint32_t key_slot,
const uint8_t *iv, uint32_t iv_len,
const uint8_t *aad, uint32_t aad_len,
const uint8_t *plaintext, uint32_t pt_len,
uint8_t *ciphertext, uint8_t *tag);
extern int32_t hsm_aes_gcm_decrypt(uint32_t key_slot,
const uint8_t *iv, uint32_t iv_len,
const uint8_t *aad, uint32_t aad_len,
const uint8_t *ciphertext, uint32_t ct_len,
const uint8_t *tag, uint8_t *plaintext);
/* GCM加密:输入明文+AAD,输出密文+Tag */
gcm_status_t gcm_encrypt_packet(const gcm_ctx_t *ctx,
const uint8_t *plaintext, uint32_t pt_len,
uint8_t *ciphertext) {
if (ctx == NULL || plaintext == NULL || ciphertext == NULL) {
return GCM_ERR_IV_NULL;
}
if (pt_len == 0 || pt_len > GCM_DATA_MAX_LEN) {
return GCM_ERR_HSM_OP_FAIL;
}
int32_t ret = hsm_aes_gcm_encrypt(AES256_GCM_KEY_SLOT,
ctx->iv, GCM_IV_LEN,
ctx->aad, ctx->aad_len,
plaintext, pt_len,
ciphertext,
(uint8_t *)ctx->tag);
if (ret != 0) {
return GCM_ERR_HSM_OP_FAIL;
}
return GCM_OK;
}
/* GCM解密验证:输入密文+Tag+AAD,输出明文并校验完整性 */
gcm_status_t gcm_decrypt_packet(const gcm_ctx_t *ctx,
const uint8_t *ciphertext, uint32_t ct_len,
uint8_t *plaintext) {
if (ctx == NULL || ciphertext == NULL || plaintext == NULL) {
return GCM_ERR_IV_NULL;
}
if (ct_len == 0 || ct_len > GCM_DATA_MAX_LEN) {
return GCM_ERR_HSM_OP_FAIL;
}
int32_t ret = hsm_aes_gcm_decrypt(AES256_GCM_KEY_SLOT,
ctx->iv, GCM_IV_LEN,
ctx->aad, ctx->aad_len,
ciphertext, ct_len,
ctx->tag,
plaintext);
if (ret != 0) {
return GCM_ERR_TAG_MISMATCH; /* 认证失败:数据被篡改或密钥错误 */
}
return GCM_OK;
}
/* 自测用例:验证加解密闭环 */
gcm_status_t gcm_self_test(void) {
gcm_ctx_t ctx;
uint8_t plaintext[] = "Secure CAN message payload";
uint8_t ciphertext[GCM_DATA_MAX_LEN];
uint8_t decrypted[GCM_DATA_MAX_LEN];
uint32_t msg_len = strlen((char *)plaintext);
/* 初始化IV(实际使用中必须唯一,此处用固定值仅作演示) */
memset(&ctx, 0, sizeof(ctx));
for (int i = 0; i < GCM_IV_LEN; i++) {
ctx.iv[i] = (uint8_t)(0xA0 + i);
}
/* 设置AAD:模拟CAN报文ID + 发送方ID */
ctx.aad[0] = 0x1A; /* CAN ID高字节 */
ctx.aad[1] = 0x2B; /* CAN ID低字节 */
ctx.aad[2] = 0x03; /* 发送方节点ID */
ctx.aad_len = 3;
/* 加密 */
if (gcm_encrypt_packet(&ctx, plaintext, msg_len, ciphertext) != GCM_OK) {
return GCM_ERR_HSM_OP_FAIL;
}
/* 解密验证 */
if (gcm_decrypt_packet(&ctx, ciphertext, msg_len, decrypted) != GCM_OK) {
return GCM_ERR_TAG_MISMATCH;
}
/* 验证明文一致性 */
if (memcmp(plaintext, decrypted, msg_len) != 0) {
return GCM_ERR_HSM_OP_FAIL;
}
return GCM_OK;
}
关键设计说明
- 密钥管理:密钥已预先烧录在HSM密钥槽0x04中,代码中不出现明文密钥,符合HSM安全边界要求。
- IV唯一性:GCM安全性依赖IV唯一性。生产环境中建议使用单调计数器或HSM内部随机数发生器生成IV,禁止在相同密钥下重复使用同一IV。
- AAD绑定:AAD参与认证但不加密。本案例将CAN ID和节点ID作为AAD,确保报文头被篡改时解密失败。
- Tag校验:解密函数内部完成Tag比对,任何一位密文或AAD被修改都会导致认证失败并返回错误码。
编译与运行
# 交叉编译(以ARM Cortex-M为例)
arm-none-eabi-gcc -c gcm_demo.c -o gcm_demo.o
arm-none-eabi-gcc gcm_demo.o -o gcm_demo.elf
# 烧录后通过调试串口观察自测结果
# 若gcm_self_test()返回GCM_OK,则加解密链路正常
验证方法
在目标硬件上执行gcm_self_test(),观察返回值:
- 返回GCM_OK:加解密闭环正确,Tag校验通过,AAD绑定生效。
- 返回GCM_ERR_TAG_MISMATCH:说明解密时Tag比对失败,可能原因包括:密文被篡改、AAD不一致、IV不匹配或密钥槽错误。
额外验证篡改检测:在加密完成后,手动修改ciphertext[0]的任意一位,再调用gcm_decrypt_packet(),此时必须返回GCM_ERR_TAG_MISMATCH,证明完整性保护有效。
判定标准
本案例通过标准如下:
gcm_self_test()返回GCM_OK,证明加解密闭环正确;- 人为篡改密文或AAD后,解密函数返回
GCM_ERR_TAG_MISMATCH,证明完整性保护有效; - 代码中无明文密钥出现,所有密钥操作均通过HSM密钥槽引用。