【问题标题】:Control full APDU with NFC Software Card Emulation on Android在 Android 上使用 NFC 软件卡仿真控制完整的 APDU
【发布时间】:2013-05-27 12:40:06
【问题描述】:

我正忙于一个应用程序来模拟 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 没有任何额外数据)。有可能吗?

【问题讨论】:

    标签: android nfc apdu hce acr122


    【解决方案1】:

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

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

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

    在 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 与 DATA = 0x01 0x02

    > FF00000005 D440 01 0102 00
    < D541 00 0102 9000
    

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

    InDataExchange 与 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 与 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 传输协议格式)。

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

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

    【讨论】:

    • 首先,我希望能够控制的是这个状态字节(你在最后一行谈论)。当前的问题是我只能返回“成功”的 R-APDU。我希望能够以另一个状态字节而不是 00 响应(例如,使用超时 01 状态代码)。
    • 顺便说一句,这是 (mroland.at/fileadmin/mroland/tutorials/…) 你的吗?我昨天读过它,它让我认为在 Android 上通过卡模拟控制完整的 ADPU 是可能的,因为您已将 ISO-7816 智能卡列为类型 4 标记,这正是问题中的第一个链接所表明的 SCE 是可能的在 Android 上。
    • 控制完整的 APDU 是可能的(正如我在回答中所写的那样)。但是,您所指的“状态字节”不是 APDU 的一部分。该状态字节是阅读器应用程序和阅读器芯片之间通信的一部分。您无法在 APDU 级别上影响它。
    • 是的,这是我的教程。
    • 不过,模拟阅读器和 nexus 7 之间的正常通信是不可能的。当我在 IsoPcdA 上使用 transcieve 时,我提供的参数不包含 SW 字节。它们是自动添加的。当我提供 {0x01} 时,字节 {0x90, 0x00} 显示在附加到 0x01 的另一端。并且发送零长度的 APDU 也是不可能的(例如 mifare OK 进行身份验证)。你有什么解决办法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 2015-01-07
    • 1970-01-01
    • 1970-01-01
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多