我有一个问题,试图使用Java中使用PC/SC读取器(特别是ACR1222L)来验证超级EV1卡。我能够使用ISO 14443-3标签的相应APDU在未受保护的标签上编写和阅读。但是,我找不到运行PWD_AUTH命令的方法,因为它不是14443-3标准的一部分(或任何本机命令)。是否可以运行此命令(或任何本地命令)?
我尝试发送以下apdu {e0 00 00 24 07 1b ff ff ff ff ff ff ff 63 00}其中1b是本机命令,ff ff ff ff ff ff是密码,而63 00是命令加密码的CRC_A。我也尝试过没有CRC,切换参数的顺序等。但是到目前为止,我无法正常工作。
我还尝试包装APDU(如https://stackoverflow.com/a/41729534/3613883中所述)。我让它与Desfire EV1卡一起使用,但它不适用于Ultralight EV1(显然它不支持ISO7816-4)。
那么,有没有一种方法可以使用PC/SC读取器对超轻质EV1卡进行身份验证?
首先,mifare Ultralight EV1不会说apdus。相反,它直接使用基于ISO/IEC 14443-3中定义的框架的命令。由于ISO/IEC 14443-3仅定义了框架和反碰撞/枚举命令,因此最重要的任何协议(例如mifare ultralight/ntag命令集)都是专有的。
。使用密码FF FF FF FF
的密码身份验证的正确命令将是:
byte[] tagCommand = new byte[] { (byte)0x1B, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
请注意,CRC通常会由非接触式前端芯片处理,因此您无需手动应用。
使用ACR1222L,有多种不同的方式来交换此类专有命令:
您可以使用PC_TO_RDR_ESCAPE(请注意,仅当您为读取器安装原始的ACR驱动程序包时,才能使用。假设您使用的是Java SmartCard IO API,则使用方法
来执行此操作Card.transmitControlCommand()
:byte[] response = card.transmitControlCommand(SCARD_CTL_CODE(3500), command);
可以在本文中找到该方法
SCARD_CTL_CODE
的定义。command
需要是一个字节数组,该字节阵列包含伪apdu的APDU标头,该标题将RAW命令传递到无接触式前端芯片和实际命令的实际命令。由于ACR1222L基于NXP PN532(?),因此无接触式前端芯片的命令将是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);
根据读者实际激活卡的方式,您可能需要使用IncommunicateThru命令而不是Indataexchange:
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);
可以通过:
添加伪APDU标头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
另一个选项是使用PC_TO_RDR_XFRBLOCK直接发送命令。这将映射到Java SmartCard IO API中的
CardChannel.transmit()
:ResponseAPDU responseApdu = cardChannel.transmit(commandAPDU);
您的读者的手册尚不清楚是否可以在该接口上使用相同的伪APDU标头。但是,如果您查看附录H,您会发现与包装到伪APDU(ACR122U遗产模式)的不同标头。因此,您可以使用以下内容:
CommandAPDU commandAPDU = new CommandAPDU(0xFF, 0x00, 0x00, 0x00, interfaceCommand);
请注意,再次,您必须将标签命令包装到Indataexchange命令中,以进行无接触式前端芯片。