当前位置: 首页>編程日記>正文

【IoT】NFC APDU 使用基础浅析

【IoT】NFC APDU 使用基础浅析

目前常见的智能 IC 卡运行着 JavaCard 虚拟机,智能 IC 卡上可以运行由精简后的 Java 语言编写的卡应用(简称 Applet)。

智能 IC 卡的 Applet 不能自己启动,必须由外部终端(例如 POS 机,地铁刷卡终端等)向卡片发送 Select 命令,由此选中卡片的 Applet,Applet 才能运行。

Appplet 侧重于数据的处理,没有花销的 I/O 功能。

Applet 的程序有生命周期和指定入口,其中最主要的几个方法如下:

a、public static void install(byte[] bArray, short bOffset, byte bLength)

构建了 Applet 子类的实例,JCRE 将会最先调用这个,所有的初始化和分配内存的操作应该在这个里面实现,可以获取卡外实体传进来的一些应用初始化参数。

b、public void process(APDU apdu)

类似于正常 java class 的 main,在安装后,APDU 的执行将在这里实现。

c、protected final void register()

applet 用来在 JCRE 中注册该 applet 实例

d、register(byte[] bArray, short bOffset, byte bLength)

register() 功能一样,增加了可以分配其特定的 AID 的功能。

e、public boolean select()

JCRE 一旦接收到 SELECT[by name] 命令时,将寻找命令中指示的 AID 对应的 Applet,使之处于活跃状态,接收并处理接下来的 APDU 命令;

在选择新的 Applet 前,JCRE 先调用当前 Applet 的 deselect 方法;

Applet 可以拒绝被选择,此时 select 方法返回 false;SELECT[by name] 命令本身也将传递给 applet 处理,此时通过 selectingApplet 用以判断当前状态。

包含一个 JavaCard 的 Applet 实现和一个 Android 端的 NFC 读写程序,实现智能 IC 卡与 Android 手机的简单通信。

1、Applet 原理浅析

接下来贴段简单的 Applet 源码,下载地址:http://download.csdn.net/detail/hellogv/8090041。

大概的思路是:Applet 定义了2个开头标识皆为 CMD_CLA 的自定义命令 CMD_INS_1 和 CMD_INS_2,当 Android 手机通过 NFC 分别发送 CMD_INS_1 和 CMD_INS_2,Applet 分别返回 strHello 和 strWorld。

核心源码如下:

public class mytest extends Applet {private static final byte[] strHello= { (byte) 'H', (byte) 'e',(byte) 'l', (byte) 'l', (byte) 'o'};private static final byte[] strWorld = {(byte) 'W',(byte) 'o', (byte) 'r', (byte) 'l', (byte) 'd', };private static final byte CMD_CLA = (byte) 0x80;private static final byte CMD_INS_1 = (byte) 0x10;private static final byte CMD_INS_2 = (byte) 0x20;public static void install(byte[] bArray, short bOffset, byte bLength) {// GP-compliant JavaCard applet registrationnew mytest().register(bArray, (short) (bOffset + 1), bArray[bOffset]);}/** 当Java卡Applet被选中时,由JCRE调用。Java卡Applet可以定义select()完成初始化,* 否则,JCRE调用父类的select()。* @see javacard.framework.Applet#select()*/public boolean select() {short debug=100;debug++;//用于断点调试,当被select时触发。return super.select();}/** 当Java卡Applet被放弃时,由JCRE调用。Java卡Applet可以定义deselect()完成清除,* 否则,JCRE调用父类的deselect()。* @see javacard.framework.Applet#deselect()*/public void deselect() {short debug=100;debug++;//用于断点调试super.deselect();}/** 每次收到APDU命令,都会执行* @see javacard.framework.Applet#process(javacard.framework.APDU)*/public void process(APDU apdu) {if (selectingApplet()) {return;}//获取外部终端发过来的数据byte[] buffer = apdu.getBuffer();//获取第一位数据byte CLA = (byte) (buffer[ISO7816.OFFSET_CLA] & 0xFF);//获取第二位数据byte INS = (byte) (buffer[ISO7816.OFFSET_INS] & 0xFF);if (CLA != CMD_CLA) {//格式不对ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);}switch (INS) {case CMD_INS_1:sendBytes(apdu,strHello);break;case CMD_INS_2:sendBytes(apdu,strWorld);break;default:ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);}}private void sendBytes(APDU apdu,byte[] arrays) {byte[] buffer = apdu.getBuffer();short length = (short) arrays.length;Util.arrayCopyNonAtomic(arrays, (short) 0, buffer, (short) 0,(short) length);apdu.setOutgoingAndSend((short) 0, length);}
}

2、Android 终端模拟

接下来贴出 Android 端的核心代码,下载地址:http://download.csdn.net/detail/hellogv/8090053。

大概的思路是:Android 端的 NFC 读写程序定义 1 个 Applet的ID(AID),SELECT 命令的报文头(SELECT_APDU_HEADER),2个自定义命令CMD_INS_1和CMD_INS_2。首先使用AID和SELECT_APDU_HEADER生成完整的SELECT命令,transceive(发送)到卡片,用于启动卡片里的AID对应的Applet。启动卡片里的Applet后,NFC读写程序发送SAMPLE_COMMAND里面的2条自定义命令,Applet分别返回"Hello""World"。

核心源码如下:

public final class CardReader {private static final String TAG = "LoyaltyCardReader";// AID for our loyalty card service.private static final String SAMPLE_CARD_AID = "1122001122";// ISO-DEP command HEADER for selecting an AID.// Format: [Class | Instruction | Parameter 1 | Parameter 2]private static final String SELECT_APDU_HEADER = "00A40400";// "OK" status word sent in response to SELECT AID command (0x9000)private static final byte[] SELECT_OK_SW = {(byte) 0x90, (byte) 0x00};//自定义的命令private static final String[] SAMPLE_COMMAND={"8010000000",//卡片收到后返回"Hello""8020000000"};//卡片收到后返回"World"public static String[][] TECHLISTS;public static IntentFilter[] FILTERS;static {try {//the tech lists used to perform matching for dispatching of the ACTION_TECH_DISCOVERED intentTECHLISTS = new String[][] { { IsoDep.class.getName() }};FILTERS = new IntentFilter[] { new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED, "*/*") };} catch (Exception e) {}}static public String tagDiscovered(Tag tag) {Log.e(TAG, "New tag discovered");String strResult="";IsoDep isoDep = IsoDep.get(tag);if (isoDep != null) {try {// Connect to the remote NFC deviceisoDep.connect();//发送select 命令,卡片会返回SELECT_OK_SW(90 00)byte[] cmdSelect = BuildSelectApdu(SAMPLE_CARD_AID);Log.e(TAG, "Sending: " + ByteArrayToHexString(cmdSelect));byte[] result = isoDep.transceive(cmdSelect);Log.e(TAG, "Receive: " + ByteArrayToHexString(result));byte[][] response = getResponse(result);byte[] statusWord =response[0];if (Arrays.equals(SELECT_OK_SW, statusWord) == false)return "";//循环发送自定义命令for(int i=0;i<SAMPLE_COMMAND.length;i++){String command = SAMPLE_COMMAND[i];result = HexStringToByteArray(command);Log.e(TAG, "Sending: " + command);result = isoDep.transceive(result);Log.e(TAG, "Receive: " + ByteArrayToHexString(result));response = getResponse(result);byte[] body =response[1];strResult=strResult+new String(body)+":"+ByteArrayToHexString(body)+"\r\n";}return strResult;} catch (IOException e) {Log.e(TAG, "Error communicating with card: " + e.toString());}}return null;}/**** 分解卡片返回的数据* @param b* @return [0]表示返回的状态值,[1]表示返回的正文*/private static byte[][] getResponse(byte[] b){byte[][] result = new byte[2][];int length = b.length;byte[] status = { b[length - 2],b[length - 1] };byte[] body = Arrays.copyOf(b, length - 2);result[0]=status;result[1]=body;return result;}public static String load(Parcelable parcelable) {// 从Parcelable筛选出各类NFC标准数据final Tag tag = (Tag) parcelable;return tagDiscovered(tag);}/*** Build APDU for SELECT AID command. This command indicates which service a reader is* interested in communicating with. See ISO 7816-4.** @param aid Application ID (AID) to select* @return APDU for SELECT AID command*/public static byte[] BuildSelectApdu(String aid) {// Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA]return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X", aid.length() / 2) + aid);}/*** Utility class to convert a byte array to a hexadecimal string.** @param bytes Bytes to convert* @return String, containing hexadecimal representation.*/public static String ByteArrayToHexString(byte[] bytes) {final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};char[] hexChars = new char[bytes.length * 2];int v;for ( int j = 0; j < bytes.length; j++ ) {v = bytes[j] & 0xFF;hexChars[j * 2] = hexArray[v >>> 4];hexChars[j * 2 + 1] = hexArray[v & 0x0F];}return new String(hexChars);}/*** Utility class to convert a hexadecimal string to a byte string.** <p>Behavior with input strings containing non-hexadecimal characters is undefined.** @param s String containing hexadecimal characters to convert* @return Byte array generated from input*/public static byte[] HexStringToByteArray(String s) {int len = s.length();byte[] data = new byte[len / 2];for (int i = 0; i < len; i += 2) {data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)+ Character.digit(s.charAt(i+1), 16));}return data;}
}

 

refer:http://blog.csdn.net/hellogv/ 

 


https://www.fengoutiyan.com/post/15012.html

相关文章:

  • 自动化nfc
  • arduino nfc
  • NFC功能可以打开吗
  • nfc读卡器模式
  • NFC有什么用
  • 手机nfc读写ic卡
  • NFC应用
  • NFC模式
  • 鏡像模式如何設置在哪,圖片鏡像操作
  • 什么軟件可以把圖片鏡像翻轉,C#圖片處理 解決左右鏡像相反(旋轉圖片)
  • 手機照片鏡像翻轉,C#圖像鏡像
  • 視頻鏡像翻轉軟件,python圖片鏡像翻轉_python中鏡像實現方法
  • 什么軟件可以把圖片鏡像翻轉,利用PS實現圖片的鏡像處理
  • 照片鏡像翻轉app,java實現圖片鏡像翻轉
  • 什么軟件可以把圖片鏡像翻轉,python圖片鏡像翻轉_python圖像處理之鏡像實現方法
  • matlab下載,matlab如何鏡像處理圖片,matlab實現圖像鏡像
  • 圖片鏡像翻轉,MATLAB:鏡像圖片
  • 鏡像翻轉圖片的軟件,圖像處理:實現圖片鏡像(基于python)
  • canvas可畫,JavaScript - canvas - 鏡像圖片
  • 圖片鏡像翻轉,UGUI優化:使用鏡像圖片
  • Codeforces,CodeForces 1253C
  • MySQL下載安裝,Mysql ERROR: 1253 解決方法
  • 勝利大逃亡英雄逃亡方案,HDU - 1253 勝利大逃亡 BFS
  • 大一c語言期末考試試題及答案匯總,電大計算機C語言1253,1253《C語言程序設計》電大期末精彩試題及其問題詳解
  • lu求解線性方程組,P1253 [yLOI2018] 扶蘇的問題 (線段樹)
  • c語言程序設計基礎題庫,1253號C語言程序設計試題,2016年1月試卷號1253C語言程序設計A.pdf
  • 信奧賽一本通官網,【信奧賽一本通】1253:抓住那頭牛(詳細代碼)
  • c語言程序設計1253,1253c語言程序設計a(2010年1月)
  • 勝利大逃亡英雄逃亡方案,BFS——1253 勝利大逃亡
  • 直流電壓測量模塊,IM1253B交直流電能計量模塊(艾銳達光電)
  • c語言程序設計第三版課后答案,【渝粵題庫】國家開放大學2021春1253C語言程序設計答案
  • 18轉換為二進制,1253. 將數字轉換為16進制
  • light-emitting diode,LightOJ-1253 Misere Nim
  • masterroyale魔改版,1253 Dungeon Master
  • codeformer官網中文版,codeforces.1253 B
  • c語言程序設計考研真題及答案,2020C語言程序設計1253,1253計算機科學與技術專業C語言程序設計A科目2020年09月國家開 放大學(中央廣播電視大學)
  • c語言程序設計基礎題庫,1253本科2016c語言程序設計試題,1253電大《C語言程序設計A》試題和答案200901
  • 肇事逃逸車輛無法聯系到車主怎么辦,1253尋找肇事司機