Android NFC M1卡读写芯片卡读写(CPU卡读写)(RFID读写)
Android NFC M1卡读写&芯片卡读写(CPU卡读写)(RFID读写)
- NFC 读写分几种,本文主要讲M1卡扇区读写和芯片卡读写
- 权限
- 初始化
- 1 onCreate( initNFC() )
- 2 onResume( )
- 3 onPause()
- 4 NFC设备刷卡时触发 onNewIntent(Intent)
- 1,标签读写
- 2,扇区读写
- 3 CPU卡读写 重头戏
NFC 读写分几种,本文主要讲M1卡扇区读写和芯片卡读写
NFC 标签读写
NFC 扇区读写
NFC 文件读写
权限
<uses-featureandroid:name="android.hardware.nfc"android:required="true"/><uses-permission android:name="android.permission.NFC"/>
<activity android:name=".ReadTextActivity" android:launchMode="singleTop"><intent-filter><action android:name="android.nfc.action.TAG_DISCOVERED"/><action android:name="android.nfc.action.TECH_DISCOVERED" /><data android:mimeType="text/plain"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></activity>
初始化
在Activity#onCreate()注册,在Activity#onResume()开启前台调度系统,在Activity#onPause退出前台调度。
1 onCreate( initNFC() )
private void initNFC() {// 获取nfc适配器,判断设备是否支持NFC功能nfcAdapter = NfcAdapter.getDefaultAdapter(this);if (nfcAdapter == null) {shotToast("当前设备不支持NFC功能");} else if (!nfcAdapter.isEnabled()) {shotToast("NFC功能未打开,请先开启后重试!");}pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);ndef.addCategory("*/*");// 允许扫描的标签类型mWriteTagFilters = new IntentFilter[]{ndef};mTechLists = new String[][]{new String[]{MifareClassic.class.getName()},new String[]{NfcA.class.getName()}};// 允许扫描的标签类型}
2 onResume( )
@Overrideprotected void onResume() {super.onResume();//开启前台调度系统nfcAdapter.enableForegroundDispatch(this, pendingIntent, mWriteTagFilters, mTechLists);}
3 onPause()
@Overrideprotected void onPause() {super.onPause();nfcAdapter.disableForegroundDispatch(this);}
4 NFC设备刷卡时触发 onNewIntent(Intent)
给伪代码,详细见下面3点分解
@Overrideprotected void onNewIntent(Intent intent) {super.onNewIntent(intent);//当该Activity接收到NFC标签时,运行该方法if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);1,标签读写Ndef ndef = Ndef.get(tag);//如果ndef为空表示不支持该格式 //可进行格式 如果格式化失败则不能只能换个方式2,M1 扇区读写MifareClassic mfc = MifareClassic.get(tag);//CPU卡时 mfc将为空3,CPU卡 读写NfcCpuUtilsnfc = new NfcCpuUtils(IsoDep.get(tag));}}
1,标签读写
/*** 写标签* @param ndef* @param tag* @param ndefMessage* @return* @throws IOException* @throws FormatException*/private boolean writeMsg(Ndef ndef, Tag tag, NdefMessage ndefMessage) throws IOException, FormatException {try {if (ndef == null) {shotToast("格式化数据开始");//Ndef格式类NdefFormatable format = NdefFormatable.get(tag);format.connect();format.format(ndefMessage);} else {shotToast("写入数据开始");//数据的写入过程一定要有连接操作ndef.connect();ndef.writeNdefMessage(ndefMessage);}return true;} catch (IOException e) {e.printStackTrace();shotToast("IO异常,读写失败");} catch (FormatException e) {e.printStackTrace();shotToast("格式化异常,读写失败");} catch (NullPointerException e) {shotToast("格NullPointerException异常,读写失败");}catch (IllegalStateException e){shotToast("Close other technology first!");}return false;}
/*** 读取NFC标签文本数据*/
private void readNfcTag(Intent intent) {if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())||NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);NdefMessage msgs[] = null;int contentSize = 0;if (rawMsgs != null) {msgs = new NdefMessage[rawMsgs.length];for (int i = 0; i < rawMsgs.length; i++) {msgs[i] = (NdefMessage) rawMsgs[i];contentSize += msgs[i].toByteArray().length;}}try {if (msgs != null) {print(msgs.length+" 长度");NdefRecord record = msgs[0].getRecords()[0];String textRecord = parseTextRecord(record);mTagText += textRecord + "\n\ntext\n" + contentSize + " bytes";print(mTagText);}} catch (Exception e) {}}
}
2,扇区读写
M1扇区默认是没有密码的,但有部分人闲不住要把密码改了,因此认证过程要加密码,一般认证KeyA就行。普通卡16个扇区64块,第一个扇区等闲不能操作。每个扇区4块,从0数起,第二扇区第一块索引就是8,每个扇区前3块存数据最后一块一般存密码。实例代码读的是2扇区8块。
/*** 扇区写* @param tag* @param sectorIndex 扇区索引 一般16个扇区 64块* @return*/public boolean writeTAG(Tag tag,int sectorIndex) {MifareClassic mfc = MifareClassic.get(tag);try {mfc.connect();if (mfc.authenticateSectorWithKeyA(sectorIndex, new byte[]{0x42,0x53,0x4B, (byte) sectorIndex,0x4C,0x53})) { //已知密码认证 r// the last block of the sector is used for KeyA and KeyB cannot be overwrittedint block = mfc.sectorToBlock(sectorIndex);mfc.writeBlock(block, "sgn-old000000000".getBytes());mfc.close();shotToast("旧卡 写入成功");return true;}else if(mfc.authenticateSectorWithKeyA(sectorIndex, MifareClassic.KEY_NFC_FORUM)){ //新卡 未设密码认证 rint block = mfc.sectorToBlock(sectorIndex);mfc.writeBlock(block, "SGN-new000000000".getBytes());mfc.close();shotToast("新卡 写入成功");} else{shotToast("未认证");}} catch (IOException e) {e.printStackTrace();shotToast("扇区连接异常");try {mfc.close();} catch (IOException e1) {e1.printStackTrace();}}return false;}/*** 读扇区* @return*/private String readTag(Tag tag,MifareClassic mfc,int sectorIndex){for (String tech : tag.getTechList()) {System.out.println("------------"+tech);}//读取TAGtry {String metaInfo = "";//Enable I/O operations to the tag from this TagTechnology object.mfc.connect();int type = mfc.getType();//获取TAG的类型int sectorCount = mfc.getSectorCount();//获取TAG中包含的扇区数String typeS = "";switch (type) {case MifareClassic.TYPE_CLASSIC:typeS = "TYPE_CLASSIC";break;case MifareClassic.TYPE_PLUS:typeS = "TYPE_PLUS";break;case MifareClassic.TYPE_PRO:typeS = "TYPE_PRO";break;case MifareClassic.TYPE_UNKNOWN:typeS = "TYPE_UNKNOWN";break;}metaInfo += "卡片类型:" + typeS + "\n共" + sectorCount + "个扇区\n共" + mfc.getBlockCount() + "个块\n存储空间: " + mfc.getSize() + "B\n";int blockIndex;if (mfc.authenticateSectorWithKeyA(sectorIndex, new byte[]{0x42,0x53,0x4B, (byte) sectorIndex,0x4C,0x53}) ) {blockIndex = mfc.sectorToBlock(sectorIndex);byte[] data = mfc.readBlock(blockIndex);metaInfo += "旧卡 Block " + blockIndex + " : " + new String(data) + "\n";}else if( mfc.authenticateSectorWithKeyA(sectorIndex, MifareClassic.KEY_NFC_FORUM)){blockIndex = mfc.sectorToBlock(sectorIndex);byte[] data = mfc.readBlock(blockIndex);metaInfo += "新卡 Block " + blockIndex + " : " + new String(data) + "\n";}else {metaInfo += "Sector " + sectorIndex + ":验证失败\n";}return metaInfo;} catch (Exception e) {Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();e.printStackTrace();} finally {if (mfc != null) {try {mfc.close();} catch (IOException e) {Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();}}}return null;}
3 CPU卡读写 重头戏
先直接上代码,看完代码在说吧,搞这个有点心力疲惫。
下面是一个写的完全流程,if的嵌套我承认有点low,但有助于流程理解。
这里要说下外部认证过程:
devices -----获取4字节随机数---------------------> cpu 卡
devices <--------随机数+90 00--------------------- cpu 卡
四个字节随机数+四个字节0 使用密钥进行DES加密,如果是8个随机数DES3加密。
将命令00 82 00 00 08 以及加密后的随机数取前8位 7f cf 90 a0 5b 9c f1 73发送
devices ----00 82 00 00 08 7f cf 90 a0 5b 9c f1 73–>cpu 卡
devices <------------- 90 00---------------------------- cpu 卡
/*** Description : cpu卡写的工具类 命令返回90 00 表示成功* CreateAuthor: Cannan* CreateTime : 2018/9/22 18:53* Project : TestNFC*/public class NfcCpuUtils {/*** 1. 在“COS命令框”输入“00A40000023F00”,然后点击“发送命令”,进入主目录*/private final byte[] CMD_START = new byte[]{0x00, (byte) 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00}; //6f,15,84,e,31,50,41,59,2e,53,59,53,2e,44,44,46,30,31,a5,3,88,1,1,90,0,/*** 2. 复合外部认证(秘钥:FFFFFFFFFFFFFFFF,秘钥标识号:00)*/private byte[] CMD_KEY = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};/*** 2.1 获取4位 随机码 {0x00, (byte) 0x84, 0x00, 0x00, 0x04}*/private final byte[] CMD_GET_RANDOM = {0x00, (byte) 0x84, 0x00, 0x00, 0x04};private final byte[] CMD_DEL = {(byte) 0x80, 0x0E, 0x00, 0x00, 0x00}; //3.删除主目录下的所有文件:800E000000(注意:这个命令会删除主目录下的所有文件)// 4. 建立外部认证秘钥 4.1选择根目录(00A4000000)// 4.2建密钥文件 (80 E0 00 00 07 3F 00 B0 01 F0 FF FF// 4.3创建外部认证密钥 (80 D4 01 00 0D 39 F0F0 AA 55 FFFFFFFFFFFFFFFF)private final byte[] CMD_CREATE_DIR = {0x00, (byte) 0xA4, 0x00, 0x00, 0x02,0x3f,0x00};private final byte[] CMD_CREATE_KEY = {(byte) 0x80, (byte) 0xE0, 0x00, 0x00, 0x07, 0x3F, 0x00, (byte) 0xB0, 0x01, (byte) 0xF0, (byte) 0xFF, (byte) 0xFF};private final byte[] CMD_CREATE_OUT_KEY = {(byte) 0x80, (byte) 0xD4, (byte) 0x01, (byte) 0x00, (byte) 0x0D, (byte)0x39, (byte) 0xF0, (byte) 0xF0, (byte) 0xAA, (byte) 0x55, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};//5 建立访问自定义文件的密钥文件private final byte[] CMD_ACCESS = {(byte) 0x80, (byte) 0xE0, (byte) 0x00, (byte) 0x01, (byte) 0x07, (byte) 0x3F, (byte) 0x01, (byte) 0x8F, (byte) 0x95, (byte) 0xF0, (byte) 0xFF, (byte) 0xFF};// 填充密钥123456private final byte[] CMD_ACCESS_INTO = {(byte) 0x80, (byte) 0xD4, (byte) 0x01, (byte) 0x01, (byte) 0x08, (byte) 0x3A, (byte) 0xF0, (byte) 0xEF, (byte) 0x44, (byte) 0x55, (byte) 0x12, (byte) 0x34, (byte) 0x56};//6. 创建自定义文件,标识为005(80E000050728000FF4F4FF02)private final byte[] CMD_ACCESS_FILE = {(byte) 0x80, (byte) 0xE0, (byte) 0x00, (byte) 0x05, (byte) 0x07, (byte) 0x28, (byte) 0x00, (byte) 0x0F, (byte) 0xF4, (byte) 0xF4, (byte) 0xFF, (byte) 0x02};//7.写数据到文件标识为0005的文件//7.1选中该文件(00A40000020005)// 7.2写数据“112233445566”到该文件(00D6000006112233445566)private final byte[] CMD_ACCESS_FILE_CHOOICE = {(byte) 0x00, (byte) 0xA4, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x05};private final byte[] CMD_ACCESS_FILE_WRITE = {(byte) 0x00, (byte) 0xD6, (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x88, (byte) 0x88, (byte) 0x88, (byte) 0x44, (byte) 0x55, (byte) 0x66};// 声明ISO-DEP协议的Tag操作实例private final IsoDep tag;public NfcCpuUtils(IsoDep tag) throws IOException {// 初始化ISO-DEP协议的Tag操作类实例this.tag = tag;tag.setTimeout(5000);tag.connect();}public byte[] wirte() throws IOException {byte[] resp = tag.transceive(CMD_START); //1 进入主目录if (checkRs(resp)) {print("1 进入主目录成功");resp = tag.transceive(CMD_GET_RANDOM); //2 获取随机码if (checkRs(resp)) {print("2 获取随机码");byte[] random = {resp[0], resp[1], resp[2], resp[3], 0x00, 0x00, 0x00, 0x00};//3 随机码4个字节+4个字节0byte[] desKey;try {desKey = encrypt(random, CMD_KEY); //4 生产加密后的随机码print("3 生产加密后的随机码");printByte(desKey);} catch (Exception e) {e.printStackTrace();desKey = null;}//00 82 00 00 08 7f cf 90 a0 5b 9c f1 73if (desKey != null && desKey.length > 8) {byte[] respondKey = {0x00, (byte) 0x82, 0x00, 0x00, 0x08, desKey[0], desKey[1], desKey[2], desKey[3], desKey[4], desKey[5], desKey[6], desKey[7]};print("4 生产加密后的随机码命令");printByte(respondKey);resp = tag.transceive(respondKey); //5 将加密后的随机码发送,注意此处第四字节表示密码标识符00,} if (checkRs(resp)) {print("5 外部认证成功");resp = tag.transceive(CMD_DEL);if (checkRs(resp)) {print("6 删除目录成功");resp = tag.transceive(CMD_CREATE_DIR);if (checkRs(resp)) {print("7 选择目录");resp = tag.transceive(CMD_CREATE_KEY);if (checkRs(resp)) {print("8 建立目录");resp = tag.transceive(CMD_CREATE_OUT_KEY);if (checkRs(resp)) {print("9 创建外部认证密钥成功");resp = tag.transceive(CMD_ACCESS);if (checkRs(resp)) {print("10 建立访问自定义文件的密钥文件成功");resp = tag.transceive(CMD_ACCESS_INTO); //11 填充密钥123456if (checkRs(resp)) {print("11 填充密钥123456成功");resp = tag.transceive(CMD_ACCESS_FILE); //12 创建自定义文件,标识为005if (checkRs(resp)) {print("12 创建自定义文件,标识为005成功");resp = tag.transceive(CMD_ACCESS_FILE_CHOOICE); // 13 选中该文件0005if (checkRs(resp)) {print(" 13 选中该文件0005成功");resp = tag.transceive(CMD_ACCESS_FILE_WRITE); //14 写数据“112233445566”到该文件if (checkRs(resp)) { //15 应该有关闭连接print("14 写数据“112233445566”到该文件成功");return "01".getBytes();}}}}}}}}}}}}return null;}private boolean checkRs(byte[] resp) {String r = printByte(resp);Log.i("---------", "response " + r);int status = ((0xff & resp[resp.length - 2]) << 8) | (0xff & resp[resp.length - 1]);return status == 0x9000;}private String printByte(byte[] data) {StringBuffer bf = new StringBuffer();for (byte b : data) {bf.append(Integer.toHexString(b & 0xFF));bf.append(",");}Log.i("TAG", bf.toString());return bf.toString();}private void print(String msg) {Log.i("TAG", msg);}/*** Description 根据键值进行加密* 随机码4个字节+4个字节0** @param data* @param key 加密键byte数组* @return* @throws Exception*/public byte[] encrypt(byte[] data, byte[] key) throws Exception {}
}
注意接收和处理返回的信息,CPU卡常用的APDU指令
参考文献:很多博客,记不得了,RFID多功能读卡器说明
https://blog.csdn.net/qq_34075348/article/details/77877306
FMCOS2.0用户手册 50-70
如果需要源码:下载地址https://download.csdn.net/download/sgn5200/10688898
Android NFC M1卡读写芯片卡读写(CPU卡读写)(RFID读写)相关推荐
- c语言读写nfc,Android NFC M1卡读写芯片卡读写(CPU卡读写)(RFID读写)
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/sgn5200/article/deta ...
- android pda界面美化,安卓设备扫描cpu卡和rfid超频卡插件cordova-plugin-pda
1.该插件只支持安卓设备,可以扫描上海复旦fm1216卡(CPU卡),s50卡,rfid超频卡等:这是我写的一个cordova插件,下面是安装步骤 2.安装方法: cordova plugin add ...
- 复旦FM17522芯片读写M1卡(S50/S70)、CPU卡要点摘录
目录 概述 卡的存储结构/文件结构 M1卡存储结构 复旦CPU卡的文件结构 卡的权限管理方式 M1卡控制字 CPU卡安全状态寄存器 卡的认证 M1卡的三次互相认证 复旦CPU卡的外部认证和内部认证 机 ...
- NFC开发 —————ID卡、IC卡(M1卡、CPU卡)的区别(三)
Android NFC开发(一) NFC开发 -----实现NFC手机做门禁卡的方法(二) NFC开发 -----实用工具以及开发文档(四) IC卡的定义 : IC(Integrated Circui ...
- Android NFC 标签读写Demo与历史漏洞概述
文章目录 前言 NFC基础 1.1 RFID区别 1.2 工作模式 1.3 日常应用 NFC标签 2.1 标签应用 2.2 应用实践 2.3 标签预览 2.4 前台调度 NFC开发 3.1 NDEF数 ...
- Android NFC 读写示例
自己新浪博客转移 在Android NFC 应用中,Android手机通常是作为通信中的发起者,也就是作为各种NFC卡的读写器.Android对NFC的支持主要在 android.nfc 和andro ...
- CPU卡读写操作函数
QQ:954486673 微信:13822155058 淘宝:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.2 ...
- 四个方面比较CPU卡加密系统与M1加密系统
http://www.dzsc.com/data/html/2010-11-24/87326.html 密钥管理系统(Key Management System),也简称KMS,是IC项目安全的核心. ...
- IC、ID、M1、CPU卡
本博文转自: http://blog.sina.com.cn/s/blog_9ed067ad0100xj3n.html 潘春伟的博客 http://www.cnblogs.com/k1two2/p ...
- IC 卡、M1 卡、CPU 卡、SAM 卡、PSAM 卡的联系与区别
一. 技术方面(非接触式 IC 卡) 1. 逻辑加密卡又叫存储卡,卡内的集成电路具有加密逻辑和 EEPROM (电可 擦除可编程只读存储器). 2. CPU 卡又叫智能卡, 卡内的集成电路包括中央处理 ...
最新文章
- R语言使用gt包和gtExtras包优雅地、漂亮地显示表格数据:使用gtExtras包添加一个图,显示表中某一列中的数字、并自定义表格数据显示的主题格式、并自定义数值数据的格式(例如百分比)
- NYOJ-括号配对问题 技巧性的非栈道法
- Mac下布置appium环境
- sqlitepython导入数据_python从sqlite读取并显示数据的方法
- Ubuntu16.04安装NVIDIA显卡(RTX20系列)驱动+CUDA10.0+cudnn+Pytorch1.1.0
- NYOJ 201 作业题 动态规划
- XP支持4G以上物理内存的方法
- [html] 怎样避免让用户看到长时间的白屏?
- Go -- php 中的pack(H*, $string) 转换成go
- Android中OnItemClick的四个参数意义
- mysql 杀掉会话
- 机器学习(周志华) 第八章集成学习
- 虚函数表构成、地址详细说明
- 把视频裁剪成图片Python
- java随机生成三位数
- 从零开始学习idea开发vue
- MBA包括哪些课程?看完这个系列的书籍你就知道了
- .NET Framework各个版本(1.0 - 2.0)
- CC2530+ESP8266使用MQTT协议上传阿里云的问题
- 点餐系统部署文档,java后台部署和微信点餐小程序的部署