1,讀取
我們需要外接一個NFC Reader讓Windows可以讀取NFC卡片的內容。
因為特殊原因,我們選擇了Sony rc-s380 NFC Reader。相關介紹
我們需要下載並安裝NFC Port Software,以便我們可以順利使用上述NFC Reader。
安裝之后,我們需要去Github獲取一個NFC Port Software的.Net封裝包:tijins/NfcLib
解壓並運行nfc_lib_sample之后我們可以看到這樣一個WindowFrom程序。
因為現在要讀取的卡類型試MIFARE,所以我們勾選正確的CheckBox,其他設置保持不變,依次點擊上述三個橘色方框按鈕。
在紅色箭頭所指的方向就能看到第一個block的十六進制字符串的數據。
為了讀取卡片所有block/page的信息,我們將btRead_Click的代碼稍稍修改為:
private void btRead_Click(object sender, EventArgs e) { byte block = (byte)nudBlock.Value; try { byte[] data = null; data = new byte[NfcLib.MF_BLOCK_LENGTH]; if (card is Mifare) { StringBuilder readSB = new StringBuilder(); for(byte i=0;i < 45; i++)//我現在的卡包含45個blocks/pages { ((Mifare)card).Read(i, data, 0); readSB.AppendLine(Utility.ByteToHex(data, 0, data.Length)); } tbRead.Text = readSB.ToString(); } } catch (Exception ex) { MessageBox.Show(ex.Message); } }
有個小遺憾就是,如果NFC Reader沒有連接的時候啟動app會拋出異常,而如果app已經啟動再拔出然后插入NFC Reader又會無法再讀卡除非重啟app或者重新初始化。這個需要有點改進。
2,解析
根據上述步驟,我們得到了某張卡的信息如下:
04 C9 02 47 0A C9 5A 84 1D 48 00 00 E1 10 12 00 0A C9 5A 84 1D 48 00 00 E1 10 12 00 01 03 A0 0C 1D 48 00 00 E1 10 12 00 01 03 A0 0C 34 03 0F D1 E1 10 12 00 01 03 A0 0C 34 03 0F D1 01 0B 54 02 01 03 A0 0C 34 03 0F D1 01 0B 54 02 65 6E 32 30 34 03 0F D1 01 0B 54 02 65 6E 32 30 31 38 31 30 01 0B 54 02 65 6E 32 30 31 38 31 30 32 35 FE 00 65 6E 32 30 31 38 31 30 32 35 FE 00 00 00 00 00 31 38 31 30 32 35 FE 00 00 00 00 00 00 00 00 00 32 35 FE 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (以下省略...)
然后,我們對它做一點移位:
04 C9 02 47 0A C9 5A 84 1D 48 00 00 E1 10 12 00
0A C9 5A 84 1D 48 00 00 E1 10 12 00 01 03 A0 0C 1D 48 00 00 E1 10 12 00 01 03 A0 0C 34 03 0F D1 E1 10 12 00 01 03 A0 0C 34 03 0F D1 01 0B 54 02
01 03 A0 0C 34 03 0F D1 01 0B 54 02 65 6E 32 30 34 03 0F D1 01 0B 54 02 65 6E 32 30 31 38 31 30 01 0B 54 02 65 6E 32 30 31 38 31 30 32 35 FE 00 65 6E 32 30 31 38 31 30 32 35 FE 00 00 00 00 00
31 38 31 30 32 35 FE 00 00 00 00 00 00 00 00 00 32 35 FE 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
可以看出,每一行只有第一列是我們需要的tag信息。
04 C9 02 47 0A C9 5A 84 1D 48 00 00 E1 10 12 00
01 03 A0 0C 34 03 0F D1 01 0B 54 02 65 6E 32 30 31 38 31 30 32 35 FE 00
前面的四行是卡的UID以及制造商等信息。我們只需要關心下半段的數據。
01 (Tag: Lock Control TLV) 03 (Length: 3 bytes) A0 0C 34 (Value: Information on position and function of lock bytes) 03 (Tag: NDEF Message TLV) 0F (Length: 15 bytes) D1 01 0B 54 02 65 6E 32 30 31 38 31 30 32 35 FE (Tag: Terminator TLV; has no length field) 00
所以,我們得到了NDEF message:D1 01 0B 54 02 65 6E 32 30 31 38 31 30 32 35
NDEF message: D1 (Header byte of record 1) 01 (Type length: 1 byte) 0B (Payload length: 11 bytes) 54 (Type: "T") 02 65 6E 32 30 31 38 31 30 32 35 (Payload field)
我們再分析最為關鍵的payload field,如下:
The payload field: 02 (Status byte: Text is UTF-8 encoded, Language code has a length of 2 bytes) 65 6E (Language code: "en") 32 30 31 38 31 30 32 35 (Text: "20181025")
可以用在線工具來驗證一下 “32 30 31 38 31 30 32 35 ”
最后,上述步驟,用寫C#的實現如下(不保證所有Mifare卡適用):
private string GetNfcTag(List<byte[]> cardContentList) { List<byte> cardBytes = new List<byte>(); foreach(byte[] rowCardContent in cardContentList) { cardBytes.AddRange(rowCardContent.Take(4)); } byte[] cardUid = cardBytes.Take(8).ToArray(); string cardUidStr = Utility.ByteToHex(cardUid, 0, cardUid.Length); byte[] cardMaker = cardBytes.Skip(8).Take(8).ToArray(); string cardMakerStr = Utility.ByteToHex(cardMaker, 0, cardMaker.Length); byte[] memoryBytes = cardBytes.Skip(16).ToArray(); byte lockControlByte = memoryBytes[0]; byte lockByteCount = memoryBytes[1];//how many bytes are the lock bytes byte[] lockBytes = memoryBytes.Skip(2).Take(lockByteCount).ToArray(); int nedfLengthByteIndex = 1 + lockByteCount + 1 + 1; byte ndefLength = memoryBytes[nedfLengthByteIndex]; if (ndefLength == 0)//Tag empty return string.Empty; byte[] ndefBytes = memoryBytes.Skip(nedfLengthByteIndex + 1).Take(ndefLength).ToArray(); byte payloadHeader = ndefBytes[0]; byte payloadTypeLength = ndefBytes[1]; byte payloadLength = ndefBytes[2]; byte[] payloadType = ndefBytes.Skip(3).Take(payloadTypeLength).ToArray(); byte[] payloadBytes = ndefBytes.Skip(3 + payloadType.Length).Take(payloadLength).ToArray(); byte languageCodeLength = payloadBytes[0]; byte[] languageCode = payloadBytes.Skip(1).Take(languageCodeLength).ToArray(); byte[] tag = payloadBytes.Skip(1 + languageCode.Length).Take(payloadLength - languageCode.Length - 1).ToArray(); string tagHex= Utility.ByteToHex(tag , 0, tag .Length); string tagStr = Encoding.UTF8.GetString(tag); return tagStr; }
參考鏈接:
How to read binary blocks of mifare card?