编程语言
首页 > 编程语言> > java – NFC阅读器“SELECT(通过AID)”APDU不会路由到Android设备

java – NFC阅读器“SELECT(通过AID)”APDU不会路由到Android设备

作者:互联网

我有一台ACR122U NFC读写器连接到安装了ACR122驱动程序的Windows机器.

我尝试使用javax.smartcardio API将SELECT(通过AID)ADPU发送到我的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是我的Android设备向NFC阅读器呈现的UID. 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设备.

这是Android项目的apduservice.xml:

<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);

这是一个查询PN532芯片当前状态的伪APDU,不会返回任何响应.难道这个特定的读者有缺陷吗?我怎么检查呢?

更新(基于discussion in chat):

使用第二个阅读器(相同型号,相同版本)进行测试.所以它可能是第一个读者的一些模糊设置或读者只是出现故障.

两个读者都有相同的版本信息:

> ACR122U固件版本:41435231323255323135( – > ACR122U215)
> PN532版本:D503 32010607 9000( – > PN532 v1.6)

解决方法:

您使用InListPassiveTarget直接指示ACR122U内的PN532 NFC芯片手动轮询标签.这基本上绕过了ACR122U的抽象层,允许您自动轮询标签并使用“标准PC / SC”与枚举的智能卡交换APDU命令.因此,通过PC / SC接口发送普通APDU将无法工作,SELECT APDU将永远不会到达Android HCE端.

相反,您还需要通过直接与PN532传输模块通信来交换APDU命令.您可以通过在InDataExchange命令中包装APDU命令来实现此目的(如果需要控制ISO / IEC 14443-4标头字段,则可以使用InCommunicateThru).在您的情况下,包装的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);

您还可以尝试使用InCommunicateThru手动发送RATS命令:

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表明该字段中存在多于一个目标(因为符合标准的标记仅在位帧防冲突字段中设置单个位).请注意,事实并非如此.响应InListPassiveTarget的ATQA是以little endian传输的.因此,位帧防冲突值为0x08(=有效/兼容),并且专有字段中的值为0x03.
>确实,您的读者对某些PN532命令没有响应(特别是因为固件版本32010607看起来很好),这确实很奇怪.我用另一台ACR122U测试了一些失败的命令,并且它们成功完成了……

标签:java,nfc,apdu,hce,acr122
来源: https://codeday.me/bug/20190701/1347056.html