Android NfcA Transceive成功失败

时间:2013-11-30 21:32:08

标签: android nfc apdu contactless-smartcard

我做了一个简单的测试应用程序,用于快速调试。我发送一些字节,打印我在手机屏幕上发送的内容并打印我收到的内容。

当我发送WRONG命令时,我在两个字节SW1SW2中得到相应的错误代码。 我也可以调用我自己的命令并用我自己的值覆盖SW1SW2,我可以得到它们。

问题在于:当我发送CORRECT命令时,收发命令失败并显示信息异常“Transceive failed”。

如果我发送了正确的命令,但是将SW1SW2覆盖到90 00以外的其他值,那么我得到我设置的SW值,但没有响应数据。 (可能是因为当SW1SW2<> 90 00时卡不发送ODATA)

那么为什么我如此确定我发送了正确的命令呢?除了搞乱我自己的测试命令之外,我调用了GetAppId命令 - 它说我必须在卡中定义AppId。 所以我在卡中定义它,发送相同的命令并收发失败。

所以我很确定问题是当有ODATA时收发失败,但我不明白为什么或如何修复它..请帮忙!

编辑:我的卡是ZeitControl的7.5 D非接触式基本卡。

EDIT2:我已将超时设置为2000毫秒,但行为没有变化。我正在尝试返回一个字节的数据,而我调用的系统命令听起来也不重。

然后我下载并附加了Android源码并进行了调试。有一些段仍然没有进入 - 但卡似乎在有效命令上返回null,除非我返回一些手动设置SW1SW2,在这种情况下,这是唯一收到的。

EDIT3:我试过的系统命令是: 192 14 0 0 0 (或C0 0E 00 00 00) (或CLA INS P1 P2 Lc) 我不是100%肯定我正确地做了那个,但是我尝试了不同长度(最多22个)Le和没有Le如上所述并且没有它不给我6700(错误的Le / Lc) 当然,而不是6700,它似乎返回null ...

另一个命令是我自己定义的20 0A(值为Byte),并且在.BAS文件中没有指定P1 / P2。 我叫那个: 32 10 1 0 1 (或20 0A 01 00 01) (或CLA INS Lc IDATA Le) 这应该意味着1字节数据输入,设置为0,预期输出1字节(一如既往地+ SW1 / SW2)。 (设置P1 / P2给出6700所以除非在命令声明中定义我不认为它们应该在那里) 这也返回null。我期待00 90 00在这里归还。 (如果我将“值”设置为00)

我正在使用HTC One X.

EDIT4: MinSdk版本= 14,目标18。

if(bitcoinCard  != null){
try {
    String sentmsg, receivedmsg;
    byte[] send = getBytes(commandBytes.getText().toString());
    byte[] data = null;
    if(send != null){
        bitcoinCard.setTimeout(2000);
        data = bitcoinCard.transceive(send);
}
        //bitcoinCard.close();
        /*if(data != null && data.length == 2)
        {
            mainLabel.setText("SW1SW2: " + (data[0] < 0 ? -data[0] + 
128 : data[0]) + " " + (data[1] < 0 ? -data[1] + 128 : data[1]));
        }else */if (data != null && send != null)
        {
            sentmsg = "" + (send[0] < 0 ? send[0] + 256 : send[0]);
            for(int i = 1; i < send.length; i++)
            {
                sentmsg = sentmsg + " " + (send[i] < 0 ? send[i] + 
256 : send[i]);
            }
            receivedmsg = "" + (data[0] < 0 ? data[0] + 256 : data[0]);
            for(int i = 1; i < data.length; i++)
            {
                receivedmsg = receivedmsg + " " + (data[i] < 0 ? data[i] + 256 : data[i]);
            }
            mainLabel.setText("Sent: " + sentmsg + "\n" +
                              "Response: " + 
receivedmsg);
        }else
        {
            mainLabel.setText("Sent or received null.");
        }
    } catch (IOException e) {

        mainLabel.setText("Tried to talk to card, but had error: " + 
e.getMessage());
    }   
}

1 个答案:

答案 0 :(得分:2)

首先,当您发送APDU时,您应该使用IsoDep对象(而不是NfcA)。 Android应该显示可用于您的卡的两种标记技术。这里的问题是,如果您使用IsoDep,Android通常只会在ISO 14443-4协议模式下激活卡。因此,当我们使用NfcA时,您的卡将无法接受APDU。

我刚刚测试过,至少在使用Android 4.1.2的Nexus S上就是这种情况。事实上,尝试使用NfcA对象进行收发会导致TagLostException s带有一些卡片以及其他一些我尝试过的卡片的奇怪行为。

其次,如果你发送

byte[] cmd = { (byte)0xC0, (byte)0x0E, (byte)0x00, (byte)0x00, (byte)0x00 };

我希望该卡能够返回实际的应用程序ID。但是,此命令的答案(即<data> <SW1=61> <SW2=len>)不符合ISO 7816-4(61xx状态代码不应返回任何数据),因此这可能会导致问题。

更新:我刚刚使用Nexus S(Android 4.1.2)对此进行了测试,并且收到此类回复并不是问题。

最后,您的其他命令(20 0A)不符合您的预期:

  1. 我强烈建议您只使用设置为0x000x80的CLA字节,除非您知道自己在做什么(使用安全消息,使用逻辑通道,......)。虽然,Android(至少使用恩智浦的NFC芯片组)并不关心APDU的结构,但你的卡可能会这样!
  2. APDU的格式始终为<CLA> <INS> <P1> <P2> [Lc [DATA]] <Le>(特殊情况为<CLA> <INS> <P1> <P2>)。所以这意味着你不能简单地省略P1和P2。
  3. 你是正确的,如果SW&lt;&gt; 9000和SW1&lt;&gt; 61,BasicCard将丢弃ODATA。