笔者作为一个苦逼即将毕业的大四学生在外打拼已经两个月了,虽然没有费什么大力气被老师推荐到一个小boss公司里面实习,两个月也是颇有感叹。对于小公司,选一个员工像选媳妇儿一样,要“上得厅堂下的厨房”,对老板来说,不管你学过什么,需要写SQL的时候你就得会数据库,需要写html的时候你就得会css,js,开发后台的时候你就得会写servlet,filter,电脑坏了还的会装系统。还得会网络布线调试。博主什么都不精,又什么都会点,反正上刚才列举的东西基本都试了一遍,感慨万千啊。这不,应公司一个移动项目需求,boss需要一个射频卡初始化程序。也不知怎么的就让博主研究研究,我也不好吐槽,不要喊我研究什么,我也没那本事,反正本着boss的需求小小员工就的始终不渝的执行原则,怀着战战兢兢的心就试着写那么几段代码。
入手吧,东西和资料也不懂,就一个D3非接触式读写器,几张M1卡(是射频卡吗,到现在还分不大清,应该有啥区别吧),一个驱动程序,安装完了后还有一个几十k的chm(api)。说干就干呗,也不怕把boss买的机子弄坏,装好驱动后就用读卡器试了试,还是很新鲜的,最少能看到这M1的存储分区吧
M1卡0~15扇区,每区4块(编号记0~63),每块能写16个字符,其中0扇区第0块装商家出厂初始化的一些信息不能擦写,每个扇区的最后一块【(扇区号+1)*4-1】保存密码,其他的数据块都能存储数据。
先不说程序的事,再来说说这M1卡的密码机制吧,这尼玛才叫一个蛋疼,反正到现在我还是一头雾水,对于我这个智商不高的童鞋来说那简直就是比微积分还难过(ps:博主大学唯一挂在的微积分大树上),反正到现在还是一个迷糊蛋,不过反正是能实现boss那不高的要求。这对我来说就可以了,那要是真的深入去学吧,我这人记两天就又忘了,话说又不能当饭吃哈,要是能破解这M1卡的密码那我反手就是100块扔老板脸上走人。(扔100的原因是博主我就是一个穷屌)
基本来说M1卡的密码有两套,分A套密码和B套密码。每套密码各3个密码。M1的数据块是32位,存16个字符(8个中文字符),用16进制表示(这也是一个很蛋疼的地方,转过去转过来的)。前12位(6个字符)和后12位分别存储A套密码和B套密码,中间8位是控制位(这个是精华,虽然我不懂),这个我是一点也没有懂,深入的东西百度吧,不过资料好像不多的样子。总之来说就是中间的控制位控制6个密码的不同权限,哪一个密码分别对那块数据有读或者写或者读写权限,密码也是被隐藏了的哦,小博主开始还在那纠结呢。这个密码机制就跳过把,反正就是不咋个懂的。请深深的百度
现在来说说那几行代码的事儿吧。
基本功能:实现对M1卡的0扇区数据初始化,修改M1密码。根据已知的密码重置M1密码。
就这么基基本本的功能。作为一个只要实现基本功能的程序博主都没有写UI,直接用DOS执行吧(java写UI也是蛋疼)。仔仔细细的把api看了个遍,就那么几个函数,看起来不难样子。
代码构思:
虽然这么一个简单的功能也不能只写一个java类就完事吧,总体的就两个package:工具包和程序运行主类一个包。
把main函数的入口分离出来单独成一个类(入口级)
把实现循环函数功能的类单独分离出来(一级类)
具体实现设备连接,M1卡初始化功能聚合成一个类(二级类)
小博把代码贴出来,供君批评吐槽-------------------------------------------------------------------------------------------------------------------------------------------------------------
public class StartMain {
public static void main(String args[]){
//String[] args = {"445566", "8", "WER3", "6789", "2", "defaultkey"};
if (null == args || args.length < 5) {
System.out.println("#####参数错误,请确认参数!#####");
return;
}else {
if (args[5].length() != 6) {
System.out.println("#####参数错误,密码必须是6为字符,请确认参数!#####");
return ;
}else {
InitMCard IMC = null;
if (args.length == 5) {
IMC = new InitMCard(args[0], args[1], args[2],
Integer.parseInt(args[3]), Integer.parseInt(args[4]), null);
}else {
IMC = new InitMCard(args[0], args[1], args[2],
Integer.parseInt(args[3]), Integer.parseInt(args[4]), args[5]);
}
IMC.start();
}
}
}
}
public class EmptyKeyMain {
public static void main(String args[]){
//String[] args = {"ABCDEF"};
if (null == args || args.length < 1) {
System.out.println("#####参数错误,请确认参数!#####");
return;
}else {
InitMCard IMC = null;
IMC = new InitMCard(args[0]);
IMC.startEmpty();
}
}
}
public class InitMCard {
private static final short sectorNo = 0;
private static final short[] blockNos = {1};
private String areaCode = null;
private String type = null;
private String batchNo = null;
private int seqStartNo;
private int seqCount;
private String initKey = "529656";
public InitMCard(){}
public InitMCard(String initKey){
if (null != initKey) {
this.initKey = initKey;
}
}
public InitMCard(String areaCode, String type, String bathNo, int seqStartNo, int seqCount, String initKey) {
if (null == areaCode || null == type || null == bathNo
|| areaCode.equals("") || type.equals("") || bathNo.equals("") || seqCount <= 0 || areaCode.length() != 6
|| type.length() != 1 || bathNo.length() != 4 || seqStartNo <= 0 || seqStartNo>99999) {
System.out.println("参数输入错误,请重新输入参数!");
return ;
}
this.areaCode = areaCode;
this.type = type;
this.batchNo = bathNo;
this.seqStartNo = seqStartNo;
this.seqCount = seqCount;
if (null != initKey) {
this.initKey = initKey;
}
}
/**
* 开始初始化方法
*/
public void start() {
if (null == this.areaCode) {
System.out.println("the end");
return;
}
String[] infos = new String[2];
int startNo = this.seqStartNo;
do {
getData(infos);
InitData.writeData(sectorNo, blockNos, infos, this.initKey);
this.seqStartNo = startNo + InitData.initCount;
delay();
} while (InitData.initCount < this.seqCount);
System.out.println("the end");
}
/**
* 清空密码
*/
public void startEmpty() {
do {
InitData.emptyKey(this.initKey);
delay();
} while (true);
}
/**
* 延迟程序
*/
public void delay() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 获取数据
* @param infos
*/
public void getData(String[] infos){
String UID = this.areaCode + this.type + this.batchNo;
String startNoS = Integer.toString(this.seqStartNo);
if (startNoS.length() < 5) {
String s = "";
for (int i = 0; i < 5-startNoS.length(); i++) {
s += "0";
}
startNoS = s+startNoS;
}
if (startNoS.length() > 5) {
startNoS = startNoS.substring(startNoS.length() - 5, startNoS.length());
}
infos[0] = UID + startNoS;
}
}
public class InitData {
public static int initCount = 0;
private static final int port = 100;
private static final int baud = 9600;
private static final JavaRD800 rd = new JavaRD800();
private static final short _SearchCardModle = 0;
private static final short _KeyAuthModle = 0;
public static char[] defaultKey = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
private static char[] emptyKey = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69 , 0xFF, 0xFF, 0xFF, 0xFF,0xFF,0xFF};
/**
* 写入数据
* @param sectorNo
* @param blockNos
* @param infos
* @param key
*/
public static void writeData (short sectorNo, short[] blockNos, String[] infos, String key){
int status = 0, icdev = 0;
int cardID[] = new int[1];
char[] readBuff = new char[16];
String card = null;
//获取设备
icdev = rd.dc_init(port, baud);
if (icdev <= 0) {
System.out.println("######设备绑定端口失败!######");
return;
}
//寻卡
status = rd.dc_card(icdev, _SearchCardModle, cardID);
if (status != 0) {
rd.dc_exit(icdev);
return;
} else {
card = Tool.cardIdInt2String(cardID[0]);
if (card == null) {
System.out.println("######M1卡ID获取失败######");
return ;
}
System.out.println("-----------设备ID:"+card);
status = KeyAuthentication(icdev, sectorNo);
if (status != 0) {
System.out.println("######验证密码错误!######");
rd.dc_beep(icdev, (short) 250);
rd.dc_exit(icdev);
return ;
}
//获取转换设备ID
status = rd.dc_read(icdev, (short)0, readBuff);
if (status != 0) {
System.out.println("######读取设备ID失败######");
rd.dc_beep(icdev, (short) 250);
rd.dc_exit(icdev);
return ;
}
//循环写数据
for (int i = 0; i < blockNos.length; i++) {
status = rd.dc_write(icdev, blockNos[i], Tool.stringTochars(infos[i]));
if (status != 0) {
rd.dc_beep(icdev, (short) 250);
System.out.println("######写入第 "+blockNos[i]+"块 错误!######");
continue;
}
}
if (status != 0) {
rd.dc_beep(icdev, (short) 250);
rd.dc_exit(icdev);
return ;
}
status = rd.dc_write(icdev, (short)((sectorNo+1)*4-1), Tool.keyStringToChars(key));
if (status != 0) {
System.out.println("######初始化密码失败!######");
rd.dc_exit(icdev);
return ;
}
System.out.println("-----------初始化密码 :" + key);
Tool.saveToLocalFlie(card, infos[0], key);
Tool.saveToDBURL(card, infos[0], key);
rd.dc_beep(icdev, (short) 20);
System.out.println("-------------------------初始化成功");
initCount++;
}
// 关闭设备
status = rd.dc_exit(icdev);
if (status != 0) {
rd.dc_beep(icdev, (short) 250);
System.out.println("######关闭端口失败!######");
rd.dc_exit(icdev);
icdev = 0;
return;
}
}
/**
* 密码验证
* @param icdev
* @param sectorNo
* @return
*/
private static int KeyAuthentication(int icdev, short sectorNo){
int t = rd.dc_load_key(icdev, _KeyAuthModle, sectorNo, defaultKey);
if (t != 0) {
return t;
}
return rd.dc_authentication(icdev, _KeyAuthModle, sectorNo);
}
public static void emptyKey(String key){
InitData.defaultKey = Tool.keyStringToChars(key);
int status = 0, icdev = 0;
int cardID[] = new int[1];
String card = null;
//获取设备
icdev = rd.dc_init(port, baud);
if (icdev <= 0) {
System.out.println("######设备绑定端口失败!######");
return;
}
//寻卡
status = rd.dc_card(icdev, _SearchCardModle, cardID);
if (status != 0) {
rd.dc_exit(icdev);
return;
} else {
card = Tool.cardIdInt2String(cardID[0]);
if (card == null) {
System.out.println("######M1卡ID获取失败######");
return ;
}
System.out.println("-----------设备ID:"+card);
status = KeyAuthentication(icdev, (short)0);
if (status != 0) {
System.out.println("######原始验证密码错误!######");
rd.dc_beep(icdev, (short) 250);
rd.dc_exit(icdev);
return ;
}
status = rd.dc_write(icdev, (short)3, emptyKey);
if (status != 0) {
System.out.println("######重置密码失败!######");
rd.dc_exit(icdev);
return ;
}
rd.dc_beep(icdev, (short) 20);
System.out.println("-----------已经重置为原始密码 ");
}
// 关闭设备
status = rd.dc_exit(icdev);
if (status != 0) {
rd.dc_beep(icdev, (short) 250);
System.out.println("######关闭端口失败!######");
rd.dc_exit(icdev);
icdev = 0;
return;
}
}
}
工具类
public class Tool {
/**
* 转换字符串成字符数组
* @param source
* @return
*/
public static char[] stringTochars(String source){
if (null == source || source.length() == 0) {
return new char[16];
}
byte[] tpBytes = null;
char[] chars = new char[16];
try {
tpBytes = source.getBytes("GBK");
} catch (UnsupportedEncodingException e) {
System.out.println("编码失败!");
}
for (int i = 0; i < 16; i++) {
if (i < tpBytes.length) {
chars[i] = (char)tpBytes[i];
}else {
chars[i] = 0x00;
}
}
return chars;
}
/**
* 转换字节数组成字符串
* @param source
* @return
*/
public static String charsToString(char[] source){
if (null == source || source.length == 0) {
return null;
}
byte[] tpBytes = new byte[16];
char[] chars = source;
String ts = "";
for (int i = 0; i < chars.length; i++) {
tpBytes[i] = (byte)chars[i];
}
try {
ts = new String(tpBytes, "GBK");
} catch (UnsupportedEncodingException e) {
System.out.println("解码失败");
return new String(tpBytes);
}
return ts;
}
/**
* 解析卡号
* @param source
* @return
*/
public static String cardIdInt2String(int intCardId){
String hexCarId = Integer.toHexString(intCardId);
int t = hexCarId.length();
if (t % 2 != 0) {
return null;
}
String cardId = "";
for (; t > 0; t =t-2) {
cardId += hexCarId.substring(t - 2, t);
}
return cardId.toUpperCase();
}
/**
* 将密码转换成char[]
* @param key
* @return
*/
public static char[] keyStringToChars(String key){
char[] defaultKey = {'5', '2', '9', '6', '5', '6', 0xFF, 0x07, 0x80, 0x69 , 0xFF, 0xFF, 0xFF, 0xFF,0xFF,0xFF};
if (null == key || key.length() < 6) {
return defaultKey;
}
char[] keychar = key.toCharArray();
for (int i = 0; i < keychar.length; i++) {
defaultKey[i] = keychar[i];
}
return defaultKey;
}
/**
* 保存到本地文件
* @param cardID
* @param UID
* @param key
* @return
*/
public static boolean saveToLocalFlie(String cardID, String UID, String key){
if (null == cardID || null == UID || null == key) {
return false;
}
String outString = "\'"+cardID +"\',\'"+UID +"\',\'"+key +"\'\r\n";
String path = System.getProperty("user.dir")+"\\CardInfo\\";
String fileName = new SimpleDateFormat("YYYYMMdd").format(new Date())+".txt";
File file = new File(path);
if (!file.isDirectory()) {
file.mkdirs();
}
file = new File(path+fileName);
FileOutputStream fos = null;
OutputStreamWriter osw = null;
try {
if (!file.exists()) {
file.createNewFile();
}
fos = new FileOutputStream(file,true);
osw = new OutputStreamWriter(fos, "utf-8");
osw.write(outString, 0, outString.length());
if (osw != null) {
osw.close();
}
if (fos != null) {
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
osw=null;
fos=null;
file=null;
return false;
}
osw=null;
fos=null;
file=null;
return true;
}
/**
* 保存到数据库
* @param cardID
* @param UID
* @param key
* @return
*/
public static boolean saveToDBURL(String cardId, String UID, String key){
String url = "http://192.168.0.5/jwapp/pub/hntinit/Query/saveCardInfo.srdbexec?cardId="+cardId+"&key="+key+"&UID="+UID;
PURL purl = new PURL();
String rt = purl.get(url);
if (rt == null) {
return false;
}
return true;
}
/**
* 重文件中根据cardId获取key
* @param filePath
* @param cardId
* @return
*/
public static char[] getKeyFromLocal(String filePath, String cardId){
if (null == filePath || filePath.equals("")) {
return null;
}
char[] keyChar = null;
File file = new File(filePath);
if (!file.exists() || !file.isFile()) {
return null;
}
String line = "";
FileInputStream fis = null;
BufferedReader bfr = null;
try {
fis = new FileInputStream(file);
bfr = new BufferedReader(new InputStreamReader(fis));
while ((line = bfr.readLine()) != null) {
if (line.indexOf(cardId) > 0) {
keyChar = (line.split(" ")[2]).toCharArray();
}
}
} catch (Exception e) {
} finally {
try {
if (fis != null) {
fis.close();
}
if (bfr != null) {
bfr.close();
}
} catch (Exception e2) {
}
}
return keyChar;
}
/**
* 从远程根据cardId获取密码
* @param cardId
* @return
*/
public static char[] getKeyFromUrl(String cardId){
String url = "http://192.168.0.5/srdbexec?cardId="+cardId;
PURL purl = new PURL();
String rt = purl.get(url);
if (rt == null || rt.substring(rt.indexOf(""), rt.indexOf(" ")).equals("0")) {
return null;
}
/*从rt中拆分*/
String keystr = rt.substring(rt.indexOf(""), rt.indexOf(""));
return keystr.toCharArray();
}
}
public class PURL {
public String get(String urlstr) {
BufferedReader br = null;
URL url = null;
StringBuffer ret = new StringBuffer();
try {
url = new URL(urlstr);
} catch (MalformedURLException e) {
return null;
}
if (null != url) {
try {
br = new BufferedReader(new InputStreamReader(url.openStream(),
"UTF-8"));
} catch (IOException e) {
return null;
}
int s;
if (null != br) {
try {
while ((s = br.read()) != -1) {
ret.append((char) s);
}
} catch (IOException e) {
return null;
}
}
if (null != br) {
try {
br.close();
} catch (IOException e) {
return null;
}
}
}
br = null;
url = null;
return ret.toString();
}
}