Java Jna调用Dll动态库函数读写IC卡

Java Jna调用Dll动态库函数读写IC卡_第1张图片

 

 发卡器介绍:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.14c4789euYabVr&id=615391857885https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.14c4789euYabVr&id=615391857885

import com.sun.jna.Library ;
import com.sun.jna.Native;
import java.io.IOException;

interface CLibrary extends Library {
    //DLL绝对路径的地址获取,注意要去空格,特别坑
    //不同版本的读写器,接口DLL文件名称、函数名称是一样的,但内核代码不一样,请选用与读写器、操作系统一致的OUR_MIFARE.dll
    String filePath = CLibrary.class.getResource("").getPath().replaceFirst("/","").replaceAll("%20"," ")+"OUR_MIFARE";
    CLibrary sdtapi = (CLibrary) Native.loadLibrary(filePath, CLibrary.class);

    //动态链接库中的方法
    byte pcdbeep(int xms);                         //让设备发出声音
    byte pcdgetdevicenumber(byte[] devicenumber);  //读取设备编号
    byte piccreadex(byte ctrlword,byte[] serial,byte area,byte keyA1B0,byte[] picckey,byte[] piccdata0_2);             //轻松读卡
    byte piccwriteex(byte ctrlword,byte[] serial,byte area,byte keyA1B0,byte[] picckey,byte[] piccdata0_2);            //轻松写卡
    byte piccchangesinglekey(byte ctrlword,byte[] serial,byte area,byte keyA1B0,byte[] piccoldkey,byte[] piccnewkey);  //改单区密码
    byte piccchangesinglekeyex(byte ctrlword,byte[] serial,byte area,byte keyA1B0,byte[] piccoldkey,byte[] piccdata);  //改单区密码,可同时修改A密码,或密码权限访问字(密码权限编码)或B密码
    byte piccrequest(byte[] serial);              //寻卡
    byte piccauthkey1(byte[] serial,byte area,byte keyA1B0,byte[] picckey);    //认证卡片密码
    byte piccread(byte block,byte[] blockdate);   //读指定块信息
    byte piccwrite(byte block,byte[] blockdate);   //读指定块信息
    byte piccwriteserial(byte ctrlword,byte[] serial,byte keyA1B0,byte[] piccoldkey,byte[] piccdata);  //写UID
}

public class ICReadWriteDemo {

    public static final byte BLOCK0_EN = 0x01;      //操作第0块
    public static final byte BLOCK1_EN = 0x02;      //操作第1块
    public static final byte BLOCK2_EN = 0x04;      //操作第2块
    public static final byte NEEDSERIAL = 0x08;     //仅对指定序列号的卡操作
    public static final byte EXTERNKEY = 0x10;      //使用函数时需指定密码,否则使用预存在读写器中的密码(该密码只能写入,无法读出,很安全)
    public static final byte NEEDHALT = 0x20;       //读卡或写卡后顺便休眠该卡,休眠后,卡必须拿离开感应区,再放回感应区,才能进行第二次操作。

    public static void main(String[] args) throws Exception {
        System.setProperty("jna.encoding", "gbk");

        int status;                       //存放返回值
        byte[] devicenumber = new byte[4];//4字节设备编号
        byte myareano;                    //区号
        byte authmode;                    //密码类型,用A密码或B密码
        byte myctrlword;                  //控制字
        byte[] mypicckey = new byte[6];   //6字节卡认证密码
        byte[] mypiccserial = new byte[4];//4字节卡序列号
        byte[] mypiccdata = new byte[48]; //48字节卡扇区数据缓冲

        if (args.length == 0) {
            System.out.println("请先输入运行参数!");
            System.out.println("\n参数 0:驱动读卡器嘀一声");
            System.out.println("\n参数 1:读取设备编号");
            System.out.println("\n参数 2:轻松读卡,一次读出指定扇区内三块共48字节数据");
            System.out.println("\n参数 3:轻松写卡,一次写指定扇区内三块共48字节数据");
            System.out.println("\n参数 4:修改卡片的A密码+控制字+B密码");
            System.out.println("\n参数 5:读取指定块共16个字节数据");
            System.out.println("\n参数 6:写16个字节数据到指定块");
            return;
        }

        //Java中只能使用string1.equals(string2)的方式来比较字符串
        if (args[0].equals("0")) {             //驱动读卡器发嘀一声
            System.out.print("\n\n0-驱动读卡器嘀一声\n");
            CLibrary.sdtapi.pcdbeep(50);
            System.out.print("结果:如果能听到读卡器嘀一声表示成功,否则请检查读卡器是否已连上线!\n\n");

        } else if (args[0].equals("1"))          //读取设备编号,可做为软件加密狗用,也可以根据此编号在公司网站上查询保修期限
        {
            status = (int) (CLibrary.sdtapi.pcdgetdevicenumber(devicenumber) & 0xff);//& 0xff用于转为无符号行数据
            System.out.print("\n\n1-读取设备编号\n");
            System.out.print("结果:");
            if (status == 0) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print("读取成功!设备编号为" + (devicenumber[0] & 0xff) + "-" + (devicenumber[1] & 0xff) + "-" + (devicenumber[2] & 0xff) + "-" + (devicenumber[3] & 0xff));
                System.out.print("\n\n");
            } else {
                PrintErrInf(status);   //错误代码提示
            }

        } else if (args[0].equals("2")) {     //轻松读卡,一次读出指定扇区内三块共48字节数据
            myctrlword = (byte) (BLOCK0_EN + BLOCK1_EN + BLOCK2_EN + EXTERNKEY);    //控制字指定,控制字的含义请查看本公司网站提供的动态库说明
            myareano = 8;                   //指定为第8区
            authmode = 1;                   //指定卡密码认证模式,大于0表示用A密码认证,推荐用A密码认证
            mypicckey[0] = (byte) 0xff;     //指定6字世的卡认证密码
            mypicckey[1] = (byte) 0xff;
            mypicckey[2] = (byte) 0xff;
            mypicckey[3] = (byte) 0xff;
            mypicckey[4] = (byte) 0xff;
            mypicckey[5] = (byte) 0xff;

            status = (int) (CLibrary.sdtapi.piccreadex(myctrlword, mypiccserial, myareano, authmode, mypicckey, mypiccdata) & 0xff);
            System.out.print("\n\n2-轻松读卡\n");
            if (status == 0) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print("读卡成功,卡序列号:" + Integer.toHexString(mypiccserial[0] & 0xff) + "-" + Integer.toHexString(mypiccserial[1] & 0xff) + "-" + Integer.toHexString(mypiccserial[2] & 0xff) + "-" + Integer.toHexString(mypiccserial[3] & 0xff));
                String ReadBuff = "";
                for (int i = 0; i < 48; i++) {
                    String bytestr = "00" + Integer.toHexString(mypiccdata[i] & 0xff);
                    ReadBuff = ReadBuff + bytestr.substring(bytestr.length() - 2, bytestr.length()) + " ";
                }
                System.out.print("\n扇区内数据:" + ReadBuff);
            } else {
                PrintErrInf(status);   //错误代码提示
            }

        } else if (args[0].equals("3")) {     //轻松写卡,一次写指定扇区内三块共48字节数据
            myctrlword = (byte) (BLOCK0_EN + BLOCK1_EN + BLOCK2_EN + EXTERNKEY);    //控制字指定,控制字的含义请查看本公司网站提供的动态库说明
            myareano = 8;                   //指定为第8区
            authmode = 1;                   //指定卡密码认证模式,大于0表示用A密码认证,推荐用A密码认证
            mypicckey[0] = (byte) 0xff;     //指定6字世的卡认证密码
            mypicckey[1] = (byte) 0xff;
            mypicckey[2] = (byte) 0xff;
            mypicckey[3] = (byte) 0xff;
            mypicckey[4] = (byte) 0xff;
            mypicckey[5] = (byte) 0xff;

            //写中文或字母数字等字符信息,将要写入的字符转ASCII码写入
            String WriteStr = "伟大的中华人民共和国万岁!1949-10-01                                "; //将要写入的文字生成字节数组
            byte[] WriteBuf = WriteStr.getBytes("gb2312");
            for (int i = 0; i < 48; i++) {  //指定写卡数据,最长48个字节
                mypiccdata[i] = WriteBuf[i];
            }

            status = (int) (CLibrary.sdtapi.piccwriteex(myctrlword, mypiccserial, myareano, authmode, mypicckey, mypiccdata) & 0xff);
            System.out.print("\n\n3-轻松写卡\n");
            if (status == 0) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print("写卡成功,卡序列号:" + Integer.toHexString(mypiccserial[0] & 0xff) + "-" + Integer.toHexString(mypiccserial[1] & 0xff) + "-" + Integer.toHexString(mypiccserial[2] & 0xff) + "-" + Integer.toHexString(mypiccserial[3] & 0xff));
                System.out.print("\n\n");
            } else {
                PrintErrInf(status);   //错误代码提示
            }

        } else if (args[0].equals("4")) {     //修改卡片的A密码+控制字+B密码
            byte[] mypiccoldkey = new byte[6];//卡旧密码
            byte[] mypiccnewkey = new byte[17];//卡新A密码+控制字+B密码

            myctrlword = (byte) (BLOCK0_EN + BLOCK1_EN + BLOCK2_EN + EXTERNKEY);    //控制字指定,控制字的含义请查看本公司网站提供的动态库说明
            myareano = 8;                   //指定为第8区
            authmode = 1;                   //指定卡密码认证模式,大于0表示用A密码认证,推荐用A密码认证
            mypiccoldkey[0] = (byte) 0xff;  //指定6字节的卡认证密码
            mypiccoldkey[1] = (byte) 0xff;
            mypiccoldkey[2] = (byte) 0xff;
            mypiccoldkey[3] = (byte) 0xff;
            mypiccoldkey[4] = (byte) 0xff;
            mypiccoldkey[5] = (byte) 0xff;

            mypiccnewkey[0] = (byte) 0xff;  //6字节的新A密码
            mypiccnewkey[1] = (byte) 0xff;
            mypiccnewkey[2] = (byte) 0xff;
            mypiccnewkey[3] = (byte) 0xff;
            mypiccnewkey[4] = (byte) 0xff;
            mypiccnewkey[5] = (byte) 0xff;

            mypiccnewkey[6] = (byte) 0xff;  //4字节的控制字,除非您能确定了解不要随便更改,否则卡报废
            mypiccnewkey[7] = (byte) 0x07;
            mypiccnewkey[8] = (byte) 0x80;
            mypiccnewkey[9] = (byte) 0x69;

            mypiccnewkey[10] = (byte) 0xff;  //6字节的新B密码
            mypiccnewkey[11] = (byte) 0xff;
            mypiccnewkey[12] = (byte) 0xff;
            mypiccnewkey[13] = (byte) 0xff;
            mypiccnewkey[14] = (byte) 0xff;
            mypiccnewkey[15] = (byte) 0xff;

            mypiccnewkey[16] = (byte) 0x03;  //功能码:3 表示同时更改A、B 密码及权限访问字;2 表示密码权限访问字不更改,只改A、B密码;0 示只改A密码

            status = (int) (CLibrary.sdtapi.piccchangesinglekeyex(myctrlword, mypiccserial, myareano, authmode, mypiccoldkey, mypiccnewkey) & 0xff);
            System.out.print("\n\n4-更改卡密码\n");
            if (status == 0) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print("卡密码更改成功,卡序列号:" + Integer.toHexString(mypiccserial[0] & 0xff) + "-" + Integer.toHexString(mypiccserial[1] & 0xff) + "-" + Integer.toHexString(mypiccserial[2] & 0xff) + "-" + Integer.toHexString(mypiccserial[3] & 0xff));
                System.out.print("\n\n");
            } else {
                PrintErrInf(status);   //错误代码提示
            }

        } else if (args[0].equals("5")) {       //读取指定块共16个字节数据
            byte myblock;                       //块号为区号*4+0、1、2、3,其中第3块为密码控制块
            byte[] myblockdata = new byte[16]; //卡数据缓冲
            myareano = 8;                      //指定为第8区
            myblock = (byte) (myareano * 4 + 0);      //第0块地址
            authmode = 1;                      //指定卡密码认证模式,大于0表示用A密码认证,推荐用A密码认证
            mypicckey[0] = (byte) 0xff;        //指定6字世的卡认证密码
            mypicckey[1] = (byte) 0xff;
            mypicckey[2] = (byte) 0xff;
            mypicckey[3] = (byte) 0xff;
            mypicckey[4] = (byte) 0xff;
            mypicckey[5] = (byte) 0xff;

            status = (int) (CLibrary.sdtapi.piccrequest(mypiccserial) & 0xff);
            if (status == 0) {
                status = (int) (CLibrary.sdtapi.piccauthkey1(mypiccserial, myareano, authmode, mypicckey) & 0xff);
                if (status == 0) {
                    status = (int) (CLibrary.sdtapi.piccread(myblock, myblockdata) & 0xff);
                    if (status == 0) {
                        CLibrary.sdtapi.pcdbeep(38);
                        System.out.print("\n5-读块成功,卡序列号:" + Integer.toHexString(mypiccserial[0] & 0xff) + "-" + Integer.toHexString(mypiccserial[1] & 0xff) + "-" + Integer.toHexString(mypiccserial[2] & 0xff) + "-" + Integer.toHexString(mypiccserial[3] & 0xff));
                        String ReadBuff = "";
                        for (int i = 0; i < 16; i++) {
                            String bytestr = "00" + Integer.toHexString(myblockdata[i] & 0xff);
                            ReadBuff = ReadBuff + bytestr.substring(bytestr.length() - 2, bytestr.length()) + " ";
                        }
                        System.out.print("\n块内数据:" + ReadBuff);
                    } else {
                        PrintErrInf(status);   //错误代码提示
                    }
                } else {
                    PrintErrInf(status);   //错误代码提示
                }
            } else {
                PrintErrInf(status);   //错误代码提示
            }

        } else if (args[0].equals("6")) {       //写指定块共16个字节数据
            byte myblock;                      //块号为区号*4+0、1、2、3,其中第3块为密码控制块
            byte blockid;
            byte[] myblockdata = new byte[16]; //卡数据缓冲
            myareano = 8;                      //指定为第8区
            blockid = 0;                       //块号,3块为密码块
            myblock = (byte) (myareano * 4 + blockid);//块地址
            authmode = 1;                      //指定卡密码认证模式,大于0表示用A密码认证,推荐用A密码认证
            mypicckey[0] = (byte) 0xff;        //指定6字世的卡认证密码
            mypicckey[1] = (byte) 0xff;
            mypicckey[2] = (byte) 0xff;
            mypicckey[3] = (byte) 0xff;
            mypicckey[4] = (byte) 0xff;
            mypicckey[5] = (byte) 0xff;

            if (blockid < 3) {
                for (int i = 0; i < 16; i++) {
                    myblockdata[i] = (byte) (i);
                }
            } else {
                System.out.print("第三块为密码块,推荐使用piccchangesinglekeyex函数");
                System.exit(1);
            }

            status = (int) (CLibrary.sdtapi.piccrequest(mypiccserial) & 0xff);
            if (status == 0) {
                status = (int) (CLibrary.sdtapi.piccauthkey1(mypiccserial, myareano, authmode, mypicckey) & 0xff);
                if (status == 0) {
                    status = (int) (CLibrary.sdtapi.piccwrite(myblock, myblockdata) & 0xff);
                    if (status == 0) {
                        CLibrary.sdtapi.pcdbeep(38);
                        System.out.print("\n6-写块成功,卡序列号:" + Integer.toHexString(mypiccserial[0] & 0xff) + "-" + Integer.toHexString(mypiccserial[1] & 0xff) + "-" + Integer.toHexString(mypiccserial[2] & 0xff) + "-" + Integer.toHexString(mypiccserial[3] & 0xff));
                    } else {
                        PrintErrInf(status);   //错误代码提示
                    }
                } else {
                    PrintErrInf(status);   //错误代码提示
                }
            } else {
                PrintErrInf(status);   //错误代码提示
            }
        } else if (args[0].equals("7")) { //写新UID
            myctrlword = (byte) (BLOCK0_EN + BLOCK1_EN + BLOCK2_EN + EXTERNKEY);    //控制字指定,控制字的含义请查看本公司网站提供的动态库说明
            authmode = 1;                   //指定卡密码认证模式,大于0表示用A密码认证,推荐用A密码认证
            mypicckey[0] = (byte) 0xFF;     //指定6字世的卡认证密码
            mypicckey[1] = (byte) 0xFF;
            mypicckey[2] = (byte) 0xFF;
            mypicckey[3] = (byte) 0xFF;
            mypicckey[4] = (byte) 0xFF;
            mypicckey[5] = (byte) 0xFF;
            int NewUid=123456789;
            byte[] UidByte=int2byte(NewUid);
            byte crcbyte=(byte) (UidByte[0] ^ UidByte[1]^ UidByte[2]^ UidByte[3]);
            byte[] myblockdata = new byte[16]; //卡数据缓冲
            for(int i=0;i<4;i++){
                myblockdata[i]=UidByte[i];
            }
            myblockdata[4]=crcbyte;

            status = (int) (CLibrary.sdtapi.piccwriteserial(myctrlword,mypiccserial,authmode,mypicckey,myblockdata) & 0xff);
            if(status == 0){
                status = (int) (CLibrary.sdtapi.piccrequest(mypiccserial) & 0xff);
                if(status == 0){
                    CLibrary.sdtapi.pcdbeep(38);
                    System.out.print("\n6-写块成功,16进制卡序列号:" + Integer.toHexString(mypiccserial[0] & 0xff) + "-" + Integer.toHexString(mypiccserial[1] & 0xff) + "-" + Integer.toHexString(mypiccserial[2] & 0xff) + "-" + Integer.toHexString(mypiccserial[3] & 0xff));
                    System.out.print("\n转10进制卡号:"+ toIntLH(mypiccserial));
                }
            }
        }
    }
    //---------------------------------------------------------------------------------整数转4字节数组
    public static byte[] int2byte(int res) {
        byte[] targets = new byte[4];
        targets[0] = (byte) (res & 0xff);// 最低位
        targets[1] = (byte) ((res >> 8) & 0xff);// 次低位
        targets[2] = (byte) ((res >> 16) & 0xff);// 次高位
        targets[3] = (byte) (res >>> 24);// 最高位,无符号右移。
        return targets;
    }
    //----------------------------------------------------------------------------------数组转整数高位在前
    public static int toIntHL(byte[] b){
        int res = 0;
        for(int i=0;i

你可能感兴趣的:(IC读写器,Java读写IC卡,Java调DLL函数,Java,NFC,QQ954486673,VX13822155058)