我正在尝试使用 javax.smartcardio读取智能卡(德语 Gesundheitskarte )
在 EF“PD”的定义中,它的长度被指定为 850 字节。内容应该是此处指定的 gzip 压缩的 ISO5589-15 编码 XML 字符串
作为我发送的 CommandAPDU
00 B0 00 00 00
获取前 256 个字节。发送后
00 B0 00 FF 00
我得到接下来的 256 个字节。
但是我怎么得到剩下的呢?
我怎么知道二进制数据何时结束?
我正在尝试使用 javax.smartcardio读取智能卡(德语 Gesundheitskarte )
在 EF“PD”的定义中,它的长度被指定为 850 字节。内容应该是此处指定的 gzip 压缩的 ISO5589-15 编码 XML 字符串
作为我发送的 CommandAPDU
00 B0 00 00 00
获取前 256 个字节。发送后
00 B0 00 FF 00
我得到接下来的 256 个字节。
但是我怎么得到剩下的呢?
我怎么知道二进制数据何时结束?
READ BINARY
APDU 允许2个字节作为文件偏移量,在 P1 和 P2 中编码,并使用 Le 作为长度,作为READ BINARY
响应中的字节数。P1 是高字节,或最高有效字节。然而,P1 的最高位被保留以指示 P1 是否还包含一个短文件标识符。0
如果您已经在读取文件,它应该保持在值,从而使您的最大偏移量为 32Ki - 1。
我无法阅读您链接的规格,但我们假设READ BINARY
您卡上的 APDU 以相同的方式工作。
您读取前 256 个字节的命令似乎是正确的,注意这Le==0x00
表示读取了 256 个字节。
要读取从偏移量 256、512 等开始的字节,请开始递增 P1,例如:
00 B0 01 00 00
00 B0 02 00 00
00 B0 03 00 00
要读取从偏移量 257 (0x101) 开始的 256 个字节:
00 B0 01 01 00
偏移量 600 (0x258):
00 B0 02 58 00
在您的代码中,如果您使用 Javaint
来存储偏移量,您通常最终会使用以下内容递增 P1:
int offset;
int P1, P2;
while (continueReading)
{
// ...
P1 = (offset >> 8) & 0xFF;
P2 = offset & 0x00FF;
// ...
// send APDU
}
如何指示文件的大小取决于实现。通常,您可以从 EF ( ) 上的 SELECT 返回的文件控制信息 (FCI) 结构中获取文件大小00 A4 00 00 02 fileId
。然而,文件的大小也可以嵌入到文件的内容中。如果可能,您不应依赖状态字来告诉您文件的大小。
加法:Le、Ne 和奇数 INS
重要的是,您只能根据您在响应数据 (RDATA) 中实际接收到的字节数来增加偏移量。请注意,如果 P3 = Le,则 Le 编码 Ne,这是响应数据的最大大小。你收到的可能少于这个。
如果文件大小为 32Ki 或更大,则需要使用带有奇数 INS ( B7
) 的 READ BINARY 来读取 32Ki 以上的数据。在这种情况下,RDATA 也可能包含开销。显然,这反过来可能会影响偏移计算以及要读取到文件末尾的计算。
偏移量在P1
&中P2
,尽管最高位用于指示您要选择具有给定 SFI 的内容。所以你也可以使用P1
字节。之后,您将不得不向READ BINARY with an odd INS
( B1
) 移动。
因此,您最多可以使用普通读取二进制文件读取 2^15 - 1 个字节。那是 32Ki - 1。当然还有额外的几个字节,因为 APDU 返回的字节。
我总是使用以下方法从智能卡中读取文件: 1 确定文件大小,例如使用 SELECT by FILE ID ( ) 返回的 FCI(文件控制信息)00 A4 02 00 02 ${FILE_ID}
,您需要解析响应。然后每次将偏移量增加返回的字节数。永远不要询问超过最大文件大小,因为大多数卡的行为不同,没有定义或完全错误)。
进阶话题:如果使用READ BINARY with ODD INS
,每次增加offset都需要减去DO的header。在这种情况下,读到最后会有点麻烦,因为您需要将标头的开销添加到Le
字节中。
Maarten Bodewes 对 IMO 的一个小补充,非常有用的回答是关于读取更大的文件,以及 stajo 建议使用扩展 Le。我希望这可以为其他人节省一些时间和精力。
尝试使用 Le 进行长读很棘手:
除此之外,您首先需要了解该卡是否完全支持扩展Lc/Le;有关此的信息分布在 ATR 历史字节、EF.ATR 和当前 EF 信息中。
因此,虽然理论上可以从单个文件中读取大量数据,但在实践中需要付出很多努力,而且您也无法使用一个命令读取整个文件。
在您努力使用扩展 Le 进行阅读之前,请考虑以上内容。
如果卡支持它,您可能可以使用扩展长度格式。如果您在 lc/le 字段中指定 00,您可以使用以下两个字节作为长度
我尝试使用上述示例读取护照的 DG2 文件,但最后我无法获取图像文件。这是我在 kotlin 中所做的:
do {
val offsetStart = (offset shr 8) and 0xFF
val offsetEnd = offset and 0xFF
LogUtils.d(offsetStart)
LogUtils.d(offsetEnd)
var offsetStartString = if(offsetStart < 10){
"0$offsetStart"
}else {
"$offsetStart"
}
val offsetEndString = if(offsetEnd < 10){
"0$offsetEnd"
}else {
"$offsetEnd"
}
LogUtils.d(offsetStartString)
LogUtils.d("00B0${offsetStartString}${offsetEndString}00")
val commandByte = toByteArray("00B0${offsetStartString}${offsetEndString}00")
resultCommand = this.nfc.transmit(commandByte,commandByte.size)
val resultHex = StringUtil.toHexString(resultCommand)
LogUtils.d(resultHex)
baos.write(resultCommand)
offset += 1
LogUtils.d(resultCommand.size)
} while (resultCommand.size > 4)