本示例使用的发卡器:https://item.taobao.com/item.htm?spm=a21dvs.23580594.0.0.1d292c1boOT14I&ft=t&id=917152255720

Desfire EV1 EV2 EV3卡说明:
一、AID:000000为PICC主应用,在主应用下EV1卡可以随意更改加解密方法,EV2/EV3卡从DES改为3K3DES/AES后不能再改回DES(返回917E的提示);
二、新出厂的卡片PICC 0号主控密钥为8字节的DES密钥,密钥为 00 00 00 00 00 00 00 00;
三、新创建的2K3DES、AES密钥16字节 ,密钥为 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
四、新创建的3K3DES 密钥24字节 ,密钥为 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
五、在非主应用下加解密方法是在创建应用时指定的,不能更改(返回911E或917E)。

一、加载发卡器驱动库函数

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

interface CLibrary extends Library {
    //不同版本的读写器,接口DLL文件名称、函数名称是一样的,但内核代码不一样,请选用与读写器、操作系统一致的OUR_MIFARE.dll 或 libOURMIFARE.so 库
    CLibrary INSTANCE = loadLibrary();

    static CLibrary loadLibrary() {
        if (Platform.isWindows()) {
            return Native.loadLibrary(System.getProperty("user.dir") + "\\OUR_MIFARE.dll", CLibrary.class);
        } else if (Platform.isLinux()) {
            return Native.loadLibrary(System.getProperty("user.dir") + "/libOURMIFARE.so", CLibrary.class);
        } else if (Platform.isMac()) {
            return Native.loadLibrary(System.getProperty("user.dir") + "/libOURMIFARE.dylib", CLibrary.class);
        } else {
            throw new RuntimeException("Unsupported operating system");
        }
    }

    byte pcdbeep(int xms);                         //让设备发出声音
    byte pcdgetdevicenumber(byte[] devicenumber);  //读取设备编号
    byte cpurequest1(byte[] mypiccserial,byte[] myparam,byte[] myver,byte[] mycode,byte[] AtqaSak);    //激活Desfire卡
    byte desfireselectapplication(byte[] aidbuf,byte[] retsw);  //选择卡内应用
    byte desfireauthkeyev1(byte[] keybuf, byte keyid,byte authmode,byte[] retsw);  //EV1 EV2 Ev3卡密钥认证
    byte desfirechangekeyev1(byte[] newkeybuf, byte keyid, byte authmode, byte zeno, byte[] oldkeybuf, byte[] retsw); //更改密钥
    byte desfireauthkeyev2(byte[] keybuf, byte keyid, byte authmode, byte[] retsw); //EV2 Ev3卡AES密钥认证
    byte desfireformatpicc(byte[] retsw);       //初始化卡(格式化卡) 返回 910E 时用
    byte desfiredeleteapplication(byte[] aid, byte[] retsw);        //删除desfire卡内的应用AID
    byte desfirecreateapplication(byte[] aid, byte keysetting,byte keynumver, byte keytype, byte[] retsw);      //在desfire卡根目录下创建新应用AID
    byte desfiregetapplicationids(byte[] aidbuf, byte[] aidsize,  byte[] retsw);        //查询desfire卡内所有的应用AID-
    byte desfiregetkeysettings(byte[] aidbuf, byte[] keysetting, byte[] keysize, byte[] retsw);     //获取AID应用的密钥配置信息
    byte desfirechangekeysettings(byte[] aidbuf, byte keysetting, byte[] retsw);        //更改desfire卡内的应用的密钥配置信息
    byte desfirecreatestddatafile(byte fileid, byte comset, byte[] accessrights, int  filesize, byte[] retsw);      //在desfire应用中创建标准文件
    byte desfircreatebackupdatafile(byte fileid, byte comset, byte[] accessrights, int filesize, byte[] retsw);     //在desfire应用中创建备份文件
    byte desfiregetfileids(byte[] fileid, byte[] filessize,  byte[] retsw);     //读取应用中的所有文件ID
    byte desfiregetfilesettings(byte fileid, byte[] filesettingsbuf, byte[] revbuflen, byte[] retsw);       //读取desfire卡应用中文件的配置信息
    byte desfirechangefilesettings(byte fileid, byte comset, byte[] accessrights,  byte[] retsw);       //更改desfire卡应用中文件的配置信息
    byte desfiredeletefile(byte fileid, byte[] retsw);      //删除应用中的文件
    byte desfirereaddata(byte cmd, byte fileno, int offset, int datalen, byte[] databuf, byte[] retsw);     //读文件
    byte desfirewritedata(byte cmd, byte fileno, int offset, int datalen, byte[] databuf, byte[] retsw);        //写文件
    byte desfirecommittransaction(byte[] retsw);        //提交事务
    byte desfireaborttransaction(byte[] retsw);     //取消事务
    byte getmifareversion(byte[] cardtypestr, byte[] AtqaSak, byte[] versionbuf, byte[] versionlen, byte[] retsw);      //获取IC卡芯片型号
}

 二、激活发卡器上的Desfire卡

byte[] mypiccserial = new byte[7];   //卡序列号
byte[] myparam = new byte[4];        //4字节卡参数
byte[] AtqaSak = new byte[3];
byte[] myver = new byte[1];
byte[] mycode = new byte[1];
System.out.print("\n2-激活射频区内的卡,每次卡离开过感应区都要先激活才能继续操作卡片\n");
byte status = (byte) (CLibrary.INSTANCE.cpurequest1(mypiccserial, myparam, myver, mycode, AtqaSak) & 0xff);//& 0xff用于转为无符号行数据
if (status == 0 || status == 52) {
	CLibrary.INSTANCE.pcdbeep(38);
	String verstr = String.format("%02X", myver[0]);
	String codestr = String.format("%02X", mycode[0]);
	String atqastr = String.format("%02X", AtqaSak[0]) + String.format("%02X", AtqaSak[1]);
	String sakstr = String.format("%02X", AtqaSak[2]);
	String parastr = "";
	for (int i = 0; i < 4; i++) {
		parastr = parastr + String.format("%02X", myparam[i]);
	}
	String cardhohex = "";
	if (AtqaSak[0] / 64 > 0) {
		for (int i = 0; i < 7; i++) {
			cardhohex = cardhohex + String.format("%02X", mypiccserial[i]);
		}
		System.out.print("激活Desfire卡成功,可以接着重复操作第二步进行调试了,\n卡号:" + cardhohex + "\n参数:" + parastr + "\nATQA:" + atqastr + "\nSAK:" + sakstr + "\n版本:" + verstr + "\n厂商代码:" + codestr + "\n");
	} else {
		for (int i = 0; i < 4; i++) {
			cardhohex = cardhohex + String.format("%02X", mypiccserial[i]);
		}
		System.out.print("激活Fm1208CPU卡成功,可以接着重复操作第二步进行调试了,\n卡号:" + cardhohex + "\n参数:" + parastr + "\nATQA:" + atqastr + "\nSAK:" + sakstr + "\n版本:" + verstr + "\n厂商代码:" + codestr + "\n");
	}
} else {
	PrintErrInf(status);   //返回代码提示
}

三、选择卡内的APP应用

String aidstr = "00 00 01";       //16进制的aid,00 00 00 表示PICC
byte[] aidbuf = new byte[3];
if (checkhexstr(aidstr, 3, aidbuf)) {
	byte[] retsw = new byte[2];     //卡操作返回代码
	byte status = (byte) (CLibrary.INSTANCE.desfireselectapplication(aidbuf, retsw) & 0xff);
	String retstr = String.format("%02X", retsw[0]) + String.format("%02X", retsw[1]);
	if (status == 0) {
		System.out.print("选择卡内AID为 " + aidstr + " 的操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	} else {
		System.out.print("选择卡内AID为 " + aidstr + " 的操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	}
} else {
	System.out.print("十六进制AID输入错误,请输入3字节的16进制AID!\n");
}

四、卡密钥认证

byte Encryption_method = 0;       //加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
String authkeystr;                //认证密钥
byte[] authkeybuf = new byte[24];
int keylen;                       //密钥长度
byte keyid = 0;                   //要认证的密钥编号,取值为:0-13,0为主控密钥
switch (Encryption_method) {
	case 0:       //DES
		keylen = 8;
		authkeystr = "00 00 00 00 00 00 00 00";
		break;
	case 2:        //3K3DES
		keylen = 24;
		authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
		break;
	default:        //2K3Des、AES 密钥长度都为 16 个字节
		keylen = 16;
		authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
}
if (checkhexstr(authkeystr, keylen, authkeybuf)) {
	byte[] retsw = new byte[2];     //卡操作返回代码
	byte status = (byte) (CLibrary.INSTANCE.desfireauthkeyev1(authkeybuf, keyid, Encryption_method, retsw) & 0xff);
	String retstr = String.format("%02X", retsw[0]) + String.format("%02X", retsw[1]);
	if (status == 0) {
		System.out.print("认证密钥编号为 " + String.format("%d", keyid) + " 的操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	} else {
		System.out.print("认证密钥编号为 " + String.format("%d", keyid) + " 的操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	}
} else {
	System.out.print("十六进制认证密钥输入错误,请输入" + String.format("%d", keylen) + "字节的16进制认证密钥!\n");
}

 五、更改密钥

byte new_Encryption_method = 0;     //新加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
String oldkeystr;                   //旧密钥
byte[] oldkeybuf = new byte[24];
String newkeystr;                   //新密钥
byte[] newkeybuf = new byte[24];
int keylen;                         //密钥长度
byte changekeyid = 1;               //要更改的密钥编号,取值为:0-13,0为主控密钥
byte authkeyid=0;                   //更改changekeyid密钥前 必须认证的密钥,此参数由 密钥配置值 决定。
switch (new_Encryption_method) {
	case 0:       //DES
		keylen = 8;
		oldkeystr = "00 00 00 00 00 00 00 00";
		newkeystr = "00 00 00 00 00 00 00 00";
		break;
	case 2:        //3K3DES
		keylen = 24;
		oldkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
		newkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
		break;
	default:        //2K3Des、AES 密钥长度都为 16 个字节
		keylen = 16;
		oldkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
		newkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
}
if (checkhexstr(oldkeystr, keylen, oldkeybuf) == false) {
	System.out.print("十六进制旧密钥输入错误,请输入" + String.format("%d", keylen) + "字节的16进制旧密钥!\n");
	return;
}
if (checkhexstr(newkeystr, keylen, newkeybuf) == false) {
	System.out.print("十六进制旧新钥输入错误,请输入" + String.format("%d", keylen) + "字节的16进制新密钥!\n");
	return;
}
if (authkeyev1(new_Encryption_method,authkeyid,oldkeystr)) {  //先认证旧密钥,入口参数authkeyid要根据密钥配值信息来赋值,如更改当前密钥要先认证0密钥就要
	byte[] retsw = new byte[2];     //卡操作返回代码
	byte status = (byte) (CLibrary.INSTANCE.desfirechangekeyev1(newkeybuf, changekeyid, new_Encryption_method, (byte) 0, oldkeybuf, retsw) & 0xff);
	String retstr = String.format("%02X", retsw[0]) + String.format("%02X", retsw[1]);
	if (status == 0) {
		System.out.print("更改 " + String.format("%d", changekeyid) + " 号密钥操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	} else {
		System.out.print("更改 " + String.format("%d", changekeyid) + " 号密钥操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	}
}else{
	System.out.print("旧密钥认证失败,更改 " + String.format("%d", changekeyid) + " 号密钥失败!");
}

六、读取PICC主控密钥配置值

byte[] aidbuf = new byte[3];
for(int i=0;i<3;i++){aidbuf[i]=0x00;}    //PICC的AID是 00 00 00
byte[] keysetting=new byte[1];
byte[] keysize=new byte[1];
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfiregetkeysettings(aidbuf, keysetting, keysize, retsw) & 0xff);
String retstr = String.format("%02X", retsw[0]) + String.format("%02X", retsw[1]);
if (status == 0) {
	int keyset0;      //更改PICC密钥配置值: 0配置值不允许修改(锁定); 1需要验证应用主密钥(默认)
	if ((keysetting[0] & 8) > 0){
		keyset0=1;
	}else{keyset0=0;}
	int keyset1;      //创建APP应用时:0需要验证应用主密钥; 1无需验证应用主密钥(默认)
	if ((keysetting[0] & 4) > 0){
		keyset1=1;
	}else{keyset1=0;}
	int keyset2;     //获取App应用ID、密钥配置时:0需要验证应用主密钥; 1无需验证应用主密钥(默认)
	if ((keysetting[0] & 2) > 0){
		keyset2=1;
	}else{keyset2=0;}
	int keyset3;    //PICC主密钥:0锁定主密钥; 1允许更改主密钥(默认)
	if ((keysetting[0] & 1) > 0){
		keyset3=1;
	}else{keyset3=0;}

	int keynum = keysize[0] % 64;

	String strls1="\n加密方式:";
	if ((keysize[0] & 0xc0) == 0x80) {
		strls1 = strls1+"AES";
	} else {
		if ((keysize[0] & 0xc0) == 0x40) {
			strls1 = strls1+"3K3DES";
		}else {
			strls1 = strls1+"DES 或 2K3DES";
		}
	}
	System.out.print("读取PICC主控密钥配置操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr)+"密钥数量:"+String.format("%d", keynum)+"\n配置参数:"+String.format("%02X", keysetting[0])+strls1);
} else {
	if (status == 94) {
		System.out.print("读取PICC主控密钥配置操作失败!请先执行选择应用AID:00 00 00");
	}else{
		System.out.print("读取PICC主控密钥配置操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	}
}

 七、更改PICC主控密钥配置

byte Encryption_method = 0;       //加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
String authkeystr;                //认证密钥
switch (Encryption_method) {
	case 0:       //DES加密,密钥长度8个字节
		authkeystr = "00 00 00 00 00 00 00 00";
		break;
	case 2:        //3K3DES加密,密钥长度24个字节
		authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
		break;
	default:        //2K3Des、AES 密钥长度都为 16 个字节
		authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
}
if (authkeyev1(Encryption_method,(byte)0,authkeystr)==false) {  //更改PICC主控密钥配置前必须先认证主控密钥
	System.out.print("PICC 0号主控密钥认证失败,无法更改PICC主控密钥配置值!");
	return;
}

byte[] aidbuf = new byte[3];
for(int i=0;i<3;i++){aidbuf[i]=0x00;}    //PICC的AID是 00 00 00
int keyset0=1;      //更改PICC密钥配置值:      0配置值不允许修改(锁定); 1需要验证应用主密钥(默认),警告,此参数如取0的设置对卡片是不可逆转的!!!!!
int keyset1=1;      //创建APP应用时:          0需要验证应用主密钥;     1无需验证应用主密钥(默认)
int keyset2=1;      //获取App应用ID、密钥配置时:0需要验证应用主密钥;     1无需验证应用主密钥(默认)
int keyset3=1;      //PICC主密钥:            0锁定主密钥;            1允许更改主密钥(默认)
byte keysetting =(byte)(keyset0*8 + keyset1*4 + keyset2*2 + keyset3);
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfirechangekeysettings(aidbuf, keysetting, retsw) & 0xff);
String retstr = String.format("%02X", retsw[0]) + String.format("%02X", retsw[1]);
if (status == 0){
	System.out.print("更改PICC主控密钥配置操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}else {
	if (status == 94) {
		System.out.print("更改PICC主控密钥配置操作失败!请先执行选择应用AID:00 00 00");
	}else{
		if (status == 63){
			System.out.print("更改PICC主控密钥配置操作失败!需要先验证PICC的主密钥!");
		}else {
			System.out.print("更改PICC主控密钥配置操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
		}
	}
}

 八、搜索卡上所有APP应用的AID号

boolean auth0keyEn=false;           //搜索PICC内所有APP应用AID是否要先认证0号主控密钥由PICC密钥配置值决定,出厂默认不需要。
if (auth0keyEn){
	byte Encryption_method = 0;     //加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
	String authkeystr;              //认证密钥
	switch (Encryption_method) {
		case 0:       //DES加密,密钥长度8个字节
			authkeystr = "00 00 00 00 00 00 00 00";
			break;
		case 2:        //3K3DES加密,密钥长度24个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
			break;
		default:        //2K3Des、AES 密钥长度都为 16 个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
	}
	if (authkeyev1(Encryption_method,(byte)0,authkeystr)==false) {
		System.out.print("PICC 0号主控密钥认证失败,无法获取到PICC内所应APP应用的AID!");
		return;
	}
}

byte[] aidbuf = new byte[57];   //应用AID号数据缓冲,每个AID号占用3个字节,最多19个应AID号
byte[] aidsize=new byte[1];     //返回的应用数量,最大19个
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfiregetapplicationids(aidbuf, aidsize, retsw) & 0xff);
String retstr = String.format("%02X", retsw[0]) + String.format("%02X", retsw[1]);
if (status == 0) {
	String strls1="";
	if (aidsize[0] > 0){
		strls1 = "应用AID:"+String.format("%02X%02X%02X",  aidbuf[0], aidbuf[1], aidbuf[2]);
		int j=1;
		while (j<aidsize[0]){
			strls1 = strls1 + ","+String.format("%02X%02X%02X",  aidbuf[j*3], aidbuf[j*3+1], aidbuf[j*3+2]);
			j++;
		}
	}
	System.out.print("搜索当前卡片内所有应用AID操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr)+"应用数量:"+String.format("%d",aidsize[0])+"\n"+strls1);
}else {
	System.out.print("搜索当前卡片内所有应用AID操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}

 九、创建新的APP应用

boolean auth0keyEn=false;           //创建新APP应用是否要先认证0号主控密钥由PICC密钥配置值决定,出厂默认不需要。
if (auth0keyEn){
	byte Encryption_method = 0;     //加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
	String authkeystr;              //认证密钥,不同的加密方式密钥长度不一 样
	switch (Encryption_method) {
		case 0:       //DES加密,密钥长度8个字节
			authkeystr = "00 00 00 00 00 00 00 00";
			break;
		case 2:        //3K3DES加密,密钥长度24个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
			break;
		default:        //2K3Des、AES 密钥长度都为 16 个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
	}
	if (authkeyev1(Encryption_method,(byte)0,authkeystr)==false) {
		System.out.print("PICC 0号主控密钥认证失败,无法获取到PICC内所应APP应用的AID!");
		return;
	}
}

String aidstr="00 00 01";       //本次新创建的APP应用AID
byte[] aidbuf=new byte[3];
if (checkhexstr(aidstr, 3, aidbuf)==false) {
	System.out.print("十六进制新AID输入错误,请输入3字节16进制的新AID!");
	return;
}
if(aidbuf[0]+aidbuf[1]+aidbuf[2]==0){
	System.out.print("新创建的应用AID不可以是PICC级的主应用!");
	return;
}
int keyset0=0;      //更改应用密钥(非应用主密钥)需要认证的密钥:   取值范围 0-15,取值14表示:要改本号密钥就先验证本号密钥,15表示:不允许修改(锁定), 默认取值0表示要认证0号主密钥
int keyset1=1;      //更改应用密钥配置值:                     0配置值不允许修改(锁定);     1需要验证应用主密钥(默认)
int keyset2=1;      //创建文件或删除文件时:                   0需要验证应用主密钥;         1无需验证应用主密钥(默认)
int keyset3=1;      //查找 文件ID,文件设置,密钥配置时:          0需要验证应用主密钥;         1无需验证应用主密钥(默认)
int keyset4=1;      //应用主密钥:                           0锁定主密钥;               1允许更改主密钥(默认)
byte keysetting =(byte)(keyset0*16 + keyset1*8 + keyset2*4 + keyset3*2 + keyset4);  //新APP应用的配置值
byte keynumber= 14;               //新应用的密钥总数量,取值范围 1-14,默认14
byte NewApp_Encryption_method=0;  //新创建的APP加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
byte[] retsw = new byte[2];       //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfirecreateapplication(aidbuf, keysetting,keynumber,NewApp_Encryption_method,retsw) & 0xff);
String retstr = String.format("%02X", retsw[0]) + String.format("%02X", retsw[1]);
if (status == 0){
	System.out.print("创建AID为 "+aidstr+" 的新APP应用操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}else{
	System.out.print("创建AID为 "+aidstr+" 的新APP应用操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}

十、读取APP密钥配置值

String aidstr="00 00 01";    //要读取配置值的APP应用AID
byte[] aidbuf=new byte[3];
if (checkhexstr(aidstr, 3, aidbuf)==false) {
	System.out.print("十六进制AID输入错误,请输入3字节16进制的AID!");
	return;
}
if(aidbuf[0]+aidbuf[1]+aidbuf[2]==0){
	System.out.print("在这里不能操作PICC级AID为00 00 00的主应用!");
	return;
}
if (selectapp(aidbuf)==false) {
	System.out.print("选择卡内AID为 " + String.format("%02X%02X%02X",  aidbuf[0], aidbuf[1], aidbuf[2])+" 的APP应用失败,无法读取其配置值。" );
	return;
} 

boolean auth0keyEn=false;           //读取APP应用配置值是否要先认证0号主控密钥由文件创建时决定。由配置值决定是否要运行这段密钥认证过程
if (auth0keyEn){
	byte Encryption_method = 0;     //加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
	String authkeystr;              //认证密钥
	switch (Encryption_method) {
		case 0:       //DES加密,密钥长度8个字节
			authkeystr = "00 00 00 00 00 00 00 00";
			break;
		case 2:        //3K3DES加密,密钥长度24个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
			break;
		default:        //2K3Des、AES 密钥长度都为 16 个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
	}
	if (authkeyev1(Encryption_method,(byte)0,authkeystr)==false) {
		System.out.print("0号主控密钥认证失败,无法获取APP的配置值!");
		return;
	}
}

byte[] keysetting=new byte[1];
byte[] keysize=new byte[1];
byte[] retsw = new byte[2];       //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfiregetkeysettings(aidbuf, keysetting,keysize,retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0) {
	int keyset0;      //更改应用密钥(非应用主密钥)需要认证的密钥:   取值范围 0-15,取值14表示:要改本号密钥就先验证本号密钥,15表示:不允许修改(锁定), 默认取值0表示要认证0号主密钥
	int keyset1;      //更改应用密钥配置值:                     0配置值不允许修改(锁定);     1需要验证应用主密钥(默认)
	int keyset2;      //创建文件或删除文件时:                   0需要验证应用主密钥;         1无需验证应用主密钥(默认)
	int keyset3;      //查找 文件ID,文件设置,密钥配置时:          0需要验证应用主密钥;         1无需验证应用主密钥(默认)
	int keyset4;      //应用主密钥:                           0锁定主密钥;               1允许更改主密钥(默认)

	keyset0= keysetting[0] / 16;

	if ((keysetting[0] & 8) > 0){
		keyset1=1;
	}else{keyset1=0;}

	if ((keysetting[0] & 4) > 0){
		keyset2=1;
	}else{keyset2=0;}

	if ((keysetting[0] & 2) > 0){
		keyset3=1;
	}else{keyset3=0;}

	if ((keysetting[0] & 1) > 0){
		keyset4=1;
	}else{keyset4=0;}

	int keynum = keysize[0] % 64;

	String strls1="\n加密方式:";
	if ((keysize[0] & 0xc0) == 0x80) {
		strls1 = strls1+"AES";
	} else {
		if ((keysize[0] & 0xc0) == 0x40) {
			strls1 = strls1+"3K3DES";
		}else {
			strls1 = strls1+"DES 或 2K3DES";
		}
	}
	System.out.print("读取AID为 "+aidstr+" 的密钥配置操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr)+"密钥数量:"+String.format("%d", keynum)+"\n配置参数:"+String.format("%02X", keysetting[0])+strls1);
} else {
	if (status == 94) {
		System.out.print("读取AID为 "+aidstr+" 的密钥配置操作失败!请先执行选择应用AID:"+aidstr);
	}else{
		System.out.print("读取AID为 "+aidstr+" 的密钥配置操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	}
}

十一、更改APP密钥配置值

String aidstr="00 00 01";     //要更改配置值的APP应用AID
byte[] aidbuf=new byte[3];
if (checkhexstr(aidstr, 3, aidbuf)==false) {
	System.out.print("十六进制AID输入错误,请输入3字节16进制的AID!");
	return;
}
if(aidbuf[0]+aidbuf[1]+aidbuf[2]==0){
	System.out.print("在这里不能操作PICC级AID为00 00 00的主应用!");
	return;
}
if (selectapp(aidbuf)==false) {
	System.out.print("选择卡内AID为 " + String.format("%02X%02X%02X",  aidbuf[0], aidbuf[1], aidbuf[2])+" 的APP应用失败,无法更改其配置值。" );
	return;
}

boolean auth0keyEn=true;            //APP应用配置值是否可以更改由创建APP创建时的配置值决定。如 设为默认的 可以验证主控密钥后更改配置,就运行此段程序,
if (auth0keyEn){
	byte Encryption_method = 0;     //加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
	String authkeystr;              //认证密钥
	switch (Encryption_method) {
		case 0:       //DES加密,密钥长度8个字节
			authkeystr = "00 00 00 00 00 00 00 00";
			break;
		case 2:        //3K3DES加密,密钥长度24个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
			break;
		default:        //2K3Des、AES 密钥长度都为 16 个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
	}
	if (authkeyev1(Encryption_method,(byte)0,authkeystr)==false) {
		System.out.print("0号主控密钥认证失败,无法更改APP的配置值!");
		return;
	}
}
int keyset0=0;      //更改应用密钥(非应用主密钥)需要认证的密钥:   取值范围 0-15,取值14表示:要改本号密钥就先验证本号密钥,15表示:不允许修改(锁定), 默认取值0表示要认证0号主密钥
int keyset1=1;      //更改应用密钥配置值:                     0配置值不允许修改(锁定);     1需要验证应用主密钥(默认)
int keyset2=1;      //创建文件或删除文件时:                   0需要验证应用主密钥;         1无需验证应用主密钥(默认)
int keyset3=1;      //查找 文件ID,文件设置,密钥配置时:          0需要验证应用主密钥;         1无需验证应用主密钥(默认)
int keyset4=1;      //应用主密钥:                           0锁定主密钥;               1允许更改主密钥(默认)
byte keysetting = (byte)(keyset0*16 + keyset1*8 + keyset2*4 + keyset3*2 +keyset4);
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfirechangekeysettings(aidbuf, keysetting, retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0){
	System.out.print("更改AID为 "+String.format("%02X%02X%02X",  aidbuf[0], aidbuf[1], aidbuf[2]) +" 的主控密钥配置操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}else {
	System.out.print("更改AID为 "+String.format("%02X%02X%02X",  aidbuf[0], aidbuf[1], aidbuf[2]) +" 的主控密钥配置操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}

 十二、删除APP应用

String aidstr="00 00 01";     //要更改配置值的APP应用AID
byte[] aidbuf=new byte[3];
if (checkhexstr(aidstr, 3, aidbuf)==false) {
	System.out.print("十六进制AID输入错误,请输入3字节16进制的AID!");
	return;
}
if(aidbuf[0]+aidbuf[1]+aidbuf[2]==0){
	System.out.print("在这里不能操作PICC级AID为00 00 00的主应用!");
	return;
}
if (selectapp(aidbuf)==false) {
	System.out.print("选择卡内AID为 " + String.format("%02X%02X%02X",  aidbuf[0], aidbuf[1], aidbuf[2])+" 的APP应用失败,无法更改其配置值。" );
	return;
}

boolean auth0keyEn=true;            //删除APP需要先认证主密钥
if (auth0keyEn){
	byte Encryption_method = 0;     //加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
	String authkeystr;              //认证密钥
	switch (Encryption_method) {
		case 0:       //DES加密,密钥长度8个字节
			authkeystr = "00 00 00 00 00 00 00 00";
			break;
		case 2:        //3K3DES加密,密钥长度24个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
			break;
		default:        //2K3Des、AES 密钥长度都为 16 个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
	}
	if (authkeyev1(Encryption_method,(byte)0,authkeystr)==false) {
		System.out.print("0号主控密钥认证失败,无法删除APP应用!");
		return;
	}
}

byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfiredeleteapplication(aidbuf,  retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0){
	System.out.print("删除AID为 "+String.format("%02X%02X%02X",  aidbuf[0], aidbuf[1], aidbuf[2]) +" 的APP应用操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}else {
	System.out.print("删除AID为 "+String.format("%02X%02X%02X",  aidbuf[0], aidbuf[1], aidbuf[2]) +" 的APP应用操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}

 十三、搜索APP应用内所有文件ID

byte[] fidbuf = new byte[16];   //文件fid数据缓冲,每个fid号占用1个字节,最多16个应fid
byte[] fidsize=new byte[1];     //返回的文件数量,最大16个
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfiregetfileids(fidbuf, fidsize, retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0) {
	String strls1="";
	if (fidsize[0] > 0){
		strls1 = "文件ID:"+String.format("%d",  fidbuf[0]);
		int j=1;
		while (j<fidsize[0]){
			strls1 = strls1 + ","+String.format("%d",  fidbuf[j]);
			j++;
		}
	}
	System.out.print("搜索当前APP应用内所有文件ID操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr)+"应用数量:"+String.format("%d",fidsize[0])+"\n"+strls1);
}else {
	System.out.print("搜索当前APP应用内所有应文件ID操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}

十四、在当前APP应用内创建新的可读写的文件

byte fileid=4;        //新文件ID号
byte comset=0;        //通讯模式:   0透明传输; 1MAC保护;  3数据加密+MAC保护
byte[] accessrights=new byte[2];        //文件访问时的密钥认证方式
int accessright0=14;     //只读时需要认证的密钥号:   取值范围 0-15, 14表示无需密码, 15表示禁止
int accessright1=14;     //只写时需要认证的密钥号:   取值范围 0-15, 14表示无需密码, 15表示禁止
int accessright2=14;     //读写时需要认证的密钥号:   取值范围 0-15, 14表示无需密码, 15表示禁止
int accessright3=14;     //更改本配置时需要的密码号: 取值范围 0-15, 14表示无需密码, 15表示禁止
accessrights[0]=(byte)(accessright2*16 +  accessright3);
accessrights[1]=(byte)(accessright0*16 +  accessright1);
int filesize=64;       //新文件空门大小
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfirecreatestddatafile(fileid, comset,accessrights,filesize, retsw) & 0xff);      //创建标准数据文件
//byte status = (byte) (CLibrary.INSTANCE.desfircreatebackupdatafile(fileid, comset,accessrights,filesize, retsw) & 0xff);  //创建备份事务文件
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0) {
	System.out.print("在当前APP应用内创建新文件操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}else{
	if (status == 53) {
		System.out.print("在当前APP应用内创建新文件操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:CPU卡功能通讯错误,可能是卡拿开重放后未激活或卡不在感应区!");
	}else{
		if (status == 57) {
			if (retstr.equals("91DE")){
				System.out.print("在当前APP应用内创建新文件操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:可能的原因:1 应用没选择对,2 密码未认证,3 文件已存在!");
			}else{
				System.out.print("在当前APP应用内创建新文件操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
			}
		}else{
			System.out.print("在当前APP应用内创建新文件操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
		}
	}
}

十五、读取文件的密钥配置值 

byte fileid=1;        //文件ID号
byte[] revbuflen=new byte[1];
byte[] filesettingsbuf=new byte[32];
byte[] retsw = new byte[2];          //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfiregetfilesettings(fileid, filesettingsbuf, revbuflen, retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0) {
	String filesetstr = "";
	for (int i = 0; i < revbuflen[0]; i++) {
		filesetstr = filesetstr + String.format("%02X", filesettingsbuf[i]);
	}
	int comset;        //通讯模式:   0透明传输; 1MAC保护;  3数据加密+MAC保护
	String comsetstr;
	if (filesettingsbuf[1] % 4 == 3) {
		comset=3;
		comsetstr="\n讯模式:数据加密+MAC保护";
	}else{
		if (filesettingsbuf[1] % 4 == 1) {
			comset=1;
			comsetstr="\n讯模式:MAC保护";
		}else{
			comset=0;
			comsetstr="\n讯模式:透明传输";
		}
	}
	int accessright0=filesettingsbuf[3] / 16;     //只读时需要认证的密钥号:   取值范围 0-15, 14表示无需密码, 15表示禁止
	int accessright1=filesettingsbuf[3] % 16;     //只写时需要认证的密钥号:   取值范围 0-15, 14表示无需密码, 15表示禁止
	int accessright2=filesettingsbuf[2] / 16;     //读写时需要认证的密钥号:   取值范围 0-15, 14表示无需密码, 15表示禁止
	int accessright3=filesettingsbuf[2] % 16;     //更改本配置时需要的密码号: 取值范围 0-15, 14表示无需密码, 15表示禁止
	int filesize=filesettingsbuf[4] + filesettingsbuf[5] * 256 + filesettingsbuf[6] * 65536;  //文件空间大小
	System.out.print("读取编号为 "+ String.format("%d", fileid)+" 的文件配置操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr)+"文件空间大小:" + String.format("%d", filesize));
	System.out.print("\n配置值:"+filesetstr+comsetstr);
}else{
	System.out.print("读取编号为 "+ String.format("%d", fileid)+" 的文件配置操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}

 十六、更改文件的密钥配置值

byte fileid=1;        //文件ID号
byte comset=0;        //通讯模式:   0透明传输; 1MAC保护;  3数据加密+MAC保护
byte[] accessrights=new byte[2];        //文件访问时的密钥认证方式
int accessright0=14;     //只读时需要认证的密钥号:   取值范围 0-15, 14表示无需密码, 15表示禁止
int accessright1=14;     //只写时需要认证的密钥号:   取值范围 0-15, 14表示无需密码, 15表示禁止
int accessright2=14;     //读写时需要认证的密钥号:   取值范围 0-15, 14表示无需密码, 15表示禁止
int accessright3=14;     //更改本配置时需要的密码号: 取值范围 0-15, 14表示无需密码, 15表示禁止
accessrights[0]=(byte)(accessright2*16 +  accessright3);
accessrights[1]=(byte)(accessright0*16 +  accessright1);
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfirechangefilesettings(fileid, comset,accessrights, retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0) {
	System.out.print("更改编号为 "+ String.format("%d", fileid)+" 的文件配置操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}else{
	if (status == 53) {
		System.out.print("更改编号为 "+ String.format("%d", fileid)+" 的文件配置操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:CPU卡功能通讯错误,可能是卡拿开重放后未激活或卡不在感应区!");
	}else{
		System.out.print("更改编号为 "+ String.format("%d", fileid)+" 的文件配置操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	}
}

 十七、删除APP应用内的文件

byte fileid=1;        //文件ID号
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfiredeletefile(fileid, retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0) {
	System.out.print("删除编号为 "+ String.format("%d", fileid)+" 的文件操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}else {
	System.out.print("删除编号为 " + String.format("%d", fileid) + " 的文件操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}

十八、读文件 

boolean auth0keyEn=true;            //如果配置值为 读文件要先认证密钥,运行此段,
if (auth0keyEn){
	byte Encryption_method = 0;     //加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
	byte keyid=1;                   //认证的密钥编号, 由文件配置值决定 需要认证的密钥编号
	String authkeystr;              //认证密钥
	switch (Encryption_method) {
		case 0:       //DES加密,密钥长度8个字节
			authkeystr = "00 00 00 00 00 00 00 00";
			break;
		case 2:        //3K3DES加密,密钥长度24个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
			break;
		default:        //2K3Des、AES 密钥长度都为 16 个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
	}
	if (authkeyev1(Encryption_method,keyid,authkeystr)==false) {
		System.out.print("密钥认证失败,无法继续以下的操作!");
		return;
	}
}

byte cmd=(byte)0xBD;   //函数第1个参数为&HBD表示读数据,为&hBB表示读记录
byte fileid=1;        //文件ID号
int rwbegin=0;        //读写起始位
int rwlen=64;         //读写长度
byte[] databuf = new byte[rwlen];    //数据缓冲
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfirereaddata(cmd,fileid,rwbegin,rwlen, databuf,retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0) {
	String datastr = "";
	for (int i=0;i<rwlen;i++){datastr=datastr+String.format("%02X ", databuf[i]);}
	System.out.print("读编号为 "+ String.format("%d", fileid)+" 的文件操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	System.out.print("读取数据:"+datastr);
}else {
	if (status == 63) {
		System.out.print("读编号为 " + String.format("%d", fileid) + " 的文件操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:权限不足,请先用正确的密钥号认证!");
	}else {
		System.out.print("读编号为 " + String.format("%d", fileid) + " 的文件操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	}
}

十九、写文件 

boolean auth0keyEn=true;            //如果配置值为 写文件要先认证密钥,运行此段,
if (auth0keyEn){
	byte Encryption_method = 0;     //加密方式  0:DES  1:2K3DES  2:3K3DES  3:AES
	byte keyid=1;                   //认证的密钥编号, 由文件配置值决定 需要认证的密钥编号
	String authkeystr;              //认证密钥
	switch (Encryption_method) {
		case 0:       //DES加密,密钥长度8个字节
			authkeystr = "00 00 00 00 00 00 00 00";
			break;
		case 2:        //3K3DES加密,密钥长度24个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
			break;
		default:        //2K3Des、AES 密钥长度都为 16 个字节
			authkeystr = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";
	}
	if (authkeyev1(Encryption_method,keyid,authkeystr)==false) {
		System.out.print("密钥认证失败,无法继续以下的操作!");
		return;
	}
}

byte cmd=(byte)0x3D;   //函数第1个参数为&H3D表示写数据,为&h3B表示写记录
byte fileid=1;         //文件ID号
int rwbegin=0;         //读写起始位
int rwlen=64;          //读写长度
byte[] databuf = new byte[rwlen];    //数据缓冲
for (int i=0;i<rwlen;i++){databuf[i]=(byte)i;}   //将要写的数据存入缓冲
byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfirewritedata(cmd,fileid,rwbegin,rwlen, databuf,retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0) {
	System.out.print("写编号为 "+ String.format("%d", fileid)+" 的文件操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}else {
	if (status == 63) {
		System.out.print("写编号为 " + String.format("%d", fileid) + " 的文件操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:权限不足,请先用正确的密钥号认证!");
	}else {
		System.out.print("写编号为 " + String.format("%d", fileid) + " 的文件操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
	}
}

二十、初始格式化卡,清空卡内所有数

byte[] retsw = new byte[2];     //卡操作返回代码
byte status = (byte) (CLibrary.INSTANCE.desfireformatpicc(retsw) & 0xff);
String retstr = String.format("%02X%02X", retsw[0] , retsw[1]);
if (status == 0) {
	System.out.print("初始格式化卡操作,卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}else {
	System.out.print("初始格式化卡操作返回异常:" + String.format("%d", status) + ",卡片返回代码:" + retstr + "\n说明:" + RetTextFromStr(retstr));
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐