Java读写CPU卡FM1208芯片

发卡器 介绍:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.19b55f800Oz8WF&id=45006910325https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.19b55f800Oz8WF&id=45006910325

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 cpurequest(byte[] mypiccserial,byte[] myparam,byte[] myver,byte[] mycode);    //激活CPU卡
    byte cpursinit(byte emptycard, byte[] mypicckey, byte mykeylen, int spacesize);    //初始化CPU卡
    byte cpursfileadd(byte FileIndex,byte[] RFilekey,byte RKLen, byte[] WFilekey,byte WKLen,int FileSize);   //创建空文件
    byte cpursfilekeychg(byte FileIndex, byte ctrlCode,byte[] Autkey,byte AKLen,byte[] Newkey,byte NKLen);   //修改文件密码
    byte cpursfiledataread(byte FileIndex,byte ctrlCode,byte[] Autkey,byte AKLen,byte DataStart,byte[] DataBuf,byte DataLen);    //读CPU卡内文件信息
    byte cpursfiledatawrite(byte FileIndex,byte ctrlCode,byte[] Autkey,byte AKLen,byte DataStart,byte[] DataBuf,byte DataLen);   //写数据到文件内
    byte cpurscardkeychg(byte[] Oldkey,byte OKLen, byte[] Newkey,byte NKLen);  //修改CPU卡密码,卡密码与文件密码无关不影响数据安全
    byte cpurscardclr();  //强制清空已用cpursinit函数成功初始化过的卡
}

public class RWFm1208Cpu {

    public static void main(String[] args) throws Exception  {
        System.setProperty("jna.encoding", "GBK");
        String filePath = CLibrary.class.getResource("").getPath().replaceFirst("/", "").replaceAll("%20", " ") + "OUR_MIFARE.DLL";
        System.out.println("本示例引用的DLL文件:" + filePath);

        if (args.length == 0) {
            System.out.println("\n请先输入运行参数!");
            System.out.println("\n参数 0:驱动读卡器嘀一声");
            System.out.println("\n参数 1:读取设备编号");
            System.out.println("\n参数 2:激活CPU卡");
            System.out.println("\n参数 3:初始化CPU卡");
            System.out.println("\n参数 4:创建文件");
            System.out.println("\n参数 5:修改文件密码");
            System.out.println("\n参数 6:读CPU卡内文件信息");
            System.out.println("\n参数 7:写数据到文件内");
            System.out.println("\n参数 8:更改CPU卡认证密码");
            System.out.println("\n参数 9:强制清空已用cpursinit函数成功初始化过的卡");
            return;
        }

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

        } else if (args[0].equals("1"))          //读取设备编号,可做为软件加密狗用,也可以根据此编号在公司网站上查询保修期限
        {
            int status;                          //存放返回值
            byte[] devicenumber = new byte[4];   //4字节设备编号

            status =(int)(CLibrary.sdtapi.pcdgetdevicenumber(devicenumber) & 0xff);//& 0xff用于转为无符号行数据
            System.out.print("\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)+"\n");
            } else {
                PrintErrInf(status);   //返回代码提示
            }

        }else if (args[0].equals("2"))          //激活CPU卡,每次卡离开过感应区都要先激活才能继续操作卡片
        {
            int status;                          //存放返回值
            byte[] mypiccserial = new byte[4];   //4字节设备编号
            byte[] myparam = new byte[4];        //4字节卡参数
            byte[] myver= new byte[1];
            byte[] mycode= new byte[1];

            System.out.print("\n2-激活CPU卡,每次卡离开过感应区都要先激活才能继续操作卡片\n");
            status =(int)(CLibrary.sdtapi.cpurequest(mypiccserial,myparam, myver, mycode) & 0xff);//& 0xff用于转为无符号行数据
            if (status == 0 || status == 52) {
                CLibrary.sdtapi.pcdbeep(38);
                String serialnumber = "";
                for (int i = 0; i < 4; i++) {
                    String bytestr = "00" + Integer.toHexString(mypiccserial[i] & 0xff);
                    serialnumber = serialnumber + bytestr.substring(bytestr.length() - 2, bytestr.length());
                }
                System.out.print("CPU卡激活成功,卡号:" + serialnumber+"\n");
            } else {
                PrintErrInf(status);   //返回代码提示
            }

        }else if (args[0].equals("3"))          //初始化CPU卡
        {
            int status;                          //存放返回值
            byte[] mypicckey = new byte[16];     //卡片认证密码,16进制,最好不要随便修改,此密码不影响数据安全
            byte mykeylen = 16 ;                 //卡片密码长度
            int  spacesize= 1000;                //应用空间字节大小(要大于所有文件总和),根据不同容量的卡设不同值
            byte emptycard=1;                    //初始化前是否清空卡内数据,取值1将先清空卡,取值为0不清空现有数据

            for(int i=0;i<16;i++){
                mypicckey[i]=(byte) 0xff;
            }
            System.out.print("\n3-初始化CPU卡\n");
            status =(int)(CLibrary.sdtapi.cpursinit(emptycard, mypicckey, mykeylen, spacesize) & 0xff);//& 0xff用于转为无符号行数据
            if (status == 0 ) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print("初始化卡成功!\n" );
            } else {
                PrintErrInf(status);   //返回代码提示
            }

        }else if (args[0].equals("4"))           //创建文件
        {
            int status;                          //存放返回值
            byte RKLen = 16 ;                    //文件 只读权限密码 长度
            byte[] RFilekey = new byte[RKLen];   //文件 只读权限密码
            byte WKLen = 16 ;                    //文件 读写权限密码 长度
            byte[] WFilekey = new byte[WKLen];   //文件 读写权限密码,此权限高,可认证此密码修改只读密码,要记住文件密码
            byte FileIndex=0;                    //文件号,取值0 到 5
            int FileSize=300;                    //指定文件大小字节数

            for(int i=0;i<16;i++){
                RFilekey[i]=(byte) 0xff;
                WFilekey[i]=(byte) 0xff;
            }

            System.out.print("\n4-创建文件\n");
            status =(int)(CLibrary.sdtapi.cpursfileadd(FileIndex, RFilekey, RKLen, WFilekey, WKLen, FileSize) & 0xff);//& 0xff用于转为无符号行数据
            if (status == 0 ) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print(Integer.toHexString(FileIndex)+" 号文件创建成功!\n" );
            } else {
                PrintErrInf(status);   //返回代码提示
            }

        }else if (args[0].equals("5"))           //修改文件密码
        {
            int status;                          //存放返回值
            byte OldKey=0;                       //取值 0 表示用只读密码来认证,取值 2 表示用读写密码来认证
            byte AKLen = 16 ;                    //文件 认证密码 长度
            byte[] Autkey = new byte[AKLen];     //文件 认证密码

            byte ChaKey=0;                       //取值 0 表示更改只读密码,   取值 1 表示更改读写密码
            byte NKLen = 16 ;                    //文件 新密码密码 长度
            byte[] Newkey = new byte[NKLen];     //文件 新密码密码
            byte FileIndex=0;                    //文件号,取值0 到 5
            byte ctrlCode=(byte)(ChaKey+OldKey);

            for(int i=0;i<16;i++){               //文件认证密码、文件新密码,修改好要记住新密码,否则文件不能读写
                Autkey[i]=(byte) 0xff;
                Newkey[i]=(byte) 0xff;
            }

            System.out.print("\n5-修改文件密码\n");
            status =(int)(CLibrary.sdtapi.cpursfilekeychg(FileIndex, ctrlCode, Autkey, AKLen, Newkey, NKLen) & 0xff);//& 0xff用于转为无符号行数据
            if (status == 0 ) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print(Integer.toHexString(FileIndex)+" 号文件密码修改成功!\n" );
            } else {
                PrintErrInf(status);   //返回代码提示
            }

        }else if (args[0].equals("6"))           //读CPU卡内文件信息
        {
            int status;                          //存放返回值
            byte AKLen = 16 ;                    //文件 认证密码 长度
            byte[] Autkey = new byte[AKLen];     //文件 认证密码
            byte FileIndex=0;                    //文件号,取值0 到 5
            byte DataStart=0;                    //读起始位置
            byte DataLen = 50 ;                  //读长度最大不能超过255,如文件长度>255 要循环读取
            byte[] DataBuf = new byte[DataLen];  //读文件数据缓冲
            byte ctrlCode=2;                     //取值 0 表示用只读密码来认证,取值 2 表示用读写密码来认证

            for(int i=0;i<16;i++){               //文件认证密码
                Autkey[i]=(byte) 0xff;
            }

            System.out.print("\n6-读CPU卡内文件信息\n");
            status = (int)(CLibrary.sdtapi.cpursfiledataread(FileIndex, ctrlCode, Autkey, AKLen, DataStart, DataBuf,DataLen) & 0xff);//& 0xff用于转为无符号行数据
            if (status == 0 ) {
                CLibrary.sdtapi.pcdbeep(38);
                String filedata="";
                for (int i = 0; i < DataLen; i++) {
                    String bytestr = "00" + Integer.toHexString(DataBuf[i] & 0xff);
                    filedata = filedata + bytestr.substring(bytestr.length() - 2, bytestr.length()) +" ";
                }
                System.out.print(Integer.toHexString(FileIndex)+" 号文件读取数据:"+filedata+"\n" );
            } else {
                PrintErrInf(status);   //返回代码提示
            }

        }else if (args[0].equals("7"))           //写数据到文件内
        {
            int status;                          //存放返回值
            byte AKLen = 16 ;                    //文件 认证密码 长度
            byte[] Autkey = new byte[AKLen];     //文件 认证密码
            byte FileIndex=0;                    //文件号,取值0 到 5
            byte DataStart=0;                    //写起始位置
            byte DataLen = 50 ;                  //写长度最大不能超过247,如文件长度>247 要循环写入
            byte[] DataBuf = new byte[DataLen];  //写文件数据缓冲
            byte ctrlCode=2;                     //取值 0 表示用只读密码来认证,取值 2 表示用读写密码来认证

            for(int i=0;i<16;i++){               //文件认证密码
                Autkey[i]=(byte) 0xff;
            }

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

            System.out.print("\n7-写数据到文件内\n");
            status =(int)(CLibrary.sdtapi.cpursfiledatawrite(FileIndex, ctrlCode, Autkey, AKLen, DataStart, DataBuf,DataLen) & 0xff);//& 0xff用于转为无符号行数据
            if (status == 0 ) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print(Integer.toHexString(FileIndex)+" 号文件写数据成功!\n" );
            } else {
                PrintErrInf(status);   //返回代码提示
            }

        }else if (args[0].equals("8"))           //修改改卡片密码(一般无必要修改,卡密码与文件内数据无关)
        {
            int status;                          //存放返回值
            byte OKLen = 16;                     //卡 旧密码 长度
            byte[] Oldkey = new byte[OKLen];     //卡 旧密码

            byte NKLen = 16;                     //卡 新密码密码 长度
            byte[] Newkey = new byte[NKLen];     //卡 新密码密码

            for (int i = 0; i < 16; i++) {       //修改卡密码请记住
                Oldkey[i] = (byte) 0xff;
                Newkey[i] = (byte) 0xff;
            }

            System.out.print("\n8-修改CPU卡片密码\n");
            status =(int)(CLibrary.sdtapi.cpurscardkeychg(Oldkey, OKLen, Newkey, NKLen) & 0xff);//& 0xff用于转为无符号行数据
            if (status == 0 ) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print("CPU卡修改卡片密码成功!\n");
            } else {
                PrintErrInf(status);   //返回代码提示
            }

        }else if (args[0].equals("9")){    //强制清空已用cpursinit函数成功初始化过的卡
            int status=(int)(CLibrary.sdtapi.cpurscardclr() & 0xff);//& 0xff用于转为无符号行数据
            if (status == 0 ) {
                CLibrary.sdtapi.pcdbeep(38);
                System.out.print("\n强制清空卡成功!\n");
            } else if(status == 64){
                System.out.print("此卡为未经过我们cpursinit函数成功初始化的卡!\n");
            }else{
                PrintErrInf(status);   //返回代码提示
            }
        }
    }

    //----------------------------------------------------------------------------------返回代码提示
    static void PrintErrInf(int errcode) {
        switch(errcode){
            case 8:
                System.out.print("错误代码:8,未寻到卡,请重新拿开卡后再放到感应区!\n");
                break;
            case 21:
                System.out.print("错误代码:21,没有动态库!\n");
                break;
            case 22:
                System.out.print("错误代码:22,动态库或驱动程序异常!\n");
                break;
            case 23:
                System.out.print("错误代码:23,驱动程序错误或尚未安装!\n");
                break;
            case 24:
                System.out.print("错误代码:24,操作超时,一般是动态库没有反映!\n");
                break;
            case 25:
                System.out.print("错误代码:25,发送字数不够!\n");
                break;
            case 26:
                System.out.print("错误代码:26,发送的CRC错!\n");
                break;
            case 27:
                System.out.print("错误代码:27,接收的字数不够!\n");
                break;
            case 28:
                System.out.print("错误代码:28,接收的CRC错!\n");
                break;
            case 50:
                System.out.print("错误代码:50,RATS错误,厂家调试代码,用户不需理会!\n");
                break;
            case 51:
                System.out.print("错误代码:51,PPS错误,厂家调试代码,用户不需理会!\n");
                break;
            case 52:
                System.out.print("错误代码:52,已进入了14443-4协议状态,可进行CPU卡功能所有操作了!\n");
                break;
            case 53:
                System.out.print("错误代码:53,CPU卡功能通讯错误,请先激活卡片!\n");
                break;
            case 54:
                System.out.print("错误代码:54,数据不足,需要接着发送未完成的数据至卡上!\n");
                break;
            case 55:
                System.out.print("错误代码:55,发送ACK指令给卡,让卡接着发送数据回来!\n");
                break;
            case 56:
                System.out.print("错误代码:56,清空根目录失败!\n");
                break;
            case 57:
                System.out.print("错误代码:57,卡片不支持功能!\n");
                break;
            case 58:
                System.out.print("错误代码:58,卡片初始化失败!\n");
                break;
            case 59:
                System.out.print("错误代码:59,分配的空间不足!\n");
                break;
            case 60:
                System.out.print("错误代码:60,本次操作的实体已存在!\n");
                break;
            case 61:
                System.out.print("错误代码:61,无足够空间!\n");
                break;
            case 62:
                System.out.print("错误代码:62,文件不存在!\n");
                break;
            case 63:
                System.out.print("错误代码:63,权限不足,有可能是用只读密码认证,导致无法更改读写密码或无法写文件!\n");
                break;
            case 64:
                System.out.print("错误代码:64,密码不存在,或密钥文件未创建!\n");
                break;
            case 65:
                System.out.print("错误代码:65,传送长度错误!\n");
                break;
            case 66:
                System.out.print("错误代码:66,Le错误,即接收的数据长度指定过大!\n");
                break;
            case 67:
                System.out.print("错误代码:67,功能不支持或卡中无MF 或卡片已锁定!\n");
                break;
            case 68:
                System.out.print("错误代码:68,密码认证错误次数过多,该密码已被锁死!\n");
                break;
            case 70:
            case 71:
            case 72:
            case 73:
            case 74:
            case 75:
            case 76:
            case 77:
            case 78:
            case 79:
            case 80:
            case 81:
            case 82:
            case 83:
            case 84:
            case 85:
                System.out.print("错误代码:"+Integer.toString(errcode)+",密码错误,剩余次数为"+Integer.toString(errcode-70)+",如果为0,该密码将锁死,无法再认证!\n");
                break;
            case 86:
                System.out.print("错误代码:"+Integer.toString(errcode)+",更改后的密码长度必须和创建时的长度一致!\n");
                break;
            case 87:
                System.out.print("错误代码:"+Integer.toString(errcode)+",应用目录不存在!\n");
                break;
            case 88:
                System.out.print("错误代码:"+Integer.toString(errcode)+",应用文件不存在!\n");
                break;
            case 89:
                System.out.print("错误代码:"+Integer.toString(errcode)+",文件号不能超过 5 \n");
                break;
            case 90:
                System.out.print("错误代码:"+Integer.toString(errcode)+",读取文件时返回的长度不足,数据可能不正确!\n");
                break;
            case 91:
                System.out.print("错误代码:"+Integer.toString(errcode)+",一次读文件的长度不能超过 255\n");
                break;
            case 92:
                System.out.print("错误代码:"+Integer.toString(errcode)+",一次写文件的长度不能超过 247\n");
                break;
            default:
                System.out.print("未知错误,错误代码:"+Integer.toString(errcode)+"\n");
                break;
        }
    }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vx_13822155058

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值