• S50 14443卡和15693卡 读写研究


    杂文

    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

    1. 测试

    通过测试 读取卡 知道。卡的标签类型是Mifare S50

    其数据结构:

    1. 密码

    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卡

    有什么好的建议可以留言给我

  • 相关阅读:
    小米6刷机开启root权限
    C标准库堆内存函数
    UE4打印到HUD的Stat命令
    Blueprint Stats插件
    PC与Mobile硬件架构对比
    atomic原子编程中的Memory Order
    Windows10下开启D3D11的Debug Layer
    【数据结构】树存储结构
    【数据结构】哈希表
    【算法】查找算法
  • 原文地址:https://www.cnblogs.com/suntanyong88/p/4284219.html
Copyright © 2020-2023  润新知