package com.acr122u.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CardTerminals;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;
/**
* javax.smartcardio,操作PCSC规范的读卡器
* 共有16个扇区,每个扇区4个区块
* IC卡的0扇区0区块放着这张卡的序列号~一般是出厂时就固化不可更改的~
* 而且!读取序列号不需要验证密码
* 区块地址从00向上递增。
* 其中,每个扇区的第三区块是密码和控制字存储的区块,不能作为数据存储使用。
* 还有一个特例,就是0扇区的0区块,存储的是卡片的序列号,不可更改。
* 每个扇区只需认证一次密钥即可对三个数据块随意读写。
* 出厂默认的控制字FF078069表示KEYA 或者KEYB都可以随意读写。
* @author Reid(QQ1184010001)
*/
public class LetturaSmartCard {
//------------------------------------lettura---------------------------
//十六进制数
private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
//先用一个数组把密钥存起来
private static final byte[] pwd = {(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff};
//认证数据字节,包含了需要认证的区块号、密钥类型和密钥存储的地址(密钥号)
private static final byte[] check = {(byte)0x01,(byte)0x00,(byte)0x08,(byte)0x60,(byte)0x00};
/**
* 连接读卡器
*/
public static String smartCard(){
TerminalFactory factory = TerminalFactory.getDefault();
//清除所有终端列表
try {
Class<?> pcscterminal = Class.forName("sun.security.smartcardio.PCSCTerminals");
Field contextId = pcscterminal.getDeclaredField("contextId");
contextId.setAccessible(true);
if(contextId.getLong(pcscterminal) != 0L)
{
// 首先获取一个新的上下文值
Class<?> pcsc = Class.forName("sun.security.smartcardio.PCSC");
Method SCardEstablishContext = pcsc.getDeclaredMethod("SCardEstablishContext", new Class[] {Integer.TYPE });
SCardEstablishContext.setAccessible(true);
Field SCARD_SCOPE_USER = pcsc.getDeclaredField("SCARD_SCOPE_USER");
SCARD_SCOPE_USER.setAccessible(true);
long newId = ((Long)SCardEstablishContext.invoke(pcsc,
new Object[] { SCARD_SCOPE_USER.getInt(pcsc) }
));
contextId.setLong(pcscterminal, newId);
// 然后清除缓存中的终端
CardTerminals terminals = factory.terminals();
Field fieldTerminals = pcscterminal.getDeclaredField("terminals");
fieldTerminals.setAccessible(true);
Class<?> classMap = Class.forName("java.util.Map");
Method clearMap = classMap.getDeclaredMethod("clear");
clearMap.invoke(fieldTerminals.get(terminals));
}
} catch (Exception e) {
e.printStackTrace();
}
//重新获取终端列表
List<CardTerminal> terminals;
try {
terminals = factory.terminals().list();//get读卡器列表
System.out.println("阅读器连接列表: " + terminals);
CardTerminal a = terminals.get(0);//使用第0个读卡器[暂且不考虑同时插N个读卡器的情况了]
System.out.println("第一个终端: " + a);
a.waitForCardPresent(0L);//等待放置卡片
Card card = a.connect("T=1");//连接卡片,协议T=1 块读写(T=0貌似不支持,一用就报错)
CardChannel channel = card.getBasicChannel();//打开通道
CommandAPDU getUID = new CommandAPDU(0xFF, 0xCA, 0x00, 0x00,0x04);//中文API第12页
ResponseAPDU r = channel.transmit(getUID);//发送getUID指令
//CommandAPDU loadPWD = new CommandAPDU(0xFF, 0x82, 0x00, 0x00, pwd,0,6);//然后构造一个加载密钥APDU指令~
//ResponseAPDU r = channel.transmit(loadPWD);//发送loadPWD指令
//CommandAPDU getData = new CommandAPDU(0xFF, 0xB0, 0x00, 0x08,0x10);//构造读区块APDU指令,读第八个区块(2扇区0区块)值
//ResponseAPDU r = channel.transmit(getData);
System.out.println(r.getBytes());
System.out.println("bytesToHexString结果: " + bytesToHexString(r.getBytes()));
System.out.println("bytesToHex结果: " + bytesToHex(r.getBytes()));
String UID = bytesToHexString(r.getData());
return UID;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Utils
* 因为数据返回是一个byte[]数组,文档和API使用的是16进制数,
* 所以需要一个将byte[]转为十六进制数的小方法
* @param bytes byte[]数组
* @return 字符串
*/
public static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
int a = 0;
for (byte b : bytes) { // 使用除与取余进行转换
if (b < 0) {
a = 256 + b;
} else {
a = b;
}
sb.append(HEX_CHAR[a / 16]);
sb.append(HEX_CHAR[a % 16]);
}
return sb.toString().toUpperCase();
}
/**
* 读取风扇区
* @param bytes byte[]数组
* @return 字符串
*/
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (int i = 0; i < bytes.length; i++) {
sb.append(String.format("%02x", bytes[i]));
}
return sb.toString();
}
}

一个不称职的程序猿
- 粉丝: 2467
最新资源
- SQL实训图书管理.doc
- 飞机钣金成形信息化的关键技术解决路径.docx
- ADPCM的语音编解码设计方案.doc
- 《单片机应用与仿真训练》设计报告:单片机的遥控窗帘.doc
- 历年计算机二级MS-Office真题.docx
- 利用BIOSIS-PREVIEWS.ppt
- 数据库原理课程设计模板.doc
- DICEPXAEP嵌入式优秀教学实验系统.doc
- ACCESS课程设计要求与选题.doc
- 互联网+时代的平面设计理念.docx
- 大数据时代政策预测的挑战及应对.docx
- 区块链技术对我国体育产业发展的影响研究.docx
- 农村家庭迈向信息化实现策略研究分析方案.doc
- ppt模板电子商务总结汇报类PPT模板.pptx
- §1电子商务概述21.ppt
- 大力推进智慧城市建设-将现代化国际港口城市建设推向新阶段.ppt
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈


