我正忙于使用应用程序模拟 Nexus 7 上的 CM10.1 与 ACR122U102 读写器的正常 APDU 通信。我找到了这个关于 software card emulation 的博客,并编写了一个应用程序,让我的设备(nexus)显示为卡片。现在我正在尝试在此设备和 ACR122u 之间来回发送消息。到目前为止,我只能通过发送 D4 40 01(InDataExchange 第 127 页)APDU 来与 nexus 7 进行通信。对于我正在编写的应用程序,这应该足够了。

问题在于我从设备发送给阅读器的答案。使用 transcieve 函数(带有反射的 android.nfc.tech.IsoPcdA),我可以使用长度 > 0 的字节数组进行回复。这会像正常的 InDataExchange 响应一样显示在读取器端(例如:D5 41 00 01 02 03 和 {01 02 03 } 是提供给 transcieve 函数的字节数组)。但是我无法控制响应中的状态字节和 SW 字节(D5 41 XX 和两个 SW)。除了源代码本身之外,没有关于这个 IsoPcdA 类的文档。

我想要做的是将 XX 更改为我选择的字节并发送长度 = 0 的答案(例如:D5 41 01 没有任何额外数据)。是否可以?

最佳答案

我不太确定你在这里想要实现什么。无论您使用 IsoPcdA 的收发方法收发什么,都是完整的 APDU(如 ISO/IEC 7816-4 中所定义,或者更确切地说是 ISO-DEP 传输协议(protocol)中的任何 PDU)。所以transceive的返回值是一个完整的C-APDU(命令APDU),transceive的字节数组参数是一个完整的R-APDU(响应APDU),包括状态字的两个字节(SW1 | SW2)。因此,该参数的最后两个字节是状态字。在您的示例中,SW1 为 02,SW2 为 03。

您在 PN532 NFC Controller 的 InDataExchange 命令中看到的状态字节不是 APDU 的状态字,而是 PN532 NFC Controller 内命令执行的状态。此状态字节为您提供有关缓冲区溢出、通信超时等的信息,而不是卡端返回的信息。

编辑:示例代码 + 测试命令:

在 Galaxy Nexus (CM 10) 上运行的示例代码:

try {
  Class isoPcdA = Class.forName("android.nfc.tech.IsoPcdA");
  Method isoPcdA_get = isoPcdA.getDeclaredMethod("get", Tag.class);

  final IsoPcdA techIsoPcdA = (IsoPcdA)isoPcdA_get.invoke(null, tag);

  if (techIsoPcdA != null) {
    if (mWorker != null) {
      mInterrupt = true;
      mWorker.interrupt();
      try {
        mWorker.join();
      } catch (Exception e) {}
    }

    mInterrupt = false;
    mWorker = new Thread(new Runnable() {
      public void run () {
        try {
          techIsoPcdA.connect();

          byte[] command = techIsoPcdA.transceive(new byte[]{ (byte)0x90, (byte)0x00 });
          Log.d(CardEmulationTest.class.getName(), "Connected.");

          while (!mInterrupt) {
            Log.d(CardEmulationTest.class.getName(), "C-APDU=" + StringUtils.convertByteArrayToHexString(command));
            command = techIsoPcdA.transceive(command);
          }
        } catch (Exception e) {
          Log.e(CardEmulationTest.class.getName(), "Exception while communicating on IsoPcdA object", e);
        } finally {
          try {
            techIsoPcdA.close();
          } catch (Exception e) {}
        }
      }
    });

    mWorker.start();
  }
} catch (Exception e) {
  Log.e(CardEmulationTest.class.getName(), "Exception while processing IsoPcdA object", e);
}

测试(使用 ACR122U):

InListPassivTargets(1 个目标 106kbps)
> FF00000004 D44A 0100 00
< D54B 010100046004088821310578338800 9000

InDataExchange 与 DATA = 0x01
> FF00000004 D440 01 01 00
< D541 00 01 9000

所以我们从读卡器得到一个错误代码 0x00(InDataExchange 命令的状态;不是实际响应 APDU 的一部分),我们得到 0x01 作为响应(这是 IsoDepA 响应 APDU),我们得到 0x9000 作为状态代码读卡器包装 APDU(不是实际响应 APDU 的一部分)。

InDataExchange with DATA = 0x01 0x02
> FF00000005 D440 01 0102 00
< D541 00 0102 9000

所以我们从读卡器得到一个错误代码 0x00(InDataExchange 命令的状态;不是实际响应 APDU 的一部分),我们得到 0x01 0x02 作为响应(这是 IsoDepA 响应 APDU),我们得到 0x9000 作为状态代码用于读卡器包装 APDU(不是实际响应 APDU 的一部分)。

InDataExchange with DATA = 0x01 0x02 0x03
> FF00000006 D440 01 010203 00
< D541 00 010203 9000

所以我们从读卡器得到一个错误代码 0x00(InDataExchange 命令的状态;不是实际响应 APDU 的一部分),我们得到 0x01 0x02 0x03 作为响应(这是 IsoDepA 响应 APDU),我们得到 0x9000 作为状态读卡器包装 APDU 的代码(不是实际响应 APDU 的一部分)。

InDataExchange with DATA = 0x01 0x02 0x03 0x04
> FF00000007 D440 01 01020304 00
< D541 00 01020304 9000

所以我们从读卡器中得到一个错误代码 0x00(InDataExchange 命令的状态;不是实际响应 APDU 的一部分),我们得到 0x01 0x02 0x03 0x04 作为响应(这是 IsoDepA 响应 APDU),我们得到 0x9000 作为响应读卡器包装器 APDU 的状态代码(不是实际响应 APDU 的一部分)。

因此,我们准确地获得了作为命令 APDU 作为响应 APDU 发送的数据(请注意,这些 APDU 中没有一个是根据 ISO 7816-4 格式化的,但这并不重要,因为 IsoPcdA 卡仿真适用于任何 ISO 14443-4 传输协议(protocol)格式)。

0x9000 状态码属于读卡器 APDU 封装(CLA=FF INS=00 P1P2=0000 Lc [PN542 COMMAND] Le=00),这是通过 CCID (PC/SC) 接口(interface)访问 ACR122U 的 PN532 所必需的。这些是纯粹的阅读器命令封装,与通过 ISO-DEP 的通信无关。

D440 01 [DATA] 是通过 ISO-DEP 交换数据(例如 APDU)的 PN532 命令,D541 00 [DATA] 是相关响应。

关于android - 在 Android 上使用 NFC 软件卡模拟控制完整的 APDU,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16773439/

10-10 00:46