今天记录一下Android 非接触式M1卡是怎么样改默认密码的,因为这几天刚好帮公司撸了一下,希望能对做NFC开发这一块的兄弟们有所帮助。首先我们先要了解一下为什么要M1卡的基本构造和相关说明,这里我推荐看业余代码工作者的blog,感谢他的分享。
了解完M1卡的基本构造和相关说明后,知道了M1卡有16个扇区,每个扇区的最后一块是记录KeyA和KeyB还有控制位的。KeyA和KeyB的默认密码都是ffffffffffff,其中KeyA在所有情况下都是不可读的(大多数写机程序里显示的是000000000000)。所以使用默认的密码的M1卡很容易被人模拟,就有了修改默认密码的需求。
要修改密码我们首先要知道存放密码的是哪一块结构?是怎么样的结构?
首先我解答一下上面的问题: M1卡存放密码大多数都是在 每一扇区的最后一块,结构是000000000000FF078069ffffffffffff。前12位是是KeyA,中间8位位控制位,后12位为KeyB。
这里要注意一下了,在修改之前一定要先修改控制位为(08 77 8F 69),要怎么修改呢?我们先去查找厂家给的SDK里面的write和read这两个函数。然后我们先通过调用SDK的mifare.authenticate()这个方法去校验扇区的默认密码,通过后便可调用read()方法读取扇区的数据,接下来就是调用write()方法把我们要修改的数据写进去。这里记得是先修改控制位再去修改密码,顺序不要错了,不然可能会有其他问题。
msgBuffer.delete(0, msgBuffer.length());
msgBuffer.append("寻到Mifare卡->UID:").append(mifare.uidToString()).append("\r\n");
msgBuffer.append("开始验证第1块密码\r\n");
handler.sendEmptyMessage(0);
byte[] key = {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
try {
boolean anth = mifare.authenticate((byte) 0x11, Mifare.MIFARE_KEY_TYPE_A, key);
if (anth) {
byte[] readDataBytes ;
readDataBytes = mifare.read((byte) 0x11);
msgBuffer.append("块11数据:").append(StringTool.byteHexToSting(readDataBytes)).append("\r\n");
handler.sendEmptyMessage(0);
msgBuffer.append("验证密码成功\r\n");
msgBuffer.append("写213496578320到块1\r\n");
// handler.sendEmptyMessage(0);
// boolean isSuc = mifare.write((byte)0x11, new byte[]{0x22, 0x11, 0x22, 0x44, 0x66, 0x11, 0x22, 0x77, (byte) 0x88, (byte) 0x99, 0x22, 0x55, 0x66, 0x33, 0x44, 0x55});
// boolean isSuc = mifare.write((byte)(3&0xFF),new byte[]{(byte) 0xff,(byte) 0xff,(byte) 0xff,(byte) 0xff,(byte) 0xff,(byte) 0xff,0x08,0x77, (byte) 0x8f,0x69, (byte) 0x11,(byte) 0xff,(byte) 0xff,(byte) 0xff,(byte) 0xff,(byte) 0xff});
// if (isSuc) {
// msgBuffer.append("写成功!\r\n");
// msgBuffer.append("读块1数据\r\n");
// handler.sendEmptyMessage(0);
byte[] readDataBytes1 = mifare.read((byte) 0x13);
msgBuffer.append("块1数据:").append(StringTool.byteHexToSting(readDataBytes1)).append("\r\n");
handler.sendEmptyMessage(0);
// } else {
// msgBuffer.append("写失败!\r\n");
// handler.sendEmptyMessage(0);
// return false;
// }
}
else {
msgBuffer.append("验证密码失败\r\n");
handler.sendEmptyMessage(0);
return false;
}
handler.sendEmptyMessage(0);
} catch (CardNoResponseException e) {
e.printStackTrace();
return false;
}
菜鸟代码勿喷,要是有高手能简化欢迎留言哈,这样我们就能修改了一个扇区里的密码了。但是一般来说我们都要把每个扇区的每一个密码都进行修改的,这样才能在最大限度的保证安全性。这时候我们其实就可以写一个for循环就好,至于怎么写大家可以试试思想是一样的。