Java读写MF3 D21、D41、D81卡,修改Mifare Desfire EV1 EV2 EV3 DES、3K3DES、AES加解密、创建应用、读写文件源码,支持国产龙芯麒麟统信Linux系统
本文介绍了Java基于OUR_MIFARE.dll动态库的Desfire卡操作示例,包含20个核心功能:1. 动态库加载与跨平台兼容处理;2. 卡片激活与信息获取;3. 应用选择与管理(AID操作);4. 密钥认证与修改;5. 文件操作(创建/读取/写入);6. 卡片格式化等。代码展示了完整的Desfire卡操作流程,包括密钥配置、应用管理、文件读写等关键功能,支持Windows/Linux平台,
·
本示例使用的发卡器: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));
}
更多推荐
所有评论(0)