当前位置: 首页 > 知识库问答 >
问题:

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

须志新
2023-03-14

我正在创建一个java应用程序,通过PC/SC非接触式阅读器和javax.smartcardioAPI与MifeDesFire卡通信。我设法发送常规的ISO 7816 APDU(CLA,INS,P1-P2,Lc,命令数据,Le)。

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

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

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

我用SpringCard(此处提供)的PC/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.<init>(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或其他方法发送这种命令吗?

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

谢谢

共有3个答案

苏宜人
2023-03-14

这里有答案:命令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 
柯永福
2023-03-14

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

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

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

CLA = 0x90
INC = {Your Desfire Command e.g. 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;
}
尉迟哲瀚
2023-03-14

javax.smartcardio是使用ISO 7816-4命令编写的API。因此,不可能发送“本地”命令。基本上,本机命令可以是任何东西,所以很难支持它们。

您可以恢复到JNI,也可以尝试查找使用传输ControlControl的内容。但是恐怕没有额外的库就没有真正的方法来使用DESFire。

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

 类似资料:
  • 我已经将证书导入了cacerts(JAVA\u HOME指向的地方),但仍然出现了这个错误。无法解决问题。客户端的邮件服务器(Microsoft ESMTP服务器)没有防火墙问题。我可以从我的服务器远程登录。已尝试SSLpoke,但超时。试过25号端口的tcpdump,可以看到来回的通信。基本上是试图触发来自邮件服务器的出站电子邮件。 详细的错误日志为: 原因:javax。邮政MessaginEx

  • 我试图通过APDUs命令通过HID OMNIKEY 5427 CK操作MIFARE卡ie。超轻C卡,在Windows 10 x64操作系统环境下使用WinSCard.dll。(我隶属恩智浦NDA公司,可以完全访问他们的文件) 我试着在网上找了好几天的信息。除了2页的小册子,似乎没有针对这个模型发布的文档。 像GetUID(FFCA000000)这样的简单命令就可以了,我可以取回实际的卡UID。 但

  • 我的的部分当前如下所示: ...这意味着我可以运行来启动服务器。到目前为止还不错。 但是,我希望能够运行类似的东西,并将参数传递给(例如,=>)。这可能吗?

  • javax发生了什么。从Java 9开始的smartcardio库?是否有其他方法或某种方式可以在JAR中获得它?

  • 在Java9下,各种默认包被切换到JavaEE包(不再包含在JVM中——可选可添加)。这对大多数人来说不是问题,因为我只是将JavaEE包指定为依赖项。然而,随着所说的包javax.smartcardio,我没有找到任何它可以降落的地方(github-jee,没有Maven搜索结果,...)。有人能给我一个提示在哪里可以得到最新版本的包吗?非常感谢! 我刚刚发现javax。smartcardio仍

  • 我一直在试图找到一种方法,从我的PC(Windows 7)向Arduino Uno R3发送串行命令。我一直在做这个简单的程序,你应该通过USB电缆发送一个简单的“1”,以便打开车载LED。我的Arduino代码应该可以工作(我知道的,但我会确保上传它)。我一直在尝试使用Python和pySerial发送此命令,但我似乎无法让pySerial正常工作。我也尝试过使用CMD,但当我输入命令(ECHO