首页/安全/加密与证书速查/CMAC 消息认证码
加密算法基础95 条

CMAC 消息认证码

基于分组密码的消息认证码(NIST SP 800-38B / RFC 4493):用 AES 生成定长认证标签,硬件实现简单,适合受限设备与部分金融协议。

加密与证书速查安全更新于 2026-10-13

CMAC 是什么

CMAC(Cipher-based MAC)是用分组密码构造的消息认证码,规范见 NIST SP 800-38B 与 RFC 4493(AES-CMAC)。它把密钥与分组密码结合,对消息生成定长认证标签,用来判断消息是否被篡改、是否来自持有密钥的一方。与 HMAC 相比,CMAC 不依赖哈希函数,只需要一个分组密码实现(通常是 AES),在已有 AES 硬件引擎的设备与受限终端上更容易落地,因此常见于物联网与卡类协议。

基本信息

标准NIST SP 800-38B / RFC 4493(AES-CMAC)
基础算法AES-128/192/256,也可基于 3DES 等其他分组密码
标签长度等于分组长度,AES 下为 16 字节,可按协议截断
密钥要求认证密钥应与加密密钥分离
与 HMAC 的关系两者都做完整性校验,算法与标签互不兼容

典型使用场景

  • 物联网设备固件、指令与遥测报文的完整性校验:设备算力有限,AES 引擎常已内置硬件加速
  • 金融与卡类协议的报文认证:部分行业规范直接指定 CMAC 作为认证方式
  • 无线与工业控制协议中信令帧的完整性保护
  • 与加密组合成「先加密再认证」的方案,实现机密性与完整性的分离设计
  • 替代存在变长拼接缺陷的 CBC-MAC,成本几乎没有增加

算法计算与示例

算法计算与示例
# Python(cryptography 库):计算 AES-CMAC 标签
from cryptography.hazmat.primitives import cmac
from cryptography.hazmat.primitives.ciphers import algorithms

c = cmac.CMAC(algorithms.AES(key))    # key 为 16 / 24 / 32 字节
c.update(b'header')                   # 可多次 update 分段喂入
c.update(b'payload')
tag = c.finalize()                    # 输出 16 字节标签
c.verify(tag)                         # 校验,失败时抛异常
# 命令行(OpenSSL 3.x):
# openssl mac -macopt cipher:AES-256-CBC -macopt hexkey:<32 字节 hex> -in msg.bin CMAC

CMAC 与 HMAC 对比

对比项CMACHMAC
依赖原语分组密码(AES)哈希函数(SHA-2)
标签长度等于分组长度,AES 下 16 字节等于哈希输出长度,SHA-256 为 32 字节
硬件成本复用已有 AES 引擎需要哈希核或软件实现
标准出处NIST SP 800-38B、RFC 4493FIPS 198-1、RFC 2104
典型场景受限设备、卡类协议网络与 Web 协议、通用服务
标签截断在受限协议中有先例(例如只保留 8 字节),但截断会直接降低伪造难度:短于 64 位时需要额外的安全论证与明确的使用边界,不要只看「能验证通过」。

易错点

  • 加密密钥与认证密钥复用同一个值:用途未分离,一处泄漏同时影响机密性与完整性,应通过 KDF 派生独立密钥
  • 把 CMAC 标签当数字签名用:它是共享密钥算法,任何持有密钥的一方都能生成,无法提供不可否认性
  • 对可变长度输入误用 CBC-MAC:变长拼接场景下可被拼接攻击,需要认证时应改用 CMAC
  • 截断标签后未重新评估安全边界:标签越短伪造概率越高,短于 64 位需补充论证

数据来源与参考

  • NIST SP 800-38B(CMAC 模式)
  • RFC 4493(AES-CMAC)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌