雜文
02C3A448 2D 0804008500AABBCCDDEEFF
17B5A448 4E 0804008500AABBCCDDEEFF
A5AFA448 E6 0804008500AABBCCDDEEFF
文章參考
1.http://blog.sina.com.cn/s/blog_9ed067ad0100zyjx.html
2.http://www.sanlen.com/news/e7/2014-02-25/sl_news_41597.htm
3.http://blog.sina.com.cn/s/blog_9ed067ad01010i4v.html
14443
Mifare S50與Mifare S70
Mifare S50和Mifare S70又常被稱為Mifare Standard、Mifare Classic、MF1,是遵守ISO14443A標准的卡片中應用最為廣泛、影響力最大的的一員。而Mifare S70的容量是S50的4倍,S50的容量是1K字節,S70的容量為4K字節。讀寫器對卡片的操作時序和操作命令,二者完全一致。
Mifare S50和Mifare S70的每張卡片都有一個4字節的全球唯一序列號,卡上數據保存期為10年,可改寫10萬次,讀無限次。一般的應用中,不用考慮卡片是否會被讀壞寫壞的問題,當然暴力硬損壞除外。
Mifare S50和Mifare S70的區別主要有兩個方面。一是讀寫器對卡片發出請求命令,二者應答返回的卡類型(ATQA)字節不同。Mifare S50的卡類型(ATQA)是0004H,Mifare S70的卡類型(ATQA)是0002H。另一個區別就是二者的容量和內存結構不同。
Mifare S50把1K字節的容量分為16個扇區(Sector0-Sector15),每個扇區包括4個數據塊(Block0-Block3,我們也將16個扇區的64個塊按絕對地址編號為0~63),每個數據塊包含16個字節(Byte0-Byte15),64*16=1024。
如下表所示:
| 扇區號 |
塊號 |
|
塊類型 |
總塊號 |
| 扇區0 |
塊0 |
廠商代碼 |
廠商塊 |
0 |
|
|
塊1 |
|
數據塊 |
1 |
|
|
塊2 |
|
數據塊 |
2 |
|
|
塊3 |
密碼A 存取控制 密碼B |
控制塊 |
3 |
| 扇區1 |
塊0 |
|
數據塊 |
4 |
| 塊1 |
|
數據塊 |
5 |
|
|
|
塊2 |
|
數據塊 |
6 |
|
|
塊3 |
密碼A 存取控制 密碼B |
控制塊 |
7 |
| ... |
... |
... |
... |
... |
| 扇區15 |
塊0 |
|
數據塊 |
60 |
|
|
塊1 |
|
數據塊 |
61 |
|
|
塊2 |
|
數據塊 |
62 |
|
|
塊3 |
密碼A 存取控制 密碼B |
控制塊 |
63 |
Mifare S70把4K字節的容量分為40個扇區(Sector0-Sector39),其中前32個扇區(Sector0-Sector31)的結構和Mifare S50完全一樣,每個扇區包括4個數據塊(Block0-Block3),后8個扇區每個扇區包括16個數據塊(Block0-Block15)。我們也將40個扇區的256個塊按絕對地址編號為0~255),每個數據塊包含16個字節(Byte0-Byte15),256*16=4096。如下表所示:
| 扇區號 |
塊號 |
|
塊類型 |
總塊號 |
| 扇區0 |
塊0 |
廠商代碼 |
廠商塊 |
0 |
|
|
塊1 |
|
數據塊 |
1 |
|
|
塊2 |
|
數據塊 |
2 |
|
|
塊3 |
密碼A 存取控制 密碼B |
控制塊 |
3 |
| … |
… |
… |
… |
… |
| 扇區31 |
塊0 |
|
數據塊 |
124 |
|
|
塊1 |
|
數據塊 |
125 |
|
|
塊2 |
|
數據塊 |
126 |
|
|
塊3 |
密碼A 存取控制 密碼B |
控制塊 |
127 |
| 扇區32 |
塊0 |
|
數據塊 |
128 |
|
|
塊1 |
|
數據塊 |
129 |
|
|
… |
… |
數據塊 |
… |
|
|
塊14 |
|
數據塊 |
142 |
|
|
塊15 |
密碼A 存取控制 密碼B |
控制塊 |
143 |
| … |
… |
… |
… |
… |
| 扇區39 |
塊0 |
|
數據塊 |
240 |
|
|
塊1 |
|
數據塊 |
241 |
|
|
… |
… |
數據塊 |
… |
|
|
塊14 |
|
數據塊 |
254 |
|
|
塊15 |
密碼A 存取控制 密碼B |
控制塊 |
255 |
每個扇區都有一組獨立的密碼及訪問控制,放在每個扇區的最后一個Block,這個Block又被稱為區尾塊,S50是每個扇區的Block3,S70的前32個扇區也是Block3,后8個扇區是Block15。
S50和S70的0扇區0塊(即絕對地址0塊)用於存放廠商代碼,已經固化,不可更改,卡片序列號就存放在這里。除了廠商塊和控制塊,卡片中其余的塊都是數據塊,可用於存貯數據。數據塊可作兩種應用:
(1)用作一般的數據保存,可以進行讀、寫操作。
(2)用作數據值,可以進行初始化值、加值、減值、讀值操作。
數據塊和值塊有什么區別呢?無論塊中的內容是什么,你都可以把他看成普通數據,即使它是一個值塊。但是並不是任何數據都可以看成是值,因為值塊有一個比較嚴格的格式要求。值塊中值的長度為4個字節的補碼,其表示的范圍(-2147483648~2147483647),值塊的存儲格式如下:
| 15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
| addr |
addr |
addr |
addr |
VALUE |
VALUE |
VALUE |
|||||||||
帶下划線表示取反。VALUE是值的補碼,addr是塊號(0-63).只有具有上述格式,才被認為是值塊,否則就是普通的數據塊。
每個扇區的區尾塊為控制塊,包括了6字節密碼A、4字節存取控制、6字節密碼B。例如一張新出廠的卡片控制塊內容如下:
| A0 A1 A2 A3 A4 A5 FF 07 80 69 B0 B1 B2 B3 B4 B5 |
密碼A 存取控制 密碼B
新卡的出廠密碼一般是密碼A為A0A1A2A3A4A5,密碼B為B0B1B2B3B4B5,或者密碼A和密碼B都是6個FF。存取控制用以設定扇區中各個塊(包括控制塊本身)的存取條件
讀寫器與S50和S70的通訊流程如下圖所示:
S50與Mifare S70" o:button="t">
卡片選擇和三次相互認證在前面已經介紹過。其他操作如下:
(1)讀 (Read):讀取一個塊的內容,包括普通數據塊和值塊;
(2)寫 (Write):寫數據到一個塊,包括普通數據塊和值塊,值塊中寫入了非法格式的數據,值塊就變成了普通數據塊;
(3)加(Increment):對值塊進行加值,只能對值塊操作;
(4)減(Decrement):對值塊進行減值,只能對值塊操作;
(5)中止(Halt):將卡置於睡眠工作狀態,只有使用WAKE-UP命令才能喚醒。
事實上加值和減值操作並不是直接在Mifare的塊中進行的。這兩個命令先把Block中的值讀出來,然后進行加或減,加減后的結果暫時存放在卡上的易失性數據寄存器(RAM)中,然后再利用另一個命令傳輸(Transfer)將數據寄存器中的內容寫入塊中。與傳輸(Transfer)相對應的命令是存儲(Restore),作用是將塊中的內容存到數據寄存器中,不過這個命令很少用到。
惟一標識符說明
制造商塊地址是0x00,如表A-1所示。它包含IC制造商信息、惟一標識符(UID)。由於安全和系統需要,當IC制造商在生產過程中編程以后,這個塊是寫保護的,即不可改寫,符合本技術要求中對電子標簽惟一標識符的要求。
制造商塊字節編碼(Address:0x00h)
| Byte |
0 |
1 |
2 |
3 |
4 |
5-15 |
| Content |
0 1 2 3 4 5 惟一標識符(UID) |
BCC |
BCC 制造商信息 |
|||
其中 為惟一標識符(UID)校驗字節,Byte4 = Byte0 ^ Byte1 ^ Byte2 ^ Byte3
RFID讀寫器控制軟件-HID V1.0.5 使用說明(非官方)
針對 Mifare S50
- 測試
通過測試 讀取卡 知道。卡的標簽類型是Mifare S50
其數據結構:
- 密碼
1.新卡的出廠密碼一般是密碼A為A0A1A2A3A4A5,密碼B為B0B1B2B3B4B5,或者密碼A和密碼B都是6個FF。
2.出廠白卡的控制字通常是FF078069
3.每個扇區密碼獨立互不干擾。比如將0扇區密碼從6組 FF 改為 6組 AA,那么讀寫0扇區密碼就是6組 AA,而其他扇區密碼還是6組 FF;由於密碼A 是不可見 一旦忘記那你只能仰天長嘆了。(密碼數據類型:必須是十六進制數)
3.操作說明
4.塊號與塊數
14443卡 讀寫 Code 如下:
using RFIDRDH_NET; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace RFIDSystem { /// <summary> /// s50 讀卡器 /// </summary> public class Rfidrd14443 { #region 自定義變量 private static Rfidrd14443 rdh = null; /// <summary> /// 讀寫器設備句柄 大於0打開成功,小於或者等於0打開失敗 /// </summary> private int handleid; #endregion #region 自定義屬性 /// <summary> /// 是否打開讀寫器 /// </summary> private bool isOpen = false; public bool IsOpen { get { return isOpen; } set { isOpen = value; } } //public Rfidrd14443() //{ //} /// <summary> /// 打開設備 返回設備句柄 /// </summary> /// <returns></returns> public int OpenDevice() { if (IsOpen) { return handleid; } else { handleid = RFIDRDH.RD_OpenDevice(); if (handleid > 0) { IsOpen = true; } return handleid; } } /// <summary> /// 關閉 /// </summary> /// <returns></returns> public bool Close() { if (RFIDRDH.RD_CloseUSB(handleid) == 0) { isOpen = false; return true; } else { return false; } } /// <summary> /// 創建14443卡對象 /// </summary> /// <returns></returns> public static Rfidrd14443 GetRfidrd14443() { if (rdh == null) { rdh = new Rfidrd14443(); } return rdh; } #endregion #region 14443卡輔助方法 /// <summary> /// 寫入指定區域 /// </summary> /// <param name="afi">是否包含領域標識符</param> /// <param name="nBlockNo">塊號</param> /// <param name="sbPwd">密碼</param> /// <param name="data">存儲數據</param> /// <returns></returns> public bool Write14443Data(string afi, int nBlockNo, StringBuilder sbPwd,StringBuilder data) {//寫入指定區域 bool uafi = false; if (afi != null) { uafi = false; } List<RFID> rfids = GetRfidList(afi, uafi); if (rfids != null && rfids.Count > 0) { RFIDRDH.RD_SetUid(handleid, rfids[0].UID);//設置讀塊數據命令UID int r5 = RFIDRDH.RD_SelectTag(handleid);//選擇標簽 if (r5 != 0) return false; int r6= RFIDRDH.RD_SetAuth(handleid, 0, 0, sbPwd);//設置密碼相關參數 if (r6 != 0) return false; //int r7 = RFIDRDH.RD_Autnenticate(handleid, 0);//標簽認證 //if (r7 != 0) // return null; //StringBuilder writePwd =new StringBuilder(); //writePwd.Append("333333333000000000000000000000000"); int r8 = RFIDRDH.RD_WriteTagDataL(handleid, 8, data);//直接寫塊數據(為了方便管理,都存在8塊號) if (r8 == 0) return true; } return false; } /// <summary> /// 讀取指定塊信息 /// </summary> /// <param name="afi">是否包含領域標識符</param> /// <param name="nBlockNo">塊號</param> /// <param name="sbPwd">密碼</param> /// <returns></returns> public RFID ReadTagData(string afi, int nBlockNo, StringBuilder sbPwd) { int r100 = RFIDRDH.RD_SetBeep(handleid, 1);//為了解決蜂鳴聲重復響 if (r100 != 0) return null; #region 獲得讀卡產品的序列號 /* StringBuilder sbNum = new StringBuilder(); int result =0; int r101 = RFIDRDH.RD_GetSerialNum(sbNum, ref result); if (r101 != 0) return null;*/ #endregion bool uafi = false; if (afi != null) { uafi = true; } List<RFID> rfids = GetRfidList(afi, uafi); if (rfids != null && rfids.Count > 0) { int r4 = RFIDRDH.RD_SetUid(handleid, rfids[0].UID);//設置讀塊數據命令UID if (r4 != 0) { return null; } int r5 = RFIDRDH.RD_SelectTag(handleid);//選擇標簽 if (r5 != 0) return null; //sbPwd.Append("ffffffffffff"); int r6 = RFIDRDH.RD_SetAuth(handleid, 0, 0, sbPwd);//設置密碼相關參數 if (r6 != 0) return null; StringBuilder data = new StringBuilder(); RFIDRDH.RD_ReadTagDataL(handleid, nBlockNo, 1, data);//塊號8,塊數1 //if (r7 != 0) // return null; rfids[0].blockdata = data.ToString(); return rfids[0]; } return null; } public List<RFID> GetRfidList(string afi, bool useafi) { List<RFID> rfidsList = new List<RFID>(); int uafi = useafi==true ? 1 : 0; int r1 = RFIDRDH.RD_SetFlag(handleid, uafi, 0, 0, 1, 0, 0); //設置標志位 if (afi != null) { int r0 = RFIDRDH.RD_SetAfi(handleid, afi); } if (r1 != 0) return null; int r2 = RFIDRDH.RD_SetDefTagType(handleid, "0212");//S50 Mifare 1k if (r2 != 0) return null; StringBuilder sbTagPs=new StringBuilder(); int count = 0; int r3 = RFIDRDH.RD_InventoryTagPs(handleid, sbTagPs, ref count);//標簽檢測 if (sbTagPs.Length % 8 == 0) {//ISO14443A string uids = sbTagPs.ToString(); for (int i = 0; i < uids.Length; i += 8) { RFID rf = new RFID(); rf.UID = uids.Substring(i, 8); rfidsList.Add(rf); } return rfidsList; } return null; } #endregion #region 檢測是什么卡 /// <summary> /// 檢測卡 /// </summary> /// <param name="afi"></param> /// <param name="useafi"></param> /// <returns></returns> public string CardDetection(string afi, bool useafi) { int uafi = useafi == true ? 1 : 0; int r1 = RFIDRDH.RD_SetFlag(handleid, uafi, 0, 0, 1, 0, 0); //設置標志位 if (afi != null) { int r0 = RFIDRDH.RD_SetAfi(handleid, afi); } if (r1 != 0) return null; int r2 = RFIDRDH.RD_SetDefTagType(handleid, "0121");//S50 Mifare 1k //int r2 = RFIDRDH.RD_SetDefTagType(handleid, "0212"); if (r2 != 0) return null; StringBuilder sbTagPs = new StringBuilder(); int count = 0; int r3 = RFIDRDH.RD_InventoryTagPs(handleid, sbTagPs, ref count);//標簽檢測 if (sbTagPs.Length==16) { return "15693"; } if (r3 == 7) { int s2 = RFIDRDH.RD_SetDefTagType(handleid, "0212"); if (s2 != 0) return null; StringBuilder sbTagPs2 = new StringBuilder(); int s2count = 0; int s3 = RFIDRDH.RD_InventoryTagPs(handleid, sbTagPs2, ref s2count);//標簽檢測 if (sbTagPs2.Length == 8) {//ISO14443A return "14443"; } } return ""; } #endregion } }
<Window x:Class="WpfApplicationTest._14443Window" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="_14443Window" Height="300" Width="300"> <Grid> <Button Name="btn14443Read" Content="14443讀寫" Width="100" Height="20" Click="btn14443Read_Click" Margin="96,62,96,178"></Button> <Button x:Name="btn14443detection" Content="檢測卡類型" Width="100" Height="20" Click="btn14443detection_Click" Margin="96,130,96,110"/> </Grid> </Window>
using RFIDSystem; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace WpfApplicationTest { /// <summary> /// _14443Window.xaml 的交互邏輯 /// </summary> public partial class _14443Window : Window { public _14443Window() { InitializeComponent(); } private void btn14443Read_Click(object sender, RoutedEventArgs e) {//讀寫 try { Rfidrd14443 rfidcard = Rfidrd14443.GetRfidrd14443();//實例化14443卡對象 int mac = rfidcard.OpenDevice();//打開設備 if (mac <= 0) { MessageBox.Show("啟用讀卡器失敗!"); return; } StringBuilder sbPwd=new StringBuilder(); sbPwd.Append("ffffffffffff"); RFID rtag = rfidcard.ReadTagData(null,8,sbPwd); if (rtag != null) { if (rtag.blockdata[0] == '3') { MessageBox.Show("此卡已激活"); return; } StringBuilder data = new StringBuilder(); data.Append("33333333000000000000000000000000"); bool wtTag = rfidcard.Write14443Data(null, 8, sbPwd, data); if (wtTag) MessageBox.Show("寫入成功!"); else //卡已鎖定 不可用 MessageBox.Show("該卡已鎖定!"); } else { MessageBox.Show("未檢測磁卡片!"); } rfidcard.Close(); } catch(Exception ex) { MessageBox.Show("寫入異常"+ex.ToString()); } } private void btn14443detection_Click(object sender, RoutedEventArgs e) {//檢測 Rfidrd14443 rfidcard = Rfidrd14443.GetRfidrd14443();//實例化14443卡對象 int mac = rfidcard.OpenDevice();//打開設備 if (mac <= 0) { MessageBox.Show("啟用讀卡器失敗!"); return; } string afi = string.Empty; bool uafi = false; if (afi != null) { uafi = true; } string result = rfidcard.CardDetection(null, uafi); if (result != "") { MessageBox.Show("這個是" + result + "卡"); } else { MessageBox.Show("異常卡"); } } } }
源碼下載:密碼是我的名字,里面有介紹 C# 怎么用讀卡器 調用 15693卡 和 14443卡
有什么好的建議可以留言給我
