我做了一个简单的测试应用程序,用于快速调试。我发送一些字节,打印我在手机屏幕上发送的内容并打印我收到的内容。
当我发送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());
}
}
答案 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
)不符合您的预期:
0x00
或0x80
的CLA字节,除非您知道自己在做什么(使用安全消息,使用逻辑通道,......)。虽然,Android(至少使用恩智浦的NFC芯片组)并不关心APDU的结构,但你的卡可能会这样!<CLA> <INS> <P1> <P2> [Lc [DATA]] <Le>
(特殊情况为<CLA> <INS> <P1> <P2>
)。所以这意味着你不能简单地省略P1和P2。