我有一个安装了ACR122驱动程序的ACR122U NFC读写器连接到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
I guess 01020304
is the UID presented by my Android device to the NFC reader. The SELECT APDU returns no response, it's 0 bytes long.
On my Android device I have this service:
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):
使用第二个阅读器(相同型号,相同版本)进行的测试才起作用。因此,第一个阅读器上的设置可能有些晦涩,或者阅读器刚出现故障。
两种阅读器具有相同的版本信息:
最佳答案
您使用InListPassiveTarget直接指示ACR122U内部的PN532 NFC芯片手动轮询标签。这实际上绕过了ACR122U的抽象层,允许您自动轮询标签并使用“标准PC / SC”与枚举的智能卡交换APDU命令。因此,无法通过PC / SC接口发送普通APDU,并且SELECT APDU将永远不会到达Android HCE端。
相反,您还需要通过直接与PN532传输模块对话来交换APDU命令。您可以通过将APDU命令包装在InDataExchange命令(或InCommunicateThru,如果您需要控制ISO / IEC 14443-4标头字段)中来完成此操作。在您的情况下,包装的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在该读取器的不同版本之间发生了巨大变化,这使得对该设备进行编程变得很困难。
更新:更多观察结果...
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);
0803
看起来很奇怪。尤其是在位帧防冲突字段中的0x03表示该字段中有多个目标(因为符合标准的标签只会在位帧防冲突字段中设置单个位)。请注意,这是不正确的。在对InListPassiveTarget的响应中,ATQA的发送顺序为低位优先。因此,位帧防冲突值是0x08(=有效/兼容),专有字段中的值是0x03。 32010607
看起来不错)是很奇怪的。我已经用另一个ACR122U测试了一些失败的命令,它们已成功完成...