NFC reader "SELECT (by AID)" APDU 未路由到 Android 设备
NFC reader "SELECT (by AID)" APDU is not routed to Android device
我有一个 ACR122U NFC reader/writer 连接到我的 Windows 安装了 ACR122 驱动程序的机器。
我尝试使用 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
我猜 01020304
是我的 Android 设备提供给 NFC reader 的 UID。 SELECT APDU return 没有响应,长度为 0 个字节。
在我的 Android 设备上我有这项服务:
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 被发送到 reader 时,通过日志我无法找到任何东西,所以看起来 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 reader 有点卡住。例如,
execute(channel, new byte[] {(byte) 0xFF, 0x00, 0x00, 0x00, 0x02, (byte) 0xd4, 0x04}, card);
这是一个查询PN532芯片当前状态的伪APDU,return没有任何响应。难道这个 reader 有缺陷?我怎样才能检查它?
更新(基于discussion in chat):
用第二个 reader(相同型号,相同版本)进行的测试刚刚成功。所以它可能是第一个 reader 上的一些模糊设置,或者 reader 只是出现故障。
两个reader的版本信息相同:
- ACR122U 固件版本:41435231323255323135 (-> ACR122U215)
- PN532 版本:D503 32010607 9000 (-> PN532 v1.6)
您使用InListPassiveTarget 直接指示ACR122U 内部的PN532 NFC 芯片手动轮询标签。这实质上绕过了 ACR122U 的抽象层,允许您自动轮询标签并使用 "standard PC/SC" 与枚举的智能卡交换 APDU 命令。因此,通过 PC/SC 接口发送普通 APDU 将不起作用,并且 SELECT APDU 永远不会到达 Android HCE 端。
相反,您还需要通过直接与 PN532 传输模块对话来交换 APDU 命令。您可以通过将 APDU 命令包装在 InDataExchange 命令中(或者 InCommunicateThru,如果您需要控制 ISO/IEC 14443-4 header 字段)来做到这一点。在您的情况下,包装的 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);
会不会是这个reader有问题?
是的,可能是这种情况,但我对此表示怀疑。请注意,ACR122U 固件有许多不同版本,其中大多数似乎存在设计缺陷。特别是 reader 的某些版本执行自动标记枚举而某些版本不执行,并且可用的 API 在 reader 的不同版本之间发生了巨大变化,这使得难以为之编程那个设备。
更新:更多观察结果...
InListPassiveTarget 命令的响应不包含ATS 数据(在UID 字段之后)。也许您的 reader 在标签选择期间没有执行自动 RATS。这可以使用 SetParameters 命令启用(在 InListPassiveTarget 之前):
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);
ATQA 0803
看起来很奇怪。特别是位帧防冲突字段中的 0x03 表明该字段中有多个目标(因为符合标准的标签只会在位帧防冲突字段中设置一个位)。 请注意,这不是真的。对 InListPassiveTarget 的响应中的 ATQA 是小端传输的。因此,位帧防冲突值为 0x08 (= valid/compliant),专有字段中的值为 0x03.
您的 reader 不响应某些 PN532 命令确实很奇怪(特别是因为固件版本 32010607
看起来不错)。我已经用另一个 ACR122U 测试了一些对您失败的命令,它们成功完成了...
我有一个 ACR122U NFC reader/writer 连接到我的 Windows 安装了 ACR122 驱动程序的机器。
我尝试使用 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
我猜 01020304
是我的 Android 设备提供给 NFC reader 的 UID。 SELECT APDU return 没有响应,长度为 0 个字节。
在我的 Android 设备上我有这项服务:
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 被发送到 reader 时,通过日志我无法找到任何东西,所以看起来 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 reader 有点卡住。例如,
execute(channel, new byte[] {(byte) 0xFF, 0x00, 0x00, 0x00, 0x02, (byte) 0xd4, 0x04}, card);
这是一个查询PN532芯片当前状态的伪APDU,return没有任何响应。难道这个 reader 有缺陷?我怎样才能检查它?
更新(基于discussion in chat):
用第二个 reader(相同型号,相同版本)进行的测试刚刚成功。所以它可能是第一个 reader 上的一些模糊设置,或者 reader 只是出现故障。
两个reader的版本信息相同:
- ACR122U 固件版本:41435231323255323135 (-> ACR122U215)
- PN532 版本:D503 32010607 9000 (-> PN532 v1.6)
您使用InListPassiveTarget 直接指示ACR122U 内部的PN532 NFC 芯片手动轮询标签。这实质上绕过了 ACR122U 的抽象层,允许您自动轮询标签并使用 "standard PC/SC" 与枚举的智能卡交换 APDU 命令。因此,通过 PC/SC 接口发送普通 APDU 将不起作用,并且 SELECT APDU 永远不会到达 Android HCE 端。
相反,您还需要通过直接与 PN532 传输模块对话来交换 APDU 命令。您可以通过将 APDU 命令包装在 InDataExchange 命令中(或者 InCommunicateThru,如果您需要控制 ISO/IEC 14443-4 header 字段)来做到这一点。在您的情况下,包装的 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);
会不会是这个reader有问题?
是的,可能是这种情况,但我对此表示怀疑。请注意,ACR122U 固件有许多不同版本,其中大多数似乎存在设计缺陷。特别是 reader 的某些版本执行自动标记枚举而某些版本不执行,并且可用的 API 在 reader 的不同版本之间发生了巨大变化,这使得难以为之编程那个设备。
更新:更多观察结果...
InListPassiveTarget 命令的响应不包含ATS 数据(在UID 字段之后)。也许您的 reader 在标签选择期间没有执行自动 RATS。这可以使用 SetParameters 命令启用(在 InListPassiveTarget 之前):
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);
ATQA请注意,这不是真的。对 InListPassiveTarget 的响应中的 ATQA 是小端传输的。因此,位帧防冲突值为 0x08 (= valid/compliant),专有字段中的值为 0x03.0803
看起来很奇怪。特别是位帧防冲突字段中的 0x03 表明该字段中有多个目标(因为符合标准的标签只会在位帧防冲突字段中设置一个位)。您的 reader 不响应某些 PN532 命令确实很奇怪(特别是因为固件版本
32010607
看起来不错)。我已经用另一个 ACR122U 测试了一些对您失败的命令,它们成功完成了...