Windows读取NXP MiFare Ultralight C类型NFC卡片的信息

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?

Reading a NFC Mifare card raw data in android

tijins/NfcLib

About the NDEF Format

MIFARE Ultralight 系列

RC-S380 非接触ICカードリーダー/ライター PaSoRi(パソリ)

原文地址:https://www.cnblogs.com/AlvinLiang/p/9889992.html

时间: 2024-11-05 17:28:36

Windows读取NXP MiFare Ultralight C类型NFC卡片的信息的相关文章

射频识别技术漫谈(16)——Mifare UltraLight

Mifare UltraLight又称为MF0,从UltraLight(超轻的)这个名字就可以看出来,它是一个低成本.小容量的卡片.低成本,是指它是目前市场中价格最低的遵守ISO14443A协议的芯片之一:小容量,是指其存储容量只有512bit(Mifare S50有8192bit). Mifare UltraLight的512bit存储容量分成16个Page,每个Page包含4个字节,如下图所示: Page0和Page1以及Page2的第1个字节是卡片的7字节序列号及其校验字节,其中BCC0=

Windows上常见的集中布尔类型的比较

博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:Windows上常见的集中布尔类型的比较.

wpf prism4 出现问题:无法加载一个或多个请求的类型。有关更多信息,请检索 LoaderExceptions 属性。

WPF Prism 框架 程序 出现 问题: 无法加载一个或多个请求的类型.有关更多信息,请检索 LoaderExceptions 属性. 1.开始以为是配置的问题,找了半天,最后原来是有个依赖类库没有引用. 错误如图: 2.最后找到这个,原来是有个依赖模块问题: 如图: 哎呀,恍然大悟,主程序 引用System.Windows.Interactivity.dll类库,问题解决!

无法加载一个或多个请求的类型。有关更多信息,请检索 LoaderExceptions 属性。

新建一个MVC4的项目,引用DAL后,将DAL的连接字符串考入: <connectionStrings>     <add name="brnmallEntities" connectionString="metadata=res://*/BrnMall.csdl|res://*/BrnMall.ssdl|res://*/BrnMall.msl;provider=System.Data.SqlClient;provider connection string

Sqlserver查询表结构信息-字段说明、类型、长度等信息

Sqlserver 中查询表结构信息-字段说明.类型.长度等信息综合语法. SELECT 表名 = d.name,--case when a.colorder=1 then d.name else '' end, 表说明 = case when a.colorder=1 then isnull(f.value,'') else '' end, 字段序号 = a.colorder, 字段名 = a.name, 标识 = case when COLUMNPROPERTY( a.id,a.name,'

“无法加载一个或多个请求的类型。有关更多信息,请检索 LoaderExceptions 属性 “之解决

今天在学习插件系统设计的时候遇到一个问题:“System.Reflection.ReflectionTypeLoadException: 无法加载一个或多个请求的类型. 于是百度一下,很多内容都差不多,摘抄一个: ------------------------------ 今天突然遇到“System.Reflection.ReflectionTypeLoadException: 无法加载一个或多个请求的类型.有关更多信息,请检索 LoaderExceptions 属性.”这样的报错,找了好长时

SAP MM 自定义条件类型出现在采购信息记录的&#39;条件&#39;界面里 ?

SAP MM 自定义条件类型出现在采购信息记录的'条件'界面里 ? 我在SAP系统里复制某个标准的采购条件类型,创建了一个新的自定义条件类型ZC05,并将其分配采购定价过程RM0000. 结果却出现一个怪现象:在ME11/ME12/ME13去维护采购信息记录的时候,当点击'条件'按钮后,该条件类型与条件类型PB00一起出现在一个小窗口里,如下图: 类似的界面也出现在合同单据里,当我们选中某个ITEM去看条件数据的时候. 为啥会这样?这可是头一回遇到!经过研究与调查,找到了原因与解决办法. 解决办

读取注册表获取Windows系统XP/7/8/10类型(使用wcscmp比较wchar[]内容)

很多方案是采用GetVersion.GetVersionEx这两个API来查询操作系统的版本号来判断当前的操作系统是Windows系列中的哪个,在Win10没有出现前,这种方法是行的通的,但是Win10出现后此方法对于判断Win10就不准了. 在此提供一个读取注册表的方法,已经验证过可行: [cpp] view plain copy //查看注册表获知:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentV

C#读取注册表中二进制类型的值(REG_BINARY)

如需要读取注册表中某个键的值, 例如读取DriverDesc对应的值,一般情况下为String类型,读取代码如下: RegistryKey driverKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Class\{4D36E968-E325-11CE-BFC1-08002BE10318}\0000"); string result = (String)driverKey.GetValue