银行卡报文鉴别码(MAC)
ISO/IEC 9797-1、ANSI X9.9 / X9.19、AS 2805.4.1、TDES CBC-MAC、Retail、CMAC、HMAC —— 一次讲清楚它们都是什么、什么关系、怎么算。
0. 为什么需要 MAC
银行卡交易报文(ISO 8583 的 0200 请求 / 0210 响应)要经过网络传输。报文里带着卡号、金额、PIN 密文……如果只是明文传输,攻击者完全可以中途把 100 块改成 10000 块,双方都察觉不到。
解决这个问题的手段叫 MAC(Message Authentication Code,报文鉴别码 / 消息鉴别码)。你列出的这一串名词——ISO 9797-1、X9.9、X9.19、AS2805.4.1、TDES CBC-MAC、Retail、CMAC、HMAC——全都是"算 MAC"这件事的各种标准、算法和叫法。这篇文章就是帮你把它们的家族关系理清楚。
1. 什么是 MAC
MAC 是用一个只有通信双方共享的密钥,对消息算出一个固定长度的"指纹"(也叫认证标签 / tag)。
发送方: MAC = F(密钥 K, 报文 M) → 把 MAC 附在报文后面发出去
接收方: 用同一个 K 对收到的 M 重新算一遍,和收到的 MAC 比对
一致 → M 没被篡改 + 确实来自持有 K 的那一方
不一致 → 拒收
它同时提供两样东西:
|
属性 |
含义 |
靠什么保证 |
|
完整性 Integrity |
报文没被改 |
改一个字节,MAC 就变了 |
|
数据源认证 Data origin authentication |
报文确实来自持有密钥的一方 |
只有双方知道 K,别人算不出来 |
MAC ≠ 哈希SHA-256 也算"指纹",但它只需要消息本身,任何人都能算。攻击者改了消息顺手重算一个哈希就行。MAC 掺入了密钥,攻击者没有密钥就算不出来,所以能防篡改。
MAC ≠ 数字签名数字签名用公私钥对:私钥签名、公钥验证,可以公开验证、防抵赖。MAC 用对称密钥,收发双方都能算,所以无法向第三方证明"这消息是对方发的"(因为收方自己也能造出同样的 MAC)。银行卡支付要的是快、双方互认,对称 MAC 足够,不需要上签名。
比喻:MAC 就像"信封上的火漆印 + 一枚只有你和对方才有的私章"。别人没章,盖不出有效的印;谁要是在路上动了信封,印就坏了。
2. 地基:分组密码与 CBC 模式
- 分组密码(Block Cipher):把数据按固定块大小加密。DES 是 8 字节一块,AES 是 16 字节一块。
- CBC 模式(Cipher Block Chaining,密码分组链接):每一块先和上一块的密文异或,再加密。这样同样的明文块,因位置和前面内容不同,得到不同的密文。
设 E(K, B) = 用密钥 K 加密一块 B
C1 = E(K, m1 ⊕ IV) IV = 0
C2 = E(K, m2 ⊕ C1)
C3 = E(K, m3 ⊕ C2)
C1, C2, C3 叫"链接值"(chaining value)。MAC 家族的很多算法,本质就是"把最后一个链接值拿来当指纹"。
3. 朴素 CBC-MAC:最直觉的做法,和它的致命弱点
做法:把消息按块分组,从 IV=0 开始用密钥 K 做 CBC 加密,取最后一个密文块作为 MAC。
MAC = E(K, mn ⊕ C(n-1)) ← 也就是最后一个链接值
致命弱点:长度扩展攻击(length extension attack)。因为 MAC 就是链条末端的密文,攻击者虽然不知道密钥,但可以把:
( 收到的 M || 收到的 MAC ) ← 把它当成"已经加密好的前缀"
继续往后追加自己的块,一直加密到最后,就能构造出一条更长的新消息,并算出它对应的合法 MAC。于是攻击者凭空得到一条"伪造但 MAC 正确"的消息。
另外,单密钥 CBC-MAC 在消息长度可变时还有更一般的伪造攻击。所以业界必须给这个朴素方案"打补丁",下面这些标准就是补丁的不同形式。
4. ISO/IEC 9797-1:把 MAC 算法家族整理成标准的"菜谱"
全名 《Information technology — Security techniques — Message Authentication Codes (MACs) — Part 1: Mechanisms using a block cipher》(信息技术 · 安全技术 · 用分组密码产生 MAC · 第 1 部分)。
它像一本菜谱系统,由两部分自由组合:
4.1 填充方法(Padding Method)—— 怎么把消息补成整块
消息长度不一定是块的整数倍,先填充:
|
方法 |
做法 |
特点 |
|
法 1(Pad 1) |
末尾补0x00 |
最简单,X9.9 / X9.19 零售 MAC 常用;但与"本来长度就是整块"的消息 无法区分边界,单独用有安全隐患,必须靠"输出变换"补救 |
|
法 2(Pad 2) |
先补一个0x80,再补0x00 |
永远能明确消息边界,现代标准更推荐 |
|
法 3(Pad 3) |
补0x00,但把原始消息长度 作为一块放在消息最前面 |
天然防扩展攻击,但要求算 MAC 前就知道长度 |
|
法 4(Pad 4) |
CMAC 专用 |
配合算法 5 |
4.2 算法(MAC Algorithm)—— 怎么跑 CBC + 最后一块怎么收尾
定义了两件事:中间怎么 CBC,以及最后一个链接值 On 怎么变换成 MAC。这个"输出变换"就是对付第 3 节那个弱点的补丁:
|
算法 |
密钥 |
最后变换 |
谁在用 |
|
算法 1 |
单密钥 K |
直接E(K, On) |
朴素 CBC-MAC;老标准 X9.9、ISO 8731-1 |
|
算法 2 |
双密钥 |
末块改用第二把密钥加密 E(K2, On) |
双密钥 CBC-MAC |
|
算法 3 |
双密钥 |
末块先 用 K2 解密、再用 K1 加密 E(K1, D(K2, On)) |
零售 MAC(Retail MAC) ,即 X9.19 |
|
算法 4 |
双密钥 |
顺序反过来 D(K2, E(K1, On)) |
部分网络细则 |
|
算法 5 |
单密钥 |
CMAC (配填充法 4) |
现代标准、AES 方案 |
现行版(2011 年)还定义了第 6 种算法,是 CMAC 家族的变体,支付领域几乎见不到,不必关心。
关键结论:"零售 MAC"不是谁新发明的算法,它就是 ISO 9797-1 算法 3 + 填充法 1,用双密钥 3DES。 业界常把"零售 MAC"和"双密钥 CBC-MAC"混着叫,说的是同一个东西。
5. Retail MAC / ANSI X9.19:支付行业最常用的 MAC
5.1 历史脉络
- ANSI X9.9(Financial Institution Message Authentication,批发 Wholesale):单密钥 DES 的 CBC-MAC,典型取 4 字节。56 位密钥,今天看太弱。
- ANSI X9.19(Financial Institution Retail Message Authentication,零售 Retail):银行卡支付用的,双密钥 3DES,MAC 8 字节(很多网络取前 4)。
- 兼容设计:如果两半密钥相等(K1 = K2),X9.19 的算法结果恰好退化成 X9.9。所以一套硬件/软件同时支持两个标准——这也是很多 HSM 里同一个 MAC 服务能配"单长度/双长度密钥"的原因。
- 国际对应关系:X9.9 ↔ ISO 8731-1,X9.19 ↔ ISO 9807。
5.2 零售 MAC 具体怎么算
设密钥为 16 字节双长度密钥,拆成 K1 = 前 8 字节,K2 = 后 8 字节:
① 填充 M' = M || 00…00 (按填充法 1 补到 8 字节整数倍)
② CBC On = E(K1, … E(K1, E(K1, m1 ⊕ IV)) … ) IV = 0,全部用 K1
③ 末变换 MAC = E(K1, D(K2, On))
① 填充:消息按填充法 1 补 0x00 到 8 字节的整数倍;
② CBC:从 IV=0 开始,用 K1 对消息做 DES-CBC,得到最后一个密文块 On;
③ 末变换:先用 K2 对 On 做 DES 解密,再用 K1 加密;
④ 输出:得到 8 字节 MAC。ISO 8583 的 F64 / F128 通常取前 4 字节或全 8 字节(各家网络规定不同)。
为什么最后要"解密再加密"这一下? 因为朴素 CBC-MAC 有长度扩展攻击。D(K2) ∘ E(K1) 这个输出变换把链条末端的链接值换了一把 K2 重新打散——攻击者不知道 K2,就没法把自己追加的块"接"上去,伪造立刻失效。
6. TDES CBC-MAC:到底是 3DES 还是 DES?
最容易混的点:
- 零售 MAC 的 CBC 阶段用的是单 DES(K1 那 8 字节),不是 3DES 跑三遍。所谓"双密钥 3DES"体现在最后变换的 E-D 结构上(K1 加密、K2 解密、K1 加密),合成一个 2-key 3DES 的等效效果。
- "TDES CBC-MAC"这个词还经常被泛指:任何用 3DES 密钥做的 CBC-MAC 家族(ISO 9797-1 算法 2/3/4 的双长度甚至三长度密钥做法,HSM 里通常叫 M0 / M1 等 key variant)。IBM CCA 的 MAC 服务里,X9.19 双/三长度密钥就对应 ISO 9797-1 算法 3。
- 三密钥变体(24 字节 K1/K2/K3)各网络细则不同,一般是 CBC 用 K1,最后变换串上更多层 E/D。联调时先问清楚对方是 2-key 还是 3-key,K1/K2 各是哪一段。
7. AS 2805.4.1:澳大利亚的 EFTPOS 标准
- 全名 《Electronic funds transfer — Requirements for interfaces, Part 4.1: Message authentication — Mechanisms using a block cipher》(电子资金转账 · 接口要求 · 第 4.1 部分 · 报文鉴别)。
- 澳大利亚的银行卡网络(ATM / EFTPOS,即银联通道/收单体系之外的澳本土网)几乎独家用 AS 2805 系列。AS 2805.4.1 规定了用分组密码生成/校验 MAC,本质就是 ISO 9797-1 的零售 MAC(2-key 3DES),后来干脆改名 AS ISO/IEC 9797.1:2019(直接采用国际标准)。
- 特点:澳洲网络要求 MAC 密钥单向使用——上行/下行各一把,分开用。这和 DUKPT 里"Msg Auth Req Key(请求方向)/ Msg Auth Rsp Key(响应方向)"的思路完全一致(见下文第 11 节)。
- 对你的意义:做澳洲收单 / EFTPOS 联调时,听到"AS2805.4.1 MAC"不要慌——它就是拿一把 16 字节 3DES 密钥跑零售 MAC,跟你在 txn_sim 里 mac.c 的 mac_retail 是同一套东西。
8. CMAC:现代接班人(AES-CMAC,NIST SP 800-38B)
8.1 为什么还要有 CMAC
零售 MAC(算法 3)能防扩展攻击,但配合 Pad 1 时,"消息长度恰好是整块"和"差一块"这两种情况无法从密文上区分,边界仍有歧义,安全证明也不友好。CMAC 用一个统一的办法解决:从密钥派生两个子密钥 K1、K2,用来区分"最后一块是完整块还是部分块"。一个算法通吃,安全性有正式证明。
8.2 步骤
① 子密钥 L = AES_K(0^128) (用 K 加密 16 个 0 字节)
K1 = 2·L (左移一位,最高位进位则异或 0x87)
K2 = 2·K1
② CBC 对前 n-1 块用 K 做 CBC,得链接值 X
③ 末块 完整块 → 用 K 加密(末块 ⊕ X ⊕ K1)
部分块 → 补 0x80 00… 后,用 K 加密(末块 ⊕ X ⊕ K2)
④ 输出 16 字节(可截断)
出现场合:EMV 的部分数据认证、AES 迁移方案、新 HSM API。ISO 9797-1 算法 5 就是它。
9. HMAC:另一条技术路线(基于哈希,不碰分组密码)
- HMAC(RFC 2104)不基于 DES/AES,而基于哈希函数(SHA-1 / SHA-256 / SHA-512)。结构是"密钥做两次填充、两次哈希":
HMAC(K, M) = H( (K ⊕ opad) ‖ H( (K ⊕ ipad) ‖ M ) )
ipad = 0x36 opad = 0x5C (按哈希块长重复填充)
ipad/opad 的作用是把密钥摊到两个独立输入里,从而防住长度扩展之类的攻击。
- 特点:软件实现快、OpenSSL / Java 到处都有,是互联网世界的 MAC 主角——TLS、JWT、API 签名、支付回调验签里全是它。
- 但在传统银行卡报文(ISO 8583 / 零售 MAC)生态里几乎不用:因为既有网络是用分组密码 + 3DES 一路铺过来的,主机侧的 HSM(加密机)也都是按分组 MAC(M0/M1…)实现的,改哈希不现实。
一句话总结:HMAC 是"互联网世界"的 MAC,零售 MAC / CMAC 是"银行卡世界"的 MAC。 做支付别拿 HMAC 去和银行对 MAC,对不上。
10. 一张表看懂全部
|
名称 |
本质 |
密钥 |
典型输出 |
主要场景 |
对应关系 |
|
ANSI X9.9 |
单密钥 DES 的 CBC-MAC |
1×DES(8B) |
4 / 8 B |
批发(Wholesale)报文、老零售 |
ISO 9797-1 算法1 + Pad1 |
|
ANSI X9.19 |
双密钥 3DES 的 CBC-MAC + ED 变换 |
2×DES(16B) |
8 B(常取前 4) |
银行卡支付主力 |
ISO 9797-1 算法3 + Pad1 |
|
零售 MAC / Retail |
= X9.19 的行业叫法 |
同上 |
同上 |
POS / ATM 交易报文 |
ISO 9807;同左 |
|
ISO/IEC 9797-1 |
通用"菜谱"标准 |
1~2 把 |
任意长度 |
标准框架 |
算法 1/2/3/4/5 × 填充 1/2/3/4 |
|
AS 2805.4.1 |
澳洲版零售 MAC |
2-key 3DES |
8 B |
澳大利亚 ATM / EFTPOS |
同算法 3,已并入 AS ISO/IEC 9797.1:2019 |
|
CMAC |
子密钥版 CBC-MAC |
AES / 3DES |
16 B |
现代标准、EMV、AES 迁移 |
NIST SP 800-38B;ISO 9797-1 算法5 + Pad4 |
|
HMAC |
基于哈希的 MAC |
任意长密钥 |
哈希输出长 |
互联网、TLS、API 签名 |
RFC 2104 |
12. 避坑清单
13. 参考
- ISO/IEC 9797-1:2011《Information technology — Security techniques — MACs — Part 1: Mechanisms using a block cipher》
- ANSI X9.9 / ANSI X9.19(零售报文鉴别)
- AS 2805.4.1 / AS ISO/IEC 9797.1:2019(澳大利亚 EFTPOS 报文鉴别)
- NIST SP 800-38B《Recommendation for Block Cipher Modes of Operation: The CMAC Mode for Authentication》
- RFC 2104《HMAC: Keyed-Hashing for Message Authentication》
- RSA Labs: What are ANSI X9 standards?
- IBM z/OS 文档:MAC keys
- AusPayNet IAC 规范(澳洲 EFTPOS 强制 AS 2805.4.1)
- AWS Payment Cryptography:AS2805 MAC 概述


