为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用APDU读取和下载ddd行车记录仪文件?

如何使用APDU读取和下载ddd行车记录仪文件?

慕尼黑8549860 2021-07-02 17:31:13
我正在尝试使用javax.smartcardio. 问题是我在盲目地做大部分事情,因为我找不到关于APDU commands.目前,我设法打印了卡片类型 ( card: PC/SC card in HID Global OMNIKEY 3x21 Smart Card Reader 0, protocol T=0, state OK) 并读取了卡片识别信息(所选文件0520)。如何下载行驶记录仪 .ddd 文件?这是到目前为止的代码:public static void main(String[] args) {        try {            TerminalFactory factory = TerminalFactory.getDefault();            List<CardTerminal> terminals = factory.terminals().list();            System.out.println("Terminals: " + terminals);            // get the first terminal            CardTerminal terminal = terminals.get(0);            // establish a connection with the card            Card card = terminal.connect("T=0");            System.out.println("card: " + card);            CardChannel channel = card.getBasicChannel();            byte[] c1 = hexStringToByteArray(stripCommandSpace("00 A4 04 0C 06 FF544143484F"));            //byte[] c1 = hexStringToByteArray(stripCommandSpace("FF CA 00 00 00"));            ResponseAPDU r1 = channel.transmit(new CommandAPDU(c1));            System.out.println("response: " + byteArrayToHexString(r1.getBytes()));            byte[] c2 = hexStringToByteArray(stripCommandSpace("00 a4 02 0c 02 05 04"));            ResponseAPDU r2 = channel.transmit(new CommandAPDU(c2));            System.out.println("response: " + byteArrayToHexString(r2.getBytes()));            byte[] c3 = hexStringToByteArray(stripCommandSpace("00 B0 00 01 128"));            ResponseAPDU r3 = channel.transmit(new CommandAPDU(c3));            System.out.println("response: " + byteArrayToHexString(r3.getBytes()));            System.out.println("data: " + byteArrayToHexString(r3.getData()));我设法识别并读取了驱动程序活动文件 - 我必须将标识符更改为0504如下图所示:现在我的问题是如何将我得到的字节数组转换为 .ddd 文件。我在我的代码的更新版本中尝试过(见上文),但 .ddd 阅读器告诉我文件已损坏(我使用第三方应用程序将 .ddd 转换为 .txt - 称为readesm)。
查看完整描述

1 回答

?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

卡驱动中的结构块:

//img1.sycdn.imooc.com//60e555ad00013e7505900297.jpg

  1. 结构块是(ICC,IC,Application_Identificacion ........):

    标头:“文件 2(0501h,0502h ....)字节”+“类型(数据-0 或有符号-1)1 个字节”+“长度 2 个字节”+ 数据(读卡):

  2. ICC、IC 和 Card_donwload 不需要签名,所以 0501 到 0522(不是 050e),签名块文件是授权所必需的,但读取字节文件和创建二进制文件不需要。

  3. 阅读 Fid 的递归:

 for (Fid fid : Fid.values()) {

    System.out.println(fid.getId());

    // not read 03f00 and 0500 not files

    if(!fid.getId().equals("3f,00") && !fid.getId().equals("05,00")){

        b = readCard(r, channel, fid.getId());

        // header block file

        byte[] htba = OperationHelper.hexToByteAr(fid.getId());

        byte[] sizeByte = ByteBuffer.allocate(4).putInt(b.length).array();

        headerBlock[0] = htba[0];       // id file byte 1

        headerBlock[1] = htba[1];       // id file byte 2

        headerBlock[2] = 0;             // type file data

        headerBlock[3] = sizeByte[2];   // size file byte 1

        headerBlock[4] = sizeByte[3];   // size file byte 2

        try{

            fileTGD.write(headerBlock);

            fileTGD.write(b);

            // add signature file

            if (!fid.getId().equals("00,02") && !fid.getId().equals("00,05")

                    && !fid.getId().equals("C1,00") && !fid.getId().equals("C1,08")

                    && !fid.getId().equals("05,0E")){

                performHashFile(r, channel);

                b = signature(r, channel);

                sizeByte = ByteBuffer.allocate(4).putInt(b.length).array();

                headerBlock[0] = htba[0];

                headerBlock[1] = htba[1];

                headerBlock[2] = 1;

                headerBlock[3] = sizeByte[2];

                headerBlock[4] = sizeByte[3];

                fileTGD.write(headerBlock);

                fileTGD.write(b);

            }

        }catch (Exception e){

            e.printStackTrace();

        }

    }

}

读取数据:


public static byte[] readCard( ResponseAPDU r, CardChannel channel, String fid){

ByteArrayOutputStream dataResponseBuffer = new ByteArrayOutputStream();

try {

    //r = channel.transmit(new CommandAPDU(0x00, 0x84, 0x00, 0x00,  OperationHelper.hexToByteAr("6f,07,00,00,00,08,00,00,00,00,00,a4,02,0c,02,05,04")));

    /**

     *  GetParameters

     *

     *  Headers

     *  CLA - 00

     *  INS - A4

     *  P1 - 02

     *  P2 - 0C

     *  DATA - 00,02         //6C,00,00,00,00,08,01,00,00,00

     *  dataOffset - 00

     *  dataLength - length of trama

     *

     */

    //r = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x02, 0x0C,  OperationHelper.hexToByteAr("00,02"), 0x00, 0x02));          

    if (!fid.equals("00,02") && !fid.equals("00,05"))

        //select MF - Only positioning

        r = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x04, 0x0C, OperationHelper.hexToByteAr("ff,54,41,43,48,4f"), 0x00, 0x06));

    // select EF

    r = channel.transmit(new CommandAPDU(0x00, APDUCommand.SELECT_FILE.getCommand(), 0x02, 0x0C, OperationHelper.hexToByteAr(fid), 0x00, 0x02));

    boolean end = true;

    int p1 = 0x00;

    int p2 = 0x00;

    Byte le = Byte.valueOf((byte) 255);

    int size = 0x00;

    do {

        r = channel.transmit(new CommandAPDU(0x00, APDUCommand.READ_BINARY.getCommand(), p1, p2, (le < 0) ? le & 255 : le));

        switch (r.getSW1()) {

            case 0x90:

                dataResponseBuffer.write(r.getData());

                size += (le < 0) ? le.intValue() & 255 : le.intValue();

                byte[] offsetarray = ByteBuffer.allocate(4).putInt(size).array();

                p1 = (offsetarray[2] < 0) ? offsetarray[2] & 255 : offsetarray[2];

                p2 = (offsetarray[3] < 0) ? offsetarray[3] & 255 : offsetarray[3];

                break;

            case 0x67: // dec 103                   

                break;

            // normal process XX = number of bytes for response enabled

            case 0x61:

            /*

             nuevaLong = Byte.valueOf(codigoError[1]);

             */

                break;

            // incorrect parameters (out of EF)

            case 0x6a:

                if (r.getSW2() == 0x86)

                    System.out.println("Parameters P1-P2 incorrects");

                break;

            // incorrect long, sw2 = exact long. If not return field data

            case 0x6c: //dec 108

                //nuevaLong = Byte.valueOf(codigoError[1]);

                if (r.getSW2() == 0x86)

                    System.out.println("Parameter P1-P2 incorrects");

                break;

            case 0x69: //dec 108

                end = false;

                break;

            case 0x6b: //dec 107

                end = false;

                /*

                int div = (le < 0)? le.intValue() & 255: le.intValue() ;

                size -= div;

                le = Byte.valueOf((byte) (div / 2));

                size += le;

                if (le.byteValue() == (byte) 0) {

                    le = Byte.valueOf((byte) 1);

                    end = false;

                }

                offsetarray = ByteBuffer.allocate(4).putInt(size).array();

                 entero = Integer.valueOf(byteArraySize4ToInt(offsetarray) );

                p1 = (offsetarray[2] < 0)? offsetarray[2] & 255: offsetarray[2];

                p2 = (offsetarray[3] < 0)? offsetarray[3] & 255: offsetarray[3];

                */

                break;


            default:

                break;

        }

    } while (end);

} catch (CardException e1) {

    e1.printStackTrace();

} catch (IOException e) {

    e.printStackTrace();

}

return dataResponseBuffer.toByteArray();

}


5.根据开关内部的文档进行错误处理


查看完整回答
反对 回复 2021-07-07
  • 1 回答
  • 0 关注
  • 177 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信