使用READ BINARY读取超过256个字节

时间:2012-07-02 16:49:11

标签: java smartcard

我正在尝试使用javax.smartcardio

读取智能卡(German Gesundheitskarte

在EF“PD”的definition中,其长度指定为850字节。内容应为指定here

的gzip压缩ISO5589-15编码XML字符串

作为CommandAPDU,我发送

00 B0 00 00 00

获取前256个字节。 发送后

00 B0 00 FF 00

我接下来的256个字节。

但我怎么得到其余的?

我如何知道二进制数据何时结束?

German Specification Part 1 | German Specification Part 2

5 个答案:

答案 0 :(得分:10)

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

在您的代码中,如果您使用Java int来存储偏移量,那么通常会以这样的方式递增P1:

int offset;
int P1, P2;

while (continueReading)
{
    // ...
    P1 = (offset >> 8) & 0xFF;
    P2 = offset & 0x00FF;
    // ...
    // send APDU
}

如何指示文件的大小取决于实现。通常,您可以从EF(00 A4 00 00 02 fileId)上的SELECT返回的文件控制信息(FCI)结构中获取文件大小。但是,文件的大小也可以嵌入文件的内容中。如果可能,您不应该依赖状态字来告诉您文件的大小。


加法:Le,Ne和奇数INS

重要的是,您只需使用响应数据(RDATA)中实际接收的字节数来增加偏移量。请注意,如果P3 = Le,则Le编码Ne,这是响应数据的最大大小。你可能收到的不到那个。

如果文件大小为32Ki或更大,则需要使用带有奇数INS(B7)的READ BINARY来读取32Ki以上的数据。在这种情况下,RDATA也可能包含开销。显然, - 反过来 - 可能会影响偏移计算和读取到文件末尾的计算。

答案 1 :(得分:5)

偏移量位于P1& P2,尽管最高位用于表示您要选择具有给定SFI的内容。因此,您也可以使用P1作为字节。之后,您将不得不转向READ BINARY with an odd INSB1)。

因此,您可以使用正常读取二进制读取最多2 ^ 15 - 1个字节。那是32Ki - 1.当然还有几个字节,因为APDU返回了字节。

我总是会使用以下方法从智能卡中读出文件:1确定文件大小,例如使用带有SELECT by FILE ID(00 A4 02 00 02 ${FILE_ID})返回的FCI(文件控制信息),您需要解析响应。然后每次增加偏移量返回的字节数。永远不要问超过最大文件大小,因为大多数卡的行为不同,没有定义或只是完全错误。)

高级主题: 如果使用READ BINARY with ODD INS,则每次增加偏移量时都需要减去DO的标题。在这种情况下,读到最后会变得有点麻烦,因为您需要将标头的开销添加到Le字节。

答案 2 :(得分:1)

IMO对IMO的一个小补充非常有用的答案是Maarten Bodewes关于阅读更大的文件,以及stajo建议使用扩展的Le。 我希望这能为他人节省一些时间和精力。

尝试使用Le进行长读取非常棘手:

  • Extended Le也需要使用扩展Lc。
  • 根据标准,扩展Lc不能为0,因此您无法从偏移0开始
  • 如果你的Lc不是0,你需要使用" B1" INS。
  • 然后,正如Maarten Bodewes解释的那样,B1计算正确的尺寸要复杂一些。

除此之外,您需要先了解该卡是否支持扩展Lc / Le;有关此信息的信息分布在ATR历史字节,EF.ATR和当前EF信息上。

因此,虽然理论上可以从单个文件中读取大批量数据,但在实践中需要付出很多努力,而且您无法使用一个命令读取整个文件。

在您努力使用扩展Le进行阅读之前,请考虑以上内容。

答案 3 :(得分:0)

如果卡支持它,您可能可以使用扩展长度格式。 如果在lc / le字段中指定00,则可以使用以下两个字节作为长度

答案 4 :(得分:0)

我尝试上述示例读取护照的DG2文件,但最后, 我无法获取图像文件。这是我在科特林所做的事情:

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)