尝试使用Java中的PC / SC阅读器(特别是ACR1222L)验证Ultralight EV1卡时遇到问题。我可以使用相应的ISO 14443-3标签APDU来编写和读取未受保护的标签。但是,我找不到运行PWD_AUTH命令的方法,因为它不是14443-3标准(或任何本机命令)的一部分。是否可以运行此命令(或任何本机命令)?
我尝试发送以下APDU {e0 00 00 24 07 1b ff ff ff ff 63 00}其中1b是本机命令,ff ff ff ff是密码,63 00是命令的CRC_A加密码。我也试过没有CRC,切换参数的顺序等,但到目前为止,我无法让它工作。
我也尝试包装APDU(如https://stackoverflow.com/a/41729534/3613883中所述)。我使用了Desfire EV1卡,但它不适用于超轻EV1(因为它显然不支持ISO7816-4)。
那么,有没有办法使用PC / SC读卡器验证Ultralight EV1卡?
答案 0 :(得分:4)
首先,MIFARE Ultralight EV1不会说APDU。相反,它使用直接基于ISO / IEC 14443-3中定义的框架的命令。由于ISO / IEC 14443-3仅定义了成帧和防冲突/枚举命令,因此任何协议(例如MIFARE Ultralight / NTAG命令集)都是专有的。
使用密码connection.end();
进行密码验证的正确命令为:
FF FF FF FF
请注意,CRC通常由非接触式前端芯片处理,因此您不需要手动处理它。
使用ACR1222L,有多种不同的方式来交换这些专有命令:
您可以使用PC_to_RDR_Escape(请注意,只有在您为阅读器安装了原始ACR驱动程序包时才可以使用它)。假设您使用的是Java Smartcard IO API,那么您可以使用byte[] tagCommand = new byte[] { (byte)0x1B, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
方法执行此操作:
Card.transmitControlCommand()
可以找到方法byte[] response = card.transmitControlCommand(SCARD_CTL_CODE(3500), command);
的定义in this post。
SCARD_CTL_CODE
需要是一个字节数组,其中包含将原始命令传递给非接触式前端芯片的伪APDU的APDU头和非接触式前端芯片的实际命令。由于ACR1222L基于NXP PN532(?),非接触式前端芯片的命令将是InDataExchange命令(参见user manual):
command
根据读者实际激活卡的方式,您可能需要使用InCommunicateThru命令而不是InDataExchange:
byte[] interfaceCommandHeader = new byte[] { (byte)0xD4, (byte)0x40, (byte)0x01 };
byte[] interfaceCommand = Arrays.copyOf(interfaceCommandHeader, interfaceCommandHeader.length + tagCommand.length);
System.arraycopy(tagCommand, 0, interfaceCommand, interfaceCommandHeader.length, tagCommand.length);
可以通过以下方式添加伪APDU标头:
byte[] interfaceCommandHeader = new byte[] { (byte)0xD4, (byte)0x42 };
byte[] interfaceCommand = Arrays.copyOf(interfaceCommandHeader, interfaceCommandHeader.length + tagCommand.length);
System.arraycopy(tagCommand, 0, interfaceCommand, interfaceCommandHeader.length, tagCommand.length);
另一种选择是使用PC_to_RDR_XfrBlock直接发送命令。这映射到Java Smartcard IO API中的byte[] commandHeader = new byte[] { (byte)0xE0, (byte)0x00, (byte)0x00, (byte)0x24, (byte)0x00 };
byte[] command = Arrays.copyOf(commandHeader, commandHeader.length + interfaceCommand.length);
System.arraycopy(interfaceCommand, 0, command, commandHeader.length, interfaceCommand.length);
command[4] = (byte)(interfaceCommand.length & 0x0FF); // update Lc field
:
CardChannel.transmit()
如果可以在该接口上使用相同的伪APDU报头,则manual of your reader不太清楚。但是,如果查看附录H,您将找到一个不同的标头,而不是包装到伪APDU(ACR122U传统模式)。所以你可以使用以下内容:
ResponseAPDU responseApdu = cardChannel.transmit(commandAPDU);
请注意,同样,您必须将tag命令包装到非接触式前端芯片的InDataExchange命令中。