使用javax.smartcardio的用于智能卡的ISO 7816 APDU

时间:2012-12-11 15:20:52

标签: java smartcard

我已经使用javax.smartcardio从智能卡读取序列号而不需要太多努力。但是现在我被分配在空白卡上创建MF(没有它不能读取序列号)。我正在根据ISO 7816指南创建APDU命令,但是由于我的十六进制值是,我无法创建正确的APDU命令转换为错误的字节。

import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;

class SmartCardAPIs {

    public int Create_MF() throws CardException{

        //--Variable declaration
        int result=0;
        Card card=null;     
        byte[] responseData=null;
        ResponseAPDU answer=null;
        String SW1=null;
        String SW2=null;
        int cla,  ins,  p1,  p2;
        byte[] data=null;
        //---------------------------------------------

        //--1--Establish connection with the smart card
        TerminalFactory factory = TerminalFactory.getDefault();
        List<CardTerminal> terminals = factory.terminals().list();
        // Use the first terminal
        CardTerminal terminal = terminals.get(0);
        // Connect with the card
        card = terminal.connect("*");
        CardChannel channel = card.getBasicChannel();           
        //---------------------------------------------

        //--2--Create MF 
        cla=0x00;
        ins=0xE0;
        p1=0x00;
        p2=0x00;
        data = new byte[] {
            (byte) 0x21,
            (byte) 0x62,
            (byte) 0x1F,
            (byte) 0x82, // **** Getting converted to -126 ****
            --
            --
            --
        };          
        answer = channel.transmit(new CommandAPDU(cla,  ins,  p1,  p2, data));
        responseData= answer.getBytes();

        if(responseData!=null)
        {
            if(responseData.length==2)
            {
                SW1=String.format("%02X ", (responseData[0])).trim();
                SW2=String.format("%02X ", (responseData[1])).trim();
            }
        }       
    }
}

我有2个问题

1:命令APDU中的数据占用一个错误的字节(标记为 * )。

2:SW1和SW2返回为6A 80,这意味着数据字段中的参数不正确(我猜是因为以十六进制格式将int转换为字节时的负值,但是因为我不得不这么做)。

我在这里放置的部分APDU命令是我提供的完整命令的一部分,命令是100%正常并经过测试,因为我已成功使用智能卡工具在空白卡中创建MF用命令。我现在想在java中做同样的事情。

我认为问题在于这个APDU的创建方式,可能是负值问题(虽然我已经创建了Applet来读取卡中的序列号,但我对java APDU的东西不是很专业)。

3 个答案:

答案 0 :(得分:2)

既然你说,你手边有一个工作命令,肯定会仔细检查它的java表示:你有多确定,在先前的尝试中命令没有成功执行? (显然只允许一个MF。)问题是,报告的错误代码与“正确的APDU已知”假设相矛盾,这是我能想到的唯一解决方案。就代码而言,java代码看起来是正确的。

其他想法:ISO创建文件的命令数据字段应该以类似于0x6X的FCI开头。可能你的0x21是整个模板的长度(应该作为LC发送),java从字节数组的长度构造自己,所以试着把它留下来。 事实上,第3个字节是0x1F,意味着0x21减去标签和长度,支持这个假设。

答案 1 :(得分:0)

我试过这个命令:

...

...

private static final byte[] Select_App = {(byte)0x00,(byte)0xA4,(byte)0x04,(byte)0x00,(byte)0x04,(byte)0x50,(byte)0x54,(byte)0x4B,(byte)0x65};

.. ..

他们工作得很好,我从卡上得到了正确的回应。但是我在android上尝试了这个命令。所以我认为字节转换是正确的,我们不需要转换任何东西

好吧,关于java.smartcardio。*;我和你有同样的问题,我不能使用那个图书馆发送任何命令。但有人说我必须使用一些java包装器来发送一些命令。嗯......我还在继续努力......: - )

答案 2 :(得分:-1)

您需要通过以下方法正确地将字节转换为十六进制。

Integer class = StringUtil.parseHex("your class as string");

Class StringUtil


public class StringUtil {
public static Integer parseHex(String iStr) {
    int mask = 255;
    if (iStr.length() > 2)
        mask = 65535;
    try {
        return Integer.valueOf(Integer.parseInt(iStr, 16) & mask);
    } catch (Exception ex) {
    }
    return null;
}