java-使用PC / SC阅读器验证Ultralight EV1

我在尝试使用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://*.com/a/41729534/3613883中所述).我可以将它与Desfire EV1卡配合使用,但不适用于超轻型EV1(因为它显然不支持ISO7816-4).

因此,有没有办法使用PC / SC读卡器来验证Ultralight EV1卡?

解决方法:

首先,MIFARE Ultralight EV1不讲APDU.而是直接使用基于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的定义可以找到in this post.

该命令必须是一个字节数组,其中包含用于将原始命令传递给非接触式前端芯片的伪APDU的APDU标头和用于非接触式前端芯片的实际命令.由于ACR1222L基于NXP PN532(?),因此用于非接触式前端芯片的命令将是InDataExchange命令(请参见user manual):

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头,则manual of your reader不太清楚.但是,如果查看附录H,则会发现与包装到伪APDU(ACR122U传统模式)不同的标头.因此,您可以使用以下内容:

CommandAPDU commandAPDU = new CommandAPDU(0xFF, 0x00, 0x00, 0x00, interfaceCommand);

再次注意,您必须将tag命令包装到非接触式前端芯片的InDataExchange命令中.

上一篇:基于SQLite日志记录工具--Log4W


下一篇:c# – 从串口读取并显示结果