梳理 Java Card API 流程
学习目标:以支持扩展APDU为导向,熟悉 Java Card API 流程。
学习向导:站在 Java Card Applet 开发者的角度,把 命令接收流程、返回响应数据流程以及如何调用API给理清楚。
第一步 通读文档
将文档大概看一遍之后,知道 javacard.framework.APDU 的 API 与传输协议无关(用文档的话说就是,applet 可以使用相同的APDU接口,而不管所使用的基础协议是 T=0 还是 T=1),还知道状态机用于表示基于调用的方法和数据传输状态的APDU对象的各种处理状态。除此之外,又定义了与协议相关的接口和枚举常量。
俗话说万事开头难,入门可以先从软柿子开始捏,我的学习路线是:先搞明白状态机各个状态的定义以及状态切换,然后把状态机的状态与API进行关联,接着分协议类型T0和T1,最后再分 ISO7816、SWP和SPI之类的。
当然了,想要将上述节点都拿下并梳理清楚之间关系,就我目前而言,难度至少5颗星,不是简单看看就能理解的,所以这篇文章主要还是用于记录我的学习过程以及各个里程段做个记忆存档。
第二步 攻克 状态机
APDU对象的状态机有正常状态和异常状态两种,正常状态又分输入状态和输出状态。
输入状态按顺序从左往右排列可分为INITIAL、PARTIAL_INCOMING和FULL_INCOMING。
同样地,输出状态按顺序从左往右排列可分为OUTGOING、OUTGOING_LENGTH_KNOWN、PARTIAL_OUTGOING和FULL_OUTGOING。
异常状态有IO_ERROR、NO_T0_GETRESPONSE、NO_T0_REISSUE和T1_IFD_ABORT四种,此时我暂不关心它们。
接着,排除与协议相关的接口后,就得到与APDU相关的接口:
修饰符和类型 | API |
---|---|
byte[] | getBuffer() |
static byte | getCurrentAPDU() |
static byte[] | getCurrentAPDUBuffer() |
byte | getCurrentState() |
static short | getInBlockSize() |
short | getIncomingLength() |
short | getOffsetCdata() |
static short | getOutBlockSize() |
short | receiveBytes(short bOff) |
void | sendBytes(short bOff, short len) |
void | sendBytesLong(byte[] outData, short bOff, short len) |
short | setIncomingAndReceive() |
short | setOutgoing() |
void | setOutgoingAndSend(short bOff, short len) |
void | setOutgoingLength(short len) |
short | setOutgoingNoChaining() |
然后将它们分为辅助和功能两类API,因为辅助类API中,只有getCurrentState()是跟状态机关联,但它不会影响状态机的变化,所以就单独将功能类API拎出来:
修饰符和类型 | API |
---|---|
short | receiveBytes(short bOff) |
void | sendBytes(short bOff, short len) |
void | sendBytesLong(byte[] outData, short bOff, short len) |
short | setIncomingAndReceive() |
short | setOutgoing() |
void | setOutgoingAndSend(short bOff, short len) |
void | setOutgoingLength(short len) |
short | setOutgoingNoChaining() |
结合文档,梳理 APDU API 切换状态机状态的流程,并进行关联。
- receiveBytes 和 setIncomingAndReceive 具有相同的状态机切换过程。
- sendBytes 和 sendBytesLong 具有相同的状态机切换过程。
- setOutgoingAndSend 适用于较短的数据长度,只有一个状态可以设置。
- setOutgoing 和 setOutgoingNoChaining 具有相同的状态机切换状态过程。
- setOutgoingLength 只设置响应数据的实际长度。