ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-07-01 12:51:18  阅读:434  来源: 互联网

标签:java nfc apdu hce acr122


我有一台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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有