杂文
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卡
有什么好的建议可以留言给我