Используйте READ BINARY для чтения более 256 байт.

Я пытаюсь прочитать смарт-карту (немецкий Gesundheitskarte), используя javax.smartcardio

В определении EF "PD" его длина указана как 850 байт. Содержимое должно представлять собой сжатую строку XML в формате ISO5589-15, как указано здесь.

Как CommandAPDU отправляю

00 B0 00 00 00

чтобы получить первые 256 байт. После отправки

00 B0 00 FF 00

Я получаю следующие 256 байт.

Но как мне получить остальные?

Как я узнаю, когда двоичные данные закончатся?

Немецкая спецификация, часть 1 | Немецкая спецификация, часть 2


person rretzbach    schedule 02.07.2012    source источник


Ответы (5)


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

Чтобы прочитать 256 байтов, начиная со смещения 257 (0x101):

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
}

Способ указания размера файла зависит от реализации. Обычно вы можете получить размер файла из структуры информации об управлении файлами (FCI), возвращаемой SELECT в EF (00 A4 00 00 02 fileId). Однако размер файла также может быть встроен в содержимое файла. Если возможно, вы не должны полагаться на слова состояния, чтобы узнать размер файла.


Дополнение: Le, Ne и нечетные INS

Важно, чтобы вы увеличивали смещение только на количество байтов, которое вы фактически получили в данных ответа (RDATA). Обратите внимание, что если P3 = Le, то Le кодирует Ne, что является максимальным размером данных ответа. Вы можете получить меньше, чем это.

Если размер файла составляет 32 КБ или более, вам необходимо использовать READ BINARY с нечетным INS (B7), чтобы прочитать данные выше 32 КБ. В этом случае RDATA также может содержать служебные данные. Очевидно, что это, в свою очередь, может повлиять на вычисления смещения и вычисления для чтения до конца файла.

person pb2q    schedule 02.07.2012
comment
P3 - это не количество байтов, которые нужно прочитать. Он содержит Le — кодировку максимального количества байтов, которое должно быть возвращено в ответном APDU. Это почти то же самое. - person Maarten Bodewes; 02.07.2012
comment
зависит от того, кого вы спросите на самом деле. Я провел слишком много времени со спецификациями GSM, где P3 = длина, но ваша точка зрения по-прежнему хороша, большинство людей используют Le, и это понятнее. - person pb2q; 02.07.2012
comment
Это не имело в виду нападение на вашу позицию. Проблема в том, что многие создатели спецификаций не понимают разницы, поэтому по умолчанию она становится либо одной из двух (а иногда и их смесью). - person Maarten Bodewes; 02.07.2012
comment
Нисколько. Ваши комментарии полезны. На самом деле это различие, вероятно, заслуживает упоминания в вики тега [smartcard]. - person pb2q; 02.07.2012
comment
К сожалению, я сделал обширное редактирование того, что я считал своим ответом. Я надеюсь, что вы согласны с правками, в противном случае, пожалуйста, откатите их. - person Maarten Bodewes; 31.08.2015

Смещение находится в P1 и P2, хотя старший бит используется для указания того, что вы хотите выбрать что-то с данным SFI. Таким образом, вы также можете использовать P1 для байтов. После этого вам нужно будет двигаться в сторону READ BINARY with an odd INS (B1).

Таким образом, вы можете прочитать до 2 ^ 15 - 1 байт, используя обычный двоичный файл чтения. Это 32Ki - 1. И, конечно же, несколько дополнительных байтов из-за байтов, возвращаемых APDU.

Я всегда считывал файлы со смарт-карт следующим образом: 1 определял размер файла, т.е. используя FCI (информацию об управлении файлами), возвращенную с помощью SELECT по идентификатору файла (00 A4 02 00 02 ${FILE_ID}), вам необходимо проанализировать ответ. Затем каждый раз увеличивайте смещение на количество возвращенных байтов. Никогда не запрашивайте больше максимального размера файла, так как поведение большинства карт отличается, не определено или просто неправильно).

Дополнительная тема: Если вы используете READ BINARY with ODD INS, вам нужно вычитать заголовок DO каждый раз, когда вы увеличиваете смещение. В этом случае чтение до конца становится немного проблематичным, потому что вам нужно будет добавить служебные данные заголовка к байту Le.

person Maarten Bodewes    schedule 02.07.2012
comment
Обратите внимание, что эту информацию можно найти в ISO 7816-4. Это платное ПО, но обычно вы можете найти спецификацию нелегально бесплатно или извлечь информацию из других библиотек. Если вы создаете коммерческое программное обеспечение, купите спецификацию! - person Maarten Bodewes; 02.07.2012

Небольшое дополнение к очень полезному ответу IMO от Maarten Bodewes о чтении больших файлов и предложение stajo использовать расширенный Le. Я надеюсь, что это сэкономит другим время и усилия.

Попытка использовать Le для длинных чтений сложна:

  • Расширенный Le также требует использования расширенного Lc.
  • Расширенный Lc не должен быть равен 0, согласно стандарту, поэтому вы не можете начать со смещения 0.
  • И если ваш Lc не равен 0, вам нужно использовать ИНС "B1".
  • Затем B1 немного усложняет расчет правильных размеров, как объяснил Маартен Бодевес.

Кроме того, вам нужно сначала выяснить, поддерживает ли карта расширенный Lc/Le вообще; информация об этом распределяется по байтам истории ATR, EF.ATR и текущей информации EF.

Таким образом, хотя теоретически возможно читать большие пакеты данных из одного файла, на практике это требует больших усилий, и вы также не можете прочитать весь файл с помощью одной команды.

Рассмотрите вышеизложенное, прежде чем пытаться использовать расширенный Le для чтения.

person JWnxp    schedule 31.08.2015

если карта поддерживает это, вы, вероятно, можете использовать формат расширенной длины. если вы укажете 00 в поле lc/le, вы можете использовать два следующих байта для длины

person stajo    schedule 09.08.2013

Я попытался в приведенном выше примере прочитать файл паспорта 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)
person kouadio figux    schedule 19.01.2020