uni-app android NFC MifareClassic 读IC卡加密扇区方法
uni-app android NFC MifareClassic 读IC卡加密扇区方法
近段时间在做android下NFC的M1卡的加密扇区的读取,参考了Android_磊子的操作基础内容,但是涉及到MifareClassic类操作验证未能找到相关资料,后来查看了MifareClassic类的源代码和基于android原生案例,实现了加密扇区读取。分享下代码,希望对大家有帮助。
对于NFC操作的基本部分有很多资料都一样的,这里不再赘述,仅简单介绍MifareClassic验证和读取的过程
- 创建MifareClassic对象,
MifareClassic.get(tag);
- 建立MifareClassic类连接,
MifareClassic.connect();
- 对扇区(0-15)进行验证,按KeyA和KeyB两种验证,
MifareClassic.authenticateSectorWithKeyA(sector,key);
其中sector为扇区号,key为6字节验证码,此处Key需要处理为-128至127的字节,开始使用0x00-0xFF会报错MifareClassic.authenticateSectorWithKeyB(sector,key);
其中sector为扇区号,key为6字节验证码,此处Key需要处理为-128至127的字节,开始使用0x00-0xFF会报错
- 按块(sector*4+i)读取扇区内的16Byte内容,
MifareClassic.readBlock(Block);
Block0=sector×4+0; Block1=sector×4+1; Block2=sector×4+2; Block3=sector×4+3; - 关闭MifareClassic连接,
MifareClassic.close();
MifareClassic读取代码
//MifareClassic读取代码
readData:function(intent){
var tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
var techList = tag.getTechList();
var bisMfc=false;
for(var i=0;i<techList.length;i++){
if(techList[i].indexOf('MifareClassic')>=0){
bisMfc=true;
break;
}
}
if(!bisMfc){
this.ICERROR='卡片类型错误!';
return;
}
var mfc=MifareClassic.get(tag);
if(!mfc){
this.ICERROR='卡片获取错误!';
return;
}
mfc.setTimeout(3000);
if(!mfc.isConnected()){
try{
invoke(mfc,'connect');
}catch(e){
this.ICERROR='卡片连接错误!';
return;
}
}
try{
this.ICUID=this.ByteArrayToHexString(tag.getId());
var cmdBytes=this.HexStringToByteArray(this.keyVal);
var auth=false;
if(this.keyType=="A"){
auth=invoke(mfc,"authenticateSectorWithKeyA",parseInt(this.sector),cmdBytes);
}else{
auth=invoke(mfc,"authenticateSectorWithKeyB",parseInt(this.sector),cmdBytes);
}
if(!auth){
this.ICERROR='扇区验证失败';
return;
}
var sectorData=[];
var tmpRet;
this.ICData='IC卡扇区数据>>';
for(var i=0;i<4;i++){
tmpRet=invoke(mfc,"readBlock",this.sector*4+i);
this.ICData=this.ICData+'\n';
this.ICData=this.ICData+this.ByteArrayToHexString(tmpRet);
sectorData.push.apply(sectorData,tmpRet);
}
console.log(this.ByteArrayToHexString(sectorData));
this.ICERROR='读卡完成';
}catch(e){
this.ICERROR=e.message;
console.error(e);
}finally{
mfc.close();
}
}
//Key处理函数
HexStringToByteArray:function(instr) {
var hexA = new Array();
var pos = 0;
var len = instr.length/2;
for(var i=0; i<len; i++)
{
var s = instr.substr(pos, 2);
var v = parseInt(s, 16);
if(v>=128)
v=v-256;
hexA.push(v);
pos += 2;
}
return hexA;
}
项目是基于nui-app项目的vue测试通过的,附件共享了vue文件。
项目需设置android.permission.NFC权限。
1 回复
在uni-app中直接操作Android NFC(近场通信)功能,尤其是读取MifareClassic IC卡的加密扇区,是一个比较复杂的任务。uni-app主要面向跨平台开发,原生硬件操作(如NFC)通常需要依赖原生插件或者通过原生代码扩展来实现。以下是一个简要的思路和代码示例,展示如何在Android平台上使用NFC读取MifareClassic卡的加密扇区。
步骤概述
- 配置AndroidManifest.xml:添加NFC权限。
- 创建NFCAdapter和PendingIntent:用于监听NFC事件。
- 实现Activity的NFC回调接口:处理NFC卡读取事件。
- 使用MifareClassic类读取加密扇区:通过APDU命令或已知的密钥进行认证和读取。
示例代码
1. 配置AndroidManifest.xml
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
2. 创建NFCAdapter和PendingIntent
在Activity的onCreate方法中:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Toast.makeText(this, "This device doesn't support NFC.", Toast.LENGTH_LONG).show();
finish();
return;
}
if (!nfcAdapter.isEnabled()) {
Toast.makeText(this, "NFC is disabled.", Toast.LENGTH_LONG).show();
finish();
return;
}
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*");
} catch (IntentFilter.MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
IntentFilter[] intentFiltersArray = new IntentFilter[]{ndef, };
String[][] techListsArray = new String[][]{
new String[]{NfcF.class.getName()},
new String[]{MifareClassic.class.getName()}
};
nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
3. 实现NFC回调接口
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (tag != null) {
MifareClassic mifareClassic = MifareClassic.get(tag);
if (mifareClassic != null) {
try {
mifareClassic.connect();
// 假设你已经知道密钥A和密钥B
byte[] keyA = new byte[]{/* 密钥A */};
byte[] keyB = new byte[]{/* 密钥B */};
mifareClassic.authenticateSectorWithKeyA(1, keyA); // 扇区1
byte[] data = mifareClassic.readBlock(4); // 读取块4(扇区1的第2块)
// 处理数据
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
mifareClassic.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注意
- 权限与安全:在实际应用中,处理NFC读取和密钥操作需要格外注意安全性。
- 错误处理:示例代码中的错误处理较为简单,实际应用中应增加更多的异常处理和用户提示。
- uni-app集成:上述代码是原生Android代码,要在uni-app中使用,需通过原生插件机制集成。