应用协议数据单元 (APDU) 命令和响应的结构是什么?
What is the structure of an application protocol data unit (APDU) command and response?
我正在努力学习Java卡片。我刚刚开始,并没有找到很多资源。我的第一个问题是如何理解 APDU 命令。 (例如 ISO/IEC 7816-4 中定义的那些)
例如,如果我看到 10101010
这样的字节模式,我如何理解它的含义,特别是确定 例如CLA
或INS
?
这样的"complete"e-book恐怕根本不存在。老实说,我认为完全没有必要。如果您知道基本的 Java 语法,您会发现 JavaCard 非常容易学习(尽管使用起来很烦人)。 Javacard 中缺少所有常见的困难内容(线程、GUI、IO、注释、模板、数据库...),而且标准库非常有限,您将能够在几天内学会它们.
那里有一些不错的教程:
http://www.oracle.com/technetwork/java/embedded/javacard/overview/index.html
http://javacard.vetilles.com/tutorial/
还有一个很好的 SO 问题:
How to get started with Java Cards?
回答您的问题:JavaCard 只是一种用于编写称为 applet 的智能卡应用程序的语言。它处理所有应用程序逻辑,但不指定 APDU 格式。那是因为 JavaCard 不是唯一的智能卡技术。 APDU 格式在 ISO7816 标准中有规定,我强烈建议您通读一下。它不是免费下载的,但您可以在这里找到最重要的部分:
http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx
你会发现,你的 APDU 命令由 header:
00A404000E
和数据部分:
63616C63756C61746F722E617070
.
header指定应该调用什么函数:
00
- class 字节(CLA,00 表示 "inter-industry command sent to logical channel 0")
A4
- 指令字节(INS,A4表示"SELECT applet command")
04
- 参数 1 (P1)
00
- 参数 2 (P2)
0E
- 数据部分的长度(Lc)
并且数据部分包含应选择以供将来使用的小程序的标识符(在您的情况下,它是 ASCII 编码的字符串 "calculator.app" 顺便说一句)。
APDU 命令是以下形式的二进制数队列:
CLA | INS | P1 | P2 | Lc | CData | Le
前四个部分,即 CLA , INS , P1 和 P2在所有APDU命令中都是强制性的,每个都有一个字节长度。这些单字节长度的部分分别代表 Class、Instruction、Parameter1 和 Parameter2。
最后三个部分,即 Lc 、CData 和 Le 是 optional.Lc是Nc的编码,也就是CDATA字段长度的编码。 Le是Ne的编码,然后是可能发送的最大响应数据的编码。根据这些部分的存在与否,我们有 4 种 APDU 命令的情况,如下所示:
- 案例 1:
CLA | INS | P1 | P2
- 案例 2:
CLA | INS | P1 | P2 | Le
- 案例 3:
CLA | INS | P1 | P2 | Lc | Data
- 案例4:
CLA | INS | P1 | P2 | Lc | Data | Le
不同的命令,不同的小程序,CData的长度是不同的。根据 CData 的长度(即 Lc)和可能发送的最大响应数据的长度(即 Le),我们必须键入 APDU 命令:
- Normal/Short APDU 命令,当Lc and Le小于
0xFF
- 扩展长度的APDU命令,当Lcand/orLe 大于
0xFF
.
所以对于这些部分的长度,我们有:
Lc:短 APDU 命令为 1 个字节,扩展 APDU 命令为 3 个字节(他们指定了这个长度,因为它足够了)。
数据:长度不同。
Le : 与 Lc.
相同
如何理解 APDU 命令?
答案:
当你写一个小程序时,你指定你的小程序对它将来接收的不同 APDU 命令的响应。 Card Manager也是一个小程序。它支持的命令在您的卡 specifications/datasheet 中定义。通常几乎所有卡都是 GlobalPlatform and ISO7816 兼容的,因此它们必须支持这些文档中定义的那些强制性 APDU 命令。例如,由于 0xA4
在 ISO7816-4 标准中被定义为 SELECT FILE 命令,如果您看到像 xx A4 xx xx
这样的 APDU 正在发送到卡经理,你可以断定它与SELECT FILE
.
有关
请注意,您可以为不同小程序中的不同功能选择一个值。例如下面Applet1会return 0x6990
接收00 B0 xx xx
APDU命令,而Applet2会return 0x6991
接收同样的命令:
小程序 1:
public class SOQ extends Applet {
private SOQ() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SOQ().register();
}
public void process(APDU arg0) throws ISOException {
byte buffer[] = arg0.getBuffer();
if(buffer[ISO7816.OFFSET_CLA] == (byte) 0x00 &&buffer[ISO7816.OFFSET_INS] == (byte) 0xB0){
ISOException.throwIt((short)0x6990);
}
}
}
输出:
OpenSC: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00B00000 -s 00B00
100
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x90)
Sending: 00 B0 00 00
Received (SW1=0x69, SW2=0x90)
Sending: 00 B0 01 00
Received (SW1=0x69, SW2=0x90)
小程序 2:
public class SOQ extends Applet {
private SOQ() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SOQ().register();
}
public void process(APDU arg0) throws ISOException {
byte buffer[] = arg0.getBuffer();
if(buffer[ISO7816.OFFSET_CLA] == (byte) 0x00 && buffer[ISO7816.OFFSET_INS] == (byte) 0xB0){
ISOException.throwIt((short)0x6991);
}
}
}
输出:
OpenSC: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00B00000 -s 00B00
100
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 B0 00 00
Received (SW1=0x69, SW2=0x91)
Sending: 00 B0 01 00
Received (SW1=0x69, SW2=0x91)
因此,您的问题(我如何理解 APDU 命令?)的最终简短答案是:
你在处理你的小程序吗?
您自己定义了支持的命令及其形式!
您正在处理另一个小程序(例如卡片管理器)?
您需要该小程序的源代码或其有关其支持的命令及其形式的文档,或者该小程序兼容的standard/specification(例如卡片管理器全球平台)。
注意:我们对 APDU 响应几乎相同。
我正在努力学习Java卡片。我刚刚开始,并没有找到很多资源。我的第一个问题是如何理解 APDU 命令。 (例如 ISO/IEC 7816-4 中定义的那些)
例如,如果我看到 10101010
这样的字节模式,我如何理解它的含义,特别是确定 例如CLA
或INS
?
这样的"complete"e-book恐怕根本不存在。老实说,我认为完全没有必要。如果您知道基本的 Java 语法,您会发现 JavaCard 非常容易学习(尽管使用起来很烦人)。 Javacard 中缺少所有常见的困难内容(线程、GUI、IO、注释、模板、数据库...),而且标准库非常有限,您将能够在几天内学会它们.
那里有一些不错的教程:
http://www.oracle.com/technetwork/java/embedded/javacard/overview/index.html http://javacard.vetilles.com/tutorial/
还有一个很好的 SO 问题:
How to get started with Java Cards?
回答您的问题:JavaCard 只是一种用于编写称为 applet 的智能卡应用程序的语言。它处理所有应用程序逻辑,但不指定 APDU 格式。那是因为 JavaCard 不是唯一的智能卡技术。 APDU 格式在 ISO7816 标准中有规定,我强烈建议您通读一下。它不是免费下载的,但您可以在这里找到最重要的部分:
http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx
你会发现,你的 APDU 命令由 header:
00A404000E
和数据部分:
63616C63756C61746F722E617070
.
header指定应该调用什么函数:
00
- class 字节(CLA,00 表示 "inter-industry command sent to logical channel 0")
A4
- 指令字节(INS,A4表示"SELECT applet command")
04
- 参数 1 (P1)
00
- 参数 2 (P2)
0E
- 数据部分的长度(Lc)
并且数据部分包含应选择以供将来使用的小程序的标识符(在您的情况下,它是 ASCII 编码的字符串 "calculator.app" 顺便说一句)。
APDU 命令是以下形式的二进制数队列:
CLA | INS | P1 | P2 | Lc | CData | Le
前四个部分,即 CLA , INS , P1 和 P2在所有APDU命令中都是强制性的,每个都有一个字节长度。这些单字节长度的部分分别代表 Class、Instruction、Parameter1 和 Parameter2。
最后三个部分,即 Lc 、CData 和 Le 是 optional.Lc是Nc的编码,也就是CDATA字段长度的编码。 Le是Ne的编码,然后是可能发送的最大响应数据的编码。根据这些部分的存在与否,我们有 4 种 APDU 命令的情况,如下所示:
- 案例 1:
CLA | INS | P1 | P2
- 案例 2:
CLA | INS | P1 | P2 | Le
- 案例 3:
CLA | INS | P1 | P2 | Lc | Data
- 案例4:
CLA | INS | P1 | P2 | Lc | Data | Le
不同的命令,不同的小程序,CData的长度是不同的。根据 CData 的长度(即 Lc)和可能发送的最大响应数据的长度(即 Le),我们必须键入 APDU 命令:
- Normal/Short APDU 命令,当Lc and Le小于
0xFF
- 扩展长度的APDU命令,当Lcand/orLe 大于
0xFF
.
所以对于这些部分的长度,我们有:
Lc:短 APDU 命令为 1 个字节,扩展 APDU 命令为 3 个字节(他们指定了这个长度,因为它足够了)。
数据:长度不同。
Le : 与 Lc.
相同如何理解 APDU 命令?
答案:
当你写一个小程序时,你指定你的小程序对它将来接收的不同 APDU 命令的响应。 Card Manager也是一个小程序。它支持的命令在您的卡 specifications/datasheet 中定义。通常几乎所有卡都是 GlobalPlatform and ISO7816 兼容的,因此它们必须支持这些文档中定义的那些强制性 APDU 命令。例如,由于 0xA4
在 ISO7816-4 标准中被定义为 SELECT FILE 命令,如果您看到像 xx A4 xx xx
这样的 APDU 正在发送到卡经理,你可以断定它与SELECT FILE
.
请注意,您可以为不同小程序中的不同功能选择一个值。例如下面Applet1会return 0x6990
接收00 B0 xx xx
APDU命令,而Applet2会return 0x6991
接收同样的命令:
小程序 1:
public class SOQ extends Applet {
private SOQ() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SOQ().register();
}
public void process(APDU arg0) throws ISOException {
byte buffer[] = arg0.getBuffer();
if(buffer[ISO7816.OFFSET_CLA] == (byte) 0x00 &&buffer[ISO7816.OFFSET_INS] == (byte) 0xB0){
ISOException.throwIt((short)0x6990);
}
}
}
输出:
OpenSC: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00B00000 -s 00B00
100
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x90)
Sending: 00 B0 00 00
Received (SW1=0x69, SW2=0x90)
Sending: 00 B0 01 00
Received (SW1=0x69, SW2=0x90)
小程序 2:
public class SOQ extends Applet {
private SOQ() {
}
public static void install(byte bArray[], short bOffset, byte bLength)
throws ISOException {
new SOQ().register();
}
public void process(APDU arg0) throws ISOException {
byte buffer[] = arg0.getBuffer();
if(buffer[ISO7816.OFFSET_CLA] == (byte) 0x00 && buffer[ISO7816.OFFSET_INS] == (byte) 0xB0){
ISOException.throwIt((short)0x6991);
}
}
}
输出:
OpenSC: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00B00000 -s 00B00
100
Using reader with a card: ACS CCID USB Reader 0
Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
Received (SW1=0x90, SW2=0x00)
Sending: 00 B0 00 00
Received (SW1=0x69, SW2=0x91)
Sending: 00 B0 01 00
Received (SW1=0x69, SW2=0x91)
因此,您的问题(我如何理解 APDU 命令?)的最终简短答案是:
你在处理你的小程序吗?
您自己定义了支持的命令及其形式!
您正在处理另一个小程序(例如卡片管理器)?
您需要该小程序的源代码或其有关其支持的命令及其形式的文档,或者该小程序兼容的standard/specification(例如卡片管理器全球平台)。
注意:我们对 APDU 响应几乎相同。