当前位置: 首页 > news >正文

手把手教你用C语言实现AES-CMAC算法(附完整可运行代码)

深入解析AES-CMAC算法:从理论到嵌入式实践

在物联网设备和汽车电子系统中,数据完整性验证是确保通信安全的关键环节。AES-CMAC(Cipher-based Message Authentication Code)作为一种基于AES加密的消息认证码算法,因其高效性和安全性成为资源受限环境下的首选方案。本文将带您从算法原理入手,逐步构建一个完整的C语言实现,并分享在STM32等嵌入式平台上的优化技巧。

1. AES-CMAC算法核心原理

AES-CMAC算法本质上是通过AES加密块来生成消息认证码,其核心思想可以概括为"加密-衍生-再加密"的三段式流程。与传统的HMAC不同,CMAC专门为分组密码设计,特别适合处理固定长度的数据块。

算法运行主要分为三个关键阶段:

  1. 子密钥生成:通过加密零向量得到中间值L,再通过位移和异或运算派生出K1和K2两个子密钥
  2. 消息处理:对输入数据进行分组处理,根据是否完整分块选择使用K1或K2
  3. 最终加密:经过多轮迭代后生成认证码

RFC 4493文档中定义的算法流程如下图所示(此处应为文字描述):

初始化 → 生成子密钥 → 处理消息块 → 最终加密 → 输出MAC

关键数学运算

  • GF(2^128)域上的乘法:用于子密钥生成
  • XOR运算:用于块之间的链式连接
  • AES加密:核心加密原语

注意:在资源受限环境中,GF(2^128)乘法可以通过查表法优化,避免实时计算带来的性能开销。

2. 完整C语言实现拆解

下面我们构建一个模块化的AES-CMAC实现,将关键功能分解为独立函数以便于移植和维护。完整代码包含以下核心组件:

2.1 AES基础加密模块

typedef struct { uint32_t eK[44]; // 加密轮密钥 int Nr; // 轮数(10 for AES-128) } AesKey; void keyExpansion(const uint8_t *key, AesKey *aesKey) { // 密钥扩展实现... } void aesEncryptBlock(AesKey *ctx, const uint8_t input[16], uint8_t output[16]) { // AES-128加密单块实现... }

2.2 CMAC专用函数实现

/* 左移1位运算 */ void leftShiftOneBit(const uint8_t *input, uint8_t *output) { uint8_t overflow = 0; for(int i=15; i>=0; i--) { output[i] = (input[i] << 1) | overflow; overflow = (input[i] & 0x80) ? 1 : 0; } } /* 子密钥生成 */ void generateSubkeys(const uint8_t *key, uint8_t *K1, uint8_t *K2) { uint8_t L[16]; uint8_t Z[16] = {0}; AesKey aesKey; keyExpansion(key, &aesKey); aesEncryptBlock(&aesKey, Z, L); // 生成K1 uint8_t tmp[16]; leftShiftOneBit(L, tmp); if(L[0] & 0x80) { xor_128(tmp, const_Rb, K1); } else { memcpy(K1, tmp, 16); } // 生成K2 leftShiftOneBit(K1, tmp); if(K1[0] & 0x80) { xor_128(tmp, const_Rb, K2); } else { memcpy(K2, tmp, 16); } }

2.3 主算法实现

void aes_cmac(const uint8_t *key, const uint8_t *input, uint32_t length, uint8_t *mac) { uint8_t X[16] = {0}; uint8_t Y[16]; uint8_t M_last[16]; uint8_t K1[16], K2[16]; generateSubkeys(key, K1, K2); int n = (length + 15) / 16; // 计算完整块数 int rem = length % 16; // 最后块剩余字节 if(n == 0) { n = 1; rem = 0; } // 处理最后块 if(rem == 0) { // 完整块用K1 xor_128(&input[16*(n-1)], K1, M_last); } else { // 不完整块填充并用K2 uint8_t padded[16]; padding(&input[16*(n-1)], padded, rem); xor_128(padded, K2, M_last); } // 处理前n-1块 AesKey aesKey; keyExpansion(key, &aesKey); for(int i=0; i<n-1; i++) { xor_128(X, &input[16*i], Y); aesEncryptBlock(&aesKey, Y, X); } // 最终加密 xor_128(X, M_last, Y); aesEncryptBlock(&aesKey, Y, X); memcpy(mac, X, 16); }

3. 嵌入式系统优化技巧

在资源受限的嵌入式环境(如STM32F4系列)中实现AES-CMAC时,需要考虑以下优化策略:

3.1 内存优化方案

优化策略标准实现优化实现节省资源
轮密钥存储44×4字节现场计算176字节RAM
状态缓冲区3×16字节复用缓冲区32字节RAM
子密钥缓存不缓存启动时计算减少重复计算

3.2 性能优化技巧

  1. 使用硬件加速

    // STM32 HAL库中的硬件AES初始化 __HAL_RCC_AES_CLK_ENABLE(); hcryp.Instance = AES; hcryp.Init.DataType = CRYP_DATATYPE_8B; hcryp.Init.KeySize = CRYP_KEYSIZE_128B; HAL_CRYP_Init(&hcryp);
  2. 查表法优化

    • 预计算GF(2^128)乘法表
    • 将S盒和逆S盒存储在Flash而非RAM中
  3. 流水线处理

    // 在接收数据的同时处理前序块 while(receiving_data) { if(block_received) { process_block(); receive_next_block(); } }

3.3 安全性增强措施

  1. 防侧信道攻击

    • 固定时间算法实现
    • 随机化执行顺序
    // 固定时间的XOR实现 void constant_time_xor(uint8_t *a, uint8_t *b, uint8_t *out, size_t len) { for(size_t i=0; i<len; i++) { out[i] = a[i] ^ b[i]; } }
  2. 密钥管理

    • 使用芯片安全区域存储密钥
    • 定期更新子密钥

4. 实际应用案例分析

在汽车电子领域,AES-CMAC常用于ECU安全认证。以下是一个典型的UDS(Unified Diagnostic Services)应用场景实现:

4.1 27服务认证流程

  1. 挑战阶段

    // ECU生成随机数 uint8_t challenge[16]; HAL_RNG_GenerateRandomNumber(&hrng, (uint32_t *)challenge, 4);
  2. 响应验证

    uint8_t receivedMac[16]; uint8_t calculatedMac[16]; // 计算期望的MAC aes_cmac(secret_key, challenge, 16, calculatedMac); // 验证接收到的MAC if(memcmp(receivedMac, calculatedMac, 16) == 0) { // 认证成功 send_positive_response(); } else { // 认证失败 send_negative_response(); }

4.2 性能测试数据

在STM32F407VG(168MHz)上的测试结果:

操作纯软件实现硬件加速提升比例
AES加密520μs/块32μs/块16.25x
CMAC计算(16B)1.2ms150μs8x
CMAC计算(64B)3.8ms450μs8.4x

4.3 常见问题排查

  1. 认证失败可能原因

    • 密钥不一致
    • 数据填充错误
    • 字节序问题
    • 随机数生成质量问题
  2. 调试技巧

    // 调试打印函数 void debug_print_mac(const char *label, uint8_t *mac) { printf("%s: ", label); for(int i=0; i<16; i++) { printf("%02X", mac[i]); } printf("\n"); }

在完成基础实现后,建议使用NIST提供的测试向量进行验证,确保实现的正确性。对于汽车电子应用,还需要考虑ISO 21434等安全标准的要求,在软件架构层面做好安全防护。

http://www.rkmt.cn/news/1509834.html

相关文章:

  • 别再被忽悠了!手把手教你算清家里WiFi 6/6E/7的真实网速上限(附速查表)
  • 别再手动算了!教你用Python的while循环和math库搞定‘攒首付’月数预测
  • 用博弈论设计稳定的 Multi-Agent 协作系统
  • 2026年安徽省高考滑档怎么办?还可以上什么学校?官网最新发布 - 小张zc
  • 线性表示假设与神经网络特征存储的理论突破
  • 2026 年 6 月最新 | 网带输送机厂家盘点 本地靠谱输送设备生产厂商精选推荐 - 商业新知
  • 告别会议杂音和回声!手把手教你理解并配置音频3A(AEC/ANS/AGC)
  • 在湖北仙桃市解决孩子叛逆不听话/戒网瘾厌学的封闭式教育学校有哪些? - 善良的阿良
  • 6月广州个人黄金变现,一站式回收服务省心又划算 - 逸程
  • 2026年乐平管道疏通哪家好?5次亲身经历告诉你答案 - 本地品牌推荐
  • 排序(4)-归并排序专题——归并排序的分治美学
  • 武汉复读机构推荐武汉襄五学校 - 善良的阿良
  • 别再死记命令了!用Wireshark抓包带你彻底搞懂华三GRE隧道封装原理
  • STM32项目里直接用的ESP8266串口驱动,AP和STA模式都已封装好
  • AI泡沫下的真实生产力:万亿美元热浪与落地断层
  • vLLM 云原生推理基础设施深度解析:从 PagedAttention 内核到 Kubernetes 生产级部署
  • 当Kabeja遇见Spring Boot:为老旧DXF解析库注入现代生命力
  • 2025-2026年PVC卡片打印机厂商盘点 多场景适配 - 资讯快报
  • 2026最新太原市黄金回收价格一览表回收避坑攻略及靠谱商家推荐 - 润富黄金回收
  • 2026 新余卫生间漏水不用砸砖?微创补漏靠谱方案 - 苏易修缮
  • 2026年河北玻璃钢环保设备采购指南:从电缆桥架到一体化泵站的专业选型方案 - 优质企业观察收录
  • 2026年深圳知识产权诉讼律师推荐:专业实力护航硬科技创新 - 本地品牌推荐
  • 5分钟快速上手:PotPlayer百度翻译插件完整配置指南
  • 武汉高三复读学校怎么选,哪个学校比较好?联系电话 - 善良的阿良
  • 2026曲靖市黄金回收价格一览表回收避坑攻略靠谱商家推荐 - 润富黄金回收
  • 2026 茂名卫生间漏水不用砸砖?微创补漏靠谱方案 - 苏易修缮
  • 想二次开发Kettle?先搞懂它的源码结构:以9.2.0.0-R版本为例,拆解kettle-core、engine、plugins等核心模块
  • 武汉科谷技工学校2026年简介-学校详细地址 - 善良的阿良
  • 别再乱调了!深入浅出聊聊无人机电调的那些‘隐藏’设置:从油门行程到PWM精度
  • 从服务能力看贵州搬家公司市场格局:一次涵盖居民搬家与企业搬家的综合梳理 - 深度智识库