.NET MiFare 辅助类
本文介绍了一个 .NET 类,该类使 MiFare 卡的使用更加容易。
引言
MIFare 是一种允许无电池存储卡和读卡器之间进行非接触式数据传输的技术。MiFare 广泛用于票务(伦敦地铁的牡蛎卡)或门禁控制。本文介绍的辅助类的目的是简化在 .NET 应用程序中使用 MiFare 存储卡。特别是,该辅助类实现了以下功能
- 读/写 MiFare 卡数据块
- 设置读/写权限和卡密钥
- 应用程序目录 (MAD) 管理
背景
有几种 MiFare 存储卡。本文讨论了所谓的 MiFare Classic,它有两种尺寸:1 千字节和 4 千字节。1K 存储卡被组织成 16 个扇区。每个扇区由 4 个数据块组成,每个数据块大小为 16 字节。第 4 个数据块存储剩余 3 个数据块的读写权限。第 4 个数据块还存储访问密钥。根据 MiFare 规范,存在两个密钥,分别名为 `keyA` 和 `keyB`。每个密钥可以被授予对数据块的不同操作集。只有在应用程序使用正确的密钥成功登录到扇区后,才能读取或写入扇区中的数据块。4K 存储卡的组织方式类似。有 40 个扇区。前 32 个扇区有 4 个数据块,其余 8 个有 16 个数据块。扇区 0 的第一个数据块存储一些只读制造商信息。扇区 0 中的另外 2 个数据块存储 MiFare 应用程序目录 (MAD)。应用程序目录说明了卡上每个扇区使用的应用程序。该应用程序由注册到 Mifare 授权机构的唯一标识符标识。扇区 0 中的 MAD 处理扇区 1 到 15 中的应用程序。还有另一个 MAD(称为 MAD2)存储在扇区 16 中,它处理扇区 17 到 39 中的扇区。
Using the Code
MiFare
辅助类的目的是简化在 .NET 应用程序中使用 MiFare。
实例化
要实例化一个 MiFARECard
类,只需调用构造函数,传入一个实现 ICardReader
接口的对象的实例。 ICardReader
接口将 MiFareCard
与 MiFare
读卡器的物理实现解耦。 ICardReader
接口定义了以下方法
MiFARECard card = new MiFARECard(new FileCardReader(“test.txt”));
FileCardReader
是一个实现了 ICardReader
接口的类,并简化了 MiFARECard
类的测试。 FileReaderCard
类从磁盘上的文本文件中读取和写入数据。即使没有 MiFare
读卡器,这也可以轻松测试辅助类。
数据块的读/写
为了从卡中读取数据,MiFareCard
类实现了两种机制
- 调用
MiFARECard
类的GetData
/SetData
方法。这些方法允许写入任意长度的数据。MiFARECard
类将负责登录到所需的扇区。尾部扇区不会被覆盖。MiFARECard card = new MiFARECard(new FileCardReader(“test.txt”)); // read a block of data. The MiFARECard object will take care to login into // the proper sectors Byte[] data = card.GetData(sector, datablock, 64); // change data here.. // write data into MiFARECard class internal members card.SetData(sector, datablock, data); // write changes on card card.Flush();
- 调用 MiFare 卡上的
GetSector
方法。此方法返回一个Sector
对象。然后,在该对象上,您可以调用GetData
/SetData
方法以获取给定数据块的内容。MiFARECard card = new MiFARECard(new FileCardReader(“test.txt”)); // load the sector of interest Sector s = card.GetSector(sector); // read data from the datablock Byte[] data = s.GetData(datablock); // changes data. Because GetData do not make copies of internal data, // any changes to the data array is automatically reflected into the sector for (int i=0; i<data.Length; i++) data[i] = (byte)0x11; // write changes back to the card card.Flush();
请注意,要将更改写回卡中,请调用
Flush
方法。此方法将负责仅将实际更改的数据块写入磁盘。
设置扇区权限
要设置扇区权限,Sector
类提供了一个名为 AccessConditions
的属性。 AccessConditions
类公开了一个属性 (DataAreas
),该属性允许应用程序为每个数据块设置每个操作(Read
, Write
, Increment
, Decrement
)的权限 (Never
, KeyA
, KeyB
, KeyAOrB
)。 AccessConditions
类还允许应用程序设置密钥 A 和 B,并设置是否使用 MAD。
Sector sector0 = card.GetSector(0);
sector0.Access.DataAreas[0].Read = DataAreaAccessCondition.ConditionEnum.KeyAOrB;
sector0.Access.DataAreas[0].Write = DataAreaAccessCondition.ConditionEnum.KeyB;
sector0.Access.DataAreas[0].Increment = DataAreaAccessCondition.ConditionEnum.Never;
sector0.Access.DataAreas[0].Decrement = DataAreaAccessCondition.ConditionEnum.Never;
sector0.FlushTrailer("A0A1A2A3A4A5", "111111111111");
MAD 和 MAD2 管理
为了管理 MAD 和 MAD2,MiFARECard
类实现了两种方法
GetSectors(int appId)
:此方法返回当前由给定应用程序使用的扇区的列表。AddAppId(int appId)
:此方法为给定的应用程序保留一个扇区,并返回保留的扇区的编号。例如,根据 MAD 规范,想要保留一个扇区使用的应用程序的源代码应如下所示
MiFARECard card = new MiFARECard(); int[] sectors = card.GetSectors(0x5210); int appSector; If ((sectors != null) && (sectors.Length > 0)) { appSector = sectors[0]; } else { appSector = card.AddAppId(0x5210); If (appSector == -1) Throw new NoSectorsAvailableException(); } // get data from reserved sector Sector s = card.GetSector(appSector);
历史
- 2011 年 1 月 5 日:初始版本