第三章 APDU通信协议:智能卡与世界的对话
APDU,全称是Application Protocol Data Unit。说白了,就是智能卡和外界通信时用的“语言”。我刚开始接触JCOP开发时,觉得这东西不就是发几个字节嘛,有什么难的?结果第一次调通通信就花了整整两天——因为一个字节的顺序搞反了。
嗯,咱们今天就把这块彻底讲透。
3.1 APDU命令格式
APDU命令分两种:短APDU和扩展APDU。咱们平时用的最多的是短APDU,结构如下:
CLA INS P1 P2 [Lc] [Data] [Le]
每个字段的含义:
| 字段 | 长度 | 说明 |
|---|---|---|
| CLA | 1字节 | 指令类别,00表示ISO标准,80表示私有 |
| INS | 1字节 | 指令码,比如A4是SELECT,B0是READ BINARY |
| P1/P2 | 各1字节 | 参数,具体含义看指令定义 |
| Lc | 0或1字节 | 命令数据的长度(如果后面有数据) |
| Data | Lc字节 | 实际发送的数据 |
| Le | 0或1字节 | 期望响应的最大长度 |
关键点:CLA和INS的组合决定了卡片要做什么。我见过不少新手把INS和P1搞混,结果卡片一直返回6A86(错误的INS)。
举个例子,SELECT命令(选择文件):
00 A4 04 00 02 3F 00
这里CLA=00,INS=A4,P1=04(按文件名选择),P2=00,Lc=02,Data=3F00(MF的标识符),Le省略。
3.2 APDU响应格式
卡片处理完命令后,会返回响应。格式很简单:
[Data] SW1 SW2
SW1和SW2是状态字,共2字节。Data是可选的,取决于命令。
常见的状态字:
| SW1 SW2 | 含义 |
|---|---|
| 90 00 | 成功!我最喜欢看到这个 |
| 6A 82 | 文件未找到 |
| 6A 86 | P1/P2参数错误 |
| 69 85 | 安全条件不满足 |
| 67 00 | Lc长度错误 |
避坑指南:我曾经在项目中遇到一个诡异的问题——卡片偶尔返回6A 88(引用数据无效)。查了两天,最后发现是上位机发送数据时,Lc字段写错了。Lc必须等于后面Data的实际长度,多一个字节少一个字节都不行。
3.3 T=0与T=1协议
这两个是传输协议,决定了数据怎么在物理层上传输。你想想看,APDU是应用层的“语言”,而T=0和T=1是“运输方式”。
T=0协议:面向字符的传输。每次只传一个字节,适合低速场景。它的特点是:
- 卡片收到命令后,先返回一个过程字节(0x60表示继续,0x61+Le表示有数据要返回)
- 如果命令有Data,卡片会通过过程字节告诉终端“我准备好了,你发数据吧”
- 响应时,先返回SW1,再返回SW2
T=1协议:面向块的传输。把数据打包成块(block)发送,效率更高。它的特点是:
- 每个块有头信息(NAD、PCB、LEN)和CRC校验
- 支持链式传输(数据太长时分多次发送)
- 有重传机制,可靠性更高
我的经验:JCOP卡片通常同时支持T=0和T=1。我个人习惯用T=1,因为调试时能看到完整的块结构,出问题容易定位。但有些老旧读卡器只支持T=0,这时候就得兼容。
3.4 链路层与传输层
链路层负责物理连接的管理。在ISO 7816标准中,链路层主要处理:
- 复位应答(ATR):卡片上电后发送的第一串数据,告诉终端“我是谁,我支持什么”
- 协议参数选择(PPS):终端和卡片协商用T=0还是T=1
- 去激活:通信结束后的断电流程
传输层则是在链路层之上,负责APDU的收发。说白了,就是把APDU命令拆成T=0或T=1能处理的格式,发出去,再把响应拼回来。
这里有个容易忽略的点:ATR中的TA1字节决定了时钟频率转换因子(F)和比特率调整因子(D)。我见过有人用高速读卡器去读一张老卡片,结果通信失败——因为卡片不支持那么高的速率。
3.5 核心知识体系
下面这张图是我自己整理的APDU通信协议知识结构,你看一眼就能明白整体脉络:
3.6 实战中的注意事项
最后分享几个我在项目中踩过的坑:
- Le字段的陷阱:如果Le=0x00,表示期望最多256字节响应。但有些卡片会把0x00理解为0字节,导致返回空数据。我建议明确写Le值,别偷懒。
- 过程字节的处理:T=0协议下,卡片返回0x60表示“我还在忙”。这时候终端必须继续发送0x60直到卡片返回其他值。我见过有人只发一次0x60就放弃了,结果通信超时。
- ATR的解析:ATR中的历史字节(Historical Bytes)不是必须的,但很多卡片会用它来传递一些厂商信息。别假设所有卡片的ATR格式都一样。
- CRC校验:T=1协议中每个块都有CRC。如果CRC错误,卡片会要求重传。我曾经因为读卡器驱动没实现CRC校验,导致通信成功率只有70%。
小技巧:调试APDU通信时,我习惯用抓包工具(比如PC/SC的日志)把原始字节流记录下来。这样出问题时,可以逐字节分析,定位问题非常快。
好了,APDU通信协议这块就讲到这里。记住一句话:APDU是智能卡的“语言”,T=0和T=1是“运输方式”,链路层是“道路”。三者配合好了,卡片才能正常工作。
公众号:蓝海资料掘金营,微信deep3321