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读写)相关推荐

  1. c语言读写nfc,Android NFC M1卡读写芯片卡读写(CPU卡读写)(RFID读写)

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/sgn5200/article/deta ...

  2. android pda界面美化,安卓设备扫描cpu卡和rfid超频卡插件cordova-plugin-pda

    1.该插件只支持安卓设备,可以扫描上海复旦fm1216卡(CPU卡),s50卡,rfid超频卡等:这是我写的一个cordova插件,下面是安装步骤 2.安装方法: cordova plugin add ...

  3. 复旦FM17522芯片读写M1卡(S50/S70)、CPU卡要点摘录

    目录 概述 卡的存储结构/文件结构 M1卡存储结构 复旦CPU卡的文件结构 卡的权限管理方式 M1卡控制字 CPU卡安全状态寄存器 卡的认证 M1卡的三次互相认证 复旦CPU卡的外部认证和内部认证 机 ...

  4. NFC开发 —————ID卡、IC卡(M1卡、CPU卡)的区别(三)

    Android NFC开发(一) NFC开发 -----实现NFC手机做门禁卡的方法(二) NFC开发 -----实用工具以及开发文档(四) IC卡的定义 : IC(Integrated Circui ...

  5. Android NFC 标签读写Demo与历史漏洞概述

    文章目录 前言 NFC基础 1.1 RFID区别 1.2 工作模式 1.3 日常应用 NFC标签 2.1 标签应用 2.2 应用实践 2.3 标签预览 2.4 前台调度 NFC开发 3.1 NDEF数 ...

  6. Android NFC 读写示例

    自己新浪博客转移 在Android NFC 应用中,Android手机通常是作为通信中的发起者,也就是作为各种NFC卡的读写器.Android对NFC的支持主要在 android.nfc 和andro ...

  7. CPU卡读写操作函数

    QQ:954486673 微信:13822155058 淘宝:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-17663462238.11.2 ...

  8. 四个方面比较CPU卡加密系统与M1加密系统

    http://www.dzsc.com/data/html/2010-11-24/87326.html 密钥管理系统(Key Management System),也简称KMS,是IC项目安全的核心. ...

  9. IC、ID、M1、CPU卡

    本博文转自: http://blog.sina.com.cn/s/blog_9ed067ad0100xj3n.html   潘春伟的博客 http://www.cnblogs.com/k1two2/p ...

  10. IC 卡、M1 卡、CPU 卡、SAM 卡、PSAM 卡的联系与区别

    一. 技术方面(非接触式 IC 卡) 1. 逻辑加密卡又叫存储卡,卡内的集成电路具有加密逻辑和 EEPROM (电可 擦除可编程只读存储器). 2. CPU 卡又叫智能卡, 卡内的集成电路包括中央处理 ...

最新文章

  1. R语言使用gt包和gtExtras包优雅地、漂亮地显示表格数据:使用gtExtras包添加一个图,显示表中某一列中的数字、并自定义表格数据显示的主题格式、并自定义数值数据的格式(例如百分比)
  2. NYOJ-括号配对问题 技巧性的非栈道法
  3. Mac下布置appium环境
  4. sqlitepython导入数据_python从sqlite读取并显示数据的方法
  5. Ubuntu16.04安装NVIDIA显卡(RTX20系列)驱动+CUDA10.0+cudnn+Pytorch1.1.0
  6. NYOJ 201 作业题 动态规划
  7. XP支持4G以上物理内存的方法
  8. [html] 怎样避免让用户看到长时间的白屏?
  9. Go -- php 中的pack(H*, $string) 转换成go
  10. Android中OnItemClick的四个参数意义
  11. mysql 杀掉会话
  12. 机器学习(周志华) 第八章集成学习
  13. 虚函数表构成、地址详细说明
  14. 把视频裁剪成图片Python
  15. java随机生成三位数
  16. 从零开始学习idea开发vue
  17. MBA包括哪些课程?看完这个系列的书籍你就知道了
  18. .NET Framework各个版本(1.0 - 2.0)
  19. CC2530+ESP8266使用MQTT协议上传阿里云的问题
  20. 点餐系统部署文档,java后台部署和微信点餐小程序的部署

热门文章

  1. kotlin学习之高阶函数及常用基本高阶函数
  2. 静态HTML网页设计作品网站设计——仙灵游戏网站首页(1页) HTML+CSS+JavaScript 学生DW网页设计作业成品
  3. 普通话考试是从题库里抽吗_普通话考试试题有哪些
  4. Unity3D中玩家的移动方式,三大类型,八种方式
  5. 1000m交叉网线最简单做法
  6. 论算法人的语言表达能力
  7. 百宝云Post与Get事件教程
  8. 【SpringBoot】Bean 注入失败问题汇总
  9. 获取pc微信信息_如何获取有关您的PC的详细信息
  10. 同样是VPS,为什么RAKsmart更受欢迎