APDU считывателя NFC «SELECT (by AID)» не направляется на устройство Android - PullRequest
0 голосов
/ 13 мая 2018

У меня есть устройство чтения / записи ACR122U NFC, подключенное к моей машине Windows с установленным драйвером ACR122.

Я пытаюсь использовать javax.smartcardio API для отправки ADECT (SELECT) по AID на мое устройство Android (котороедолжен быть в режиме HCE).

Это мой код:

TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
CardTerminal terminal = terminals.get(0);
System.out.println(terminal.getName());
Card card = terminal.connect("*");
CardChannel channel = card.getBasicChannel();
execute(channel, new byte[] { (byte) 0xFF, 0x00, 0x51, (byte) 195, 0x00}, card);
execute(channel, new byte[] { (byte)0xFF, 0x00, 0x00, 0x00, 0x04,(byte)0xD4, 0x4A, 0x01, 0x00}, card); //InListPassiveTarget
execute(channel, new byte[] { (byte)0xFF, 0x00, 0x00, 0x00, 0x04,(byte)0xD4, 0x4A, 0x01, 0x00}, card); //InListPassiveTarget
execute(channel, new byte[] {0x00, (byte) 0xA4, 0x04, 0x00, 7,
                (byte)0xF0, 0x01, 0x02, 0x03, 0x04, (byte) 0x05, 0x07, 0}, card); //select AID

...

public static void execute(CardChannel channel, byte[] command, Card...cards) throws CardException {
    ByteBuffer r = ByteBuffer.allocate(1024);
    channel.transmit(bufferFromArray(command), r);
    System.out.println(convertBinToASCII(r.array(), 0, r.position()));
}

Это вывод, который я получаю:

ACS ACR122 0
3B8F8001804F0CA000000306030000000000006B
C3
D54B6300
D54B010108032004010203049000

Я думаю, 01020304 этоUID, представленный моим устройством Android для считывателя NFC.SELECT APDU не возвращает ответа, его длина составляет 0 байт.

На моем устройстве Android у меня есть эта служба:

public class MyHostApduService extends HostApduService {

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("APDU", "APDU service was created.");
    }

    @Override
    public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
       Log.e("APDU", "command apdu: " + Arrays.toString(apdu));
       return new byte[2];
    }
    @Override
    public void onDeactivated(int reason) {
       Log.e("APDU", "ON DEACTIVATED.");
    }
}

Но processCommandAdpu не вызывается.Просматривая журналы, я ничего не смог найти, когда якобы SELECT ADPU отправлен читателю, поэтому кажется, что ADPU даже не попадает на устройство Android.

Это файл apduservice.xml для проекта Android:

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/servicedesc"
    android:requireDeviceUnlock="false" >
    <aid-group
        android:category="other"
        android:description="@string/aiddescription" >
        <aid-filter android:name="F0010203040507" />
    </aid-group>
</host-apdu-service>

Кроме того, есть несколько ADPU, которые при передаче вызывают застревание считывателя NFC.Например,

execute(channel, new byte[] {(byte) 0xFF, 0x00, 0x00, 0x00, 0x02, (byte) 0xd4, 0x04}, card);

, который является псевдо-APDU для запроса текущего состояния микросхемы PN532, не возвращает никакого ответа.Может ли быть так, что этот конкретный читатель имеет недостатки?Как я могу это проверить?


ОБНОВЛЕНИЕ (на основе обсуждение в чате ):

Тест со вторым читателем (та же модель, та же версия) простоработал.Так что это могут быть некоторые неясные настройки на первом считывателе или считыватель просто неисправен.

Оба считывателя имеют одинаковую информацию о версии:

  • Версия прошивки ACR122U: 41435231323255323135 (->ACR122U215)
  • Версия PN532: D503 32010607 9000 (-> PN532 v1.6)

1 Ответ

0 голосов
/ 22 мая 2018

Вы использовали InListPassiveTarget, чтобы напрямую проинструктировать микросхему NFC PN532 внутри ACR122U вручную запрашивать теги. По сути, это обходит уровни абстракции ACR122U, которые позволяют автоматически запрашивать теги и использовать «стандартный ПК / SC» для обмена командами APDU с перечисляемой смарт-картой. Следовательно, отправка простых APDU через интерфейс ПК / SC не будет работать, и SELECT APDU никогда не будет поступать на сторону Android HCE.

Вместо этого вам также нужно будет обмениваться командами APDU, напрямую общаясь с модулем передачи PN532. Вы можете сделать это, поместив команду APDU в команду InDataExchange (или InCommunicateThru, если вам нужен контроль над полями заголовков ISO / IEC 14443-4). В вашем случае обернутая команда SELECT (по AID) APDU будет выглядеть примерно так:

execute(channel, new byte[] {
    (byte)0xFF, 0x00, 0x00, 0x00,  // direct PN532 command
    16,                // Lc = command length
    (byte)0xD4, 0x40,  // InDataExchange
    0x01,              // Tag #1 (equal to the tag number from the InListPassiveTarget response)
    0x00, (byte)0xA4, 0x04, 0x00,                         // APDU: SELECT (by AID)
          7,                                              // Lc = AID length
          (byte)0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, // AID = F0010203040507
          0x00,                                           // Le = max
}, card);

Может быть, этот конкретный читатель имеет недостатки?

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

ОБНОВЛЕНИЕ: Еще несколько замечаний ...

  • Ответ на команду InListPassiveTarget не содержит данных ATS (после поля UID). Возможно, ваш читатель не выполняет автоматические RATS во время выбора тегов. Это можно включить с помощью команды SetParameters (перед InListPassiveTarget):

    execute(channel, new byte[] {
        (byte)0xFF, 0x00, 0x00, 0x00,  // direct PN532 command
        3,                 // Lc = command length
        (byte)0xD4, 0x12,  // InDataExchange
        (1<<4),            // fAutomaticRATS = 1
    }, card);
    

    Вы также можете попробовать вручную отправить команду RATS с помощью InCommunicateThru:

    execute(channel, new byte[] {
        (byte)0xFF, 0x00, 0x00, 0x00,  // direct PN532 command
        4,                 // Lc = command length
        (byte)0xD4, 0x42,  // InCommunicateThru
        (byte)0xE0, 0x80,  // RATS (FSD = 256, CID = 0)
    }, card);
    

    После этого вы можете попытаться связаться с картой, используя InCommunicateThru и необработанные блоки ISO / IEC 14443-4:

    execute(channel, new byte[] {
        (byte)0xFF, 0x00, 0x00, 0x00,  // direct PN532 command
        16,                // Lc = command length
        (byte)0xD4, 0x42,  // InCommunicateThru
        0x02,              // PCB (I-block, change to 0x03 for the next block)
        0x00, (byte)0xA4, 0x04, 0x00,                     // APDU: SELECT (by AID)
          7,                                              // Lc = AID length
          (byte)0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, // AID = F0010203040507
          0x00,                                           // Le = max
    }, card);
    
  • ATQA 0803 выглядит довольно странно. В частности, значение 0x03 в поле антиколлизии битового кадра предполагает, что в этом поле имеется более одной цели (поскольку совместимый со стандартом тег будет устанавливать только один бит в поле антиколлизии битового кадра). Обратите внимание, что это не правда. ATQA в ответе на InListPassiveTarget передается с прямым порядком байтов. Следовательно, значение антиколлизии битового кадра равно 0x08 (= действительный / соответствует), а значение в собственном поле - 0x03.

  • Действительно, странно, что ваш ридер не отвечает на определенные команды PN532 (особенно потому, что версия прошивки 32010607 выглядит нормально). Я проверил некоторые команды, которые вы не смогли выполнить с другим ACR122U, и они успешно выполнены ...

...