第二章:APDU通信协议基础
各位同学,今天我们来聊聊APDU通信协议。说实话,这是JavaCard开发中最基础、也最容易踩坑的部分。我刚开始接触智能卡时,就被APDU的格式搞得晕头转向——明明就那么几个字节,为什么能玩出这么多花样?
2.1 APDU命令结构
APDU全称是Application Protocol Data Unit,说白了就是应用层的数据交换单元。你想想看,卡片和读卡器之间要通信,总得有个约定好的格式吧?APDU就是这个约定。
一个命令APDU由两部分组成:头部(Header)和体部(Body)。头部固定4个字节,体部则根据情况变化。
| 字节 | 名称 | 说明 |
|---|---|---|
| CLA | 指令类别 | 通常为0x00,表示ISO标准指令 |
| INS | 指令代码 | 比如0xA4表示SELECT,0xB0表示READ BINARY |
| P1 | 参数1 | 指令的具体参数 |
| P2 | 参数2 | 与P1配合使用 |
| Lc | 数据长度 | 发送的数据字节数(可选) |
| Data | 数据域 | 实际发送的数据(可选) |
| Le | 期望响应长度 | 期望返回的数据字节数(可选) |
嗯,这里要注意:Lc和Le不是同时出现的。它们的关系有点像跷跷板——有Lc就没Le,有Le就没Lc,或者两个都没有。
命令APDU的四种情况:
- 情况1:CLA INS P1 P2 —— 无数据发送,无数据接收
- 情况2:CLA INS P1 P2 Le —— 无数据发送,期望接收Le字节
- 情况3:CLA INS P1 P2 Lc Data —— 发送Lc字节数据,无数据接收
- 情况4:CLA INS P1 P2 Lc Data Le —— 发送数据,并期望接收Le字节
我个人习惯把情况1叫做"空手道"——什么都不带,什么都不拿。情况2是"空手去,满载归"。情况3是"带东西去,空手回"。情况4嘛,就是"带东西去,带东西回"。
2.2 APDU响应结构
响应APDU的结构就简单多了。它只有两部分:数据体和状态字。
响应APDU格式:
[Data] SW1 SW2
状态字SW1和SW2是两个字节,用来表示命令执行的结果。最常见的状态字是0x9000,表示一切正常。我在项目中遇到过最坑的情况就是——卡片返回了0x9000,但数据却是错的。后来才发现是APDU的Le字段写错了。
| 状态字 | 含义 | 我的经验 |
|---|---|---|
| 0x9000 | 正常执行 | 最常见的,但别太相信它 |
| 0x6A82 | 文件未找到 | SELECT指令经常遇到 |
| 0x6985 | 条件不满足 | 安全状态不对,先验证PIN |
| 0x6700 | 长度错误 | Lc或Le写错了,我犯过好几次 |
| 0x6D00 | INS不支持 | 指令代码没实现 |
避坑指南:我曾经花了一整天调试一个APDU,结果发现是Le字段写成了0x00。在T=0协议下,Le=0x00表示期望接收256字节,但在T=1协议下,Le=0x00表示不期望接收数据。这个差异让我吃了大亏。
2.3 T=0与T=1协议对比
T=0和T=1是ISO 7816-3中定义的两种传输协议。说白了,它们就是APDU在物理层上的"快递方式"。
T=0协议:字节传输协议。每个字节都需要握手确认。就像你寄快递,每走一步都要签收确认。效率低,但可靠性高。
T=1协议:块传输协议。把数据打包成块(Block)发送。就像你寄快递,一箱一箱地寄,每箱有个清单。效率高,但实现复杂。
我的建议:如果你在做简单的智能卡应用,比如门禁卡、公交卡,T=0就够用了。但如果你在做金融卡、SIM卡这种需要大量数据交换的应用,T=1是更好的选择。
| 特性 | T=0 | T=1 |
|---|---|---|
| 传输单位 | 字节 | 块(Block) |
| 握手方式 | 每个字节都需要 | 每个块需要 |
| 数据吞吐量 | 低 | 高 |
| 实现复杂度 | 简单 | 复杂 |
| 错误处理 | 基本 | 完善(有重传机制) |
| 典型应用 | 简单存储卡 | 金融卡、SIM卡 |
你想想看,为什么T=1协议会有重传机制?因为金融交易中,数据丢包可不是闹着玩的。我记得有一次帮客户调试POS机,发现T=0协议下偶尔会出现数据错位的问题,换成T=1后就再也没出现过。
2.4 核心知识体系
下面这张图是我自己整理的APDU通信协议知识体系,你可以把它当作学习地图。
这张图把APDU通信协议的核心内容都串起来了。左边是命令结构,右边是响应结构,下面是传输协议。我个人觉得,理解这三者的关系,就掌握了APDU通信的80%。
核心要点总结:
- 命令APDU:CLA INS P1 P2 [Lc Data] [Le]
- 响应APDU:[Data] SW1 SW2
- T=0:字节级传输,简单可靠
- T=1:块级传输,高效可靠
- 状态字0x9000不代表数据一定正确
好了,APDU通信协议的基础就讲到这里。记住,纸上得来终觉浅,绝知此事要躬行。我建议你找个实际的智能卡,用APDU工具发几条命令试试,感受一下T=0和T=1的区别。嗯,实践出真知。