javax.smartcardio:如何向Desfire卡发送本机命令?

我正在创建一个通过PC / SC非接触式读卡器和javax.smartcardio API与Mifare DESFire卡通信的Java应用程序。 我设法定期发送ISO 7816 APDU(CLA,INS,P1-P2,Lc,Command数据,Le)。

我在Ridrix的博客上看到 ,DESFire卡(至少我使用的EV1版本)支持APDU和Native命令 ,其中大多数命令只有1个字节长。

例如,“ 获取版本 ”命令:

Command: 60 Response: af 04 01 01 00 02 18 05 

我使用SpringCardPC / SC Diag程序( 可在此处 )测试了该命令,我得到了正确的响应。

但我无法使用javax.smartcardio发送此命令:此API似乎是为真正的 APDU创建的,因此不允许1字节长的命令。

这是我做的:

 public static void main(String[] args){ TerminalFactory factory = TerminalFactory.getDefault(); CardTerminals terminalList = factory.terminals(); try { CardTerminal ct = terminalList.list().get(0); ct.waitForCardPresent(0); Card card = ct.connect("*"); CardChannel channel = card.getBasicChannel(); byte[] command = { 0x60 }; channel.transmit(new CommandAPDU(command)); } catch (CardException e) { e.printStackTrace(); } } 

它给我以下错误:

 Exception in thread "main" java.lang.IllegalArgumentException: apdu must be at least 4 bytes long at javax.smartcardio.CommandAPDU.parse(Unknown Source) at javax.smartcardio.CommandAPDU.(Unknown Source) 

我尝试了唯一的(AFAIK)其他方式发送命令:

  ByteBuffer command = ByteBuffer.allocate(1); command.put((byte) 0x60); ByteBuffer response = ByteBuffer.allocate(512); channel.transmit(command, response); 

并得到一个类似的错误:

 Exception in thread "main" java.lang.IllegalArgumentException: Command APDU must be at least 4 bytes long at sun.security.smartcardio.ChannelImpl.checkManageChannel(Unknown Source) at sun.security.smartcardio.ChannelImpl.doTransmit(Unknown Source) at sun.security.smartcardio.ChannelImpl.transmit(Unknown Source) 

你知道使用javax.smartcardio或其他什么方式发送这种命令吗?

我知道可以包装这些命令,但我更喜欢使用(更简单的)本机命令。

谢谢。

将近4年后,但为了防止有人发现这个问题,我确实找到了答案。 今天许多读者都支持在ISO 7816-4命令中包装Desfire APDU帧。 我确实发现了数据不能超过55个字节的限制。

有关完整信息,请参阅此文档中的第23页: http : //neteril.org/files/M075031_desfire.pdf

这意味着您可以指定以下内容来包装APDU帧

 CLA = 0x90 INC = {Your Desfire Command eg 0x60 - Get Version} P1 = 0 P2 = 0 Data = 1st byte = length of data followed by byte data. Terminate data with a 0x00 byte 

响应也包括如下:

 SW1 = 0x91 SW2 = Result Status Data = Response Data 

因此可以使用以下代码

 public static byte CMD_WRAP_START = (byte)0x90; public static byte CMD_WRAP_END = (byte)0x00; private CommandAPDU wrapAPDUFrameUsingISO7816_4(byte[] apdu) throws CardException { if (apdu.length > 55){ throw new CardException("The length of the wrapped DESFire command must not be longer than 55 bytes, checksum included."); } boolean hasData = apdu.length > 1; byte[] result; if (hasData) { result = new byte[apdu.length + 5]; } else { result = new byte[apdu.length + 4]; } result[0] = CMD_WRAP_START; // CLA result[1] = apdu[0]; // DESFIRE CMD CODE result[2] = 0; // P1 result[3] = 0; // P2 if (hasData) { result[4] = (byte) (apdu.length - 1); // Length of wrapped data, ONLY IF DATA EXISTS System.arraycopy(apdu,1,result,5,apdu.length-1); // DESFIRE Command data } result[result.length-1] = CMD_WRAP_END; return new CommandAPDU(result); } private static byte [] unwrapFromISO7816_4(byte[] wrapped) throws CardException { if (wrapped.length<2){ throw new CardException("Expected at least 2 bytes for ISO 7816-4 wrapped response: " + String.valueOf(Hex.encodeHex(wrapped, false))); } if (wrapped[wrapped.length-2]!=(byte)0x91){ throw new CardException("Expected 0x91 in SW1 for ISO 7816-4 wrapped response: " + String.valueOf(Hex.encodeHex(wrapped, false))); } byte[] result = new byte[wrapped.length-1]; System.arraycopy(wrapped,0,result,1,wrapped.length-2); // The DESFIRE response result[0] = wrapped[wrapped.length-1]; // The DESFIRE Status return result; } 

javax.smartcardio是一个使用ISO 7816-4命令编写的API。 因此,无法发送“本机”命令。 基本上,本机命令可以是任何东西,因此很难支持这些命令。

您要么恢复到JNI,要么尝试找到使用transmitControlCommand东西。 但是,如果没有额外的库,我担心没有真正的方法可以使用DESFire。

我个人认为使用包装层要容易得多。

这里有答案:命令APDU必须至少为4个字节。

  * case 1 : |CLA|INS|P1 |P2 | len = 4 * case 2s: |CLA|INS|P1 |P2 |LE | len = 5 * case 3s: |CLA|INS|P1 |P2 |LC |...BODY...| len = 6..260 * case 4s: |CLA|INS|P1 |P2 |LC |...BODY...|LE | len = 7..261 * * (Extended length is not currently supported) * case 2e: |CLA|INS|P1 |P2|00 |LE1|LE2| len = 7 * case 3e: |CLA|INS|P1 |P2 |00|LC1|LC2|...BODY...| len = 8..65542 * case 4e: |CLA|INS|P1 |P2 |00|LC1|LC2|...BODY...|LE1|LE2| len =10..65544 * * EMV