65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET MiFare 辅助类

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (6投票s)

2011年1月8日

CPOL

3分钟阅读

viewsIcon

73805

downloadIcon

6882

本文介绍了一个 .NET 类,该类使 MiFare 卡的使用更加容易。

引言

MIFare 是一种允许无电池存储卡和读卡器之间进行非接触式数据传输的技术。MiFare 广泛用于票务(伦敦地铁的牡蛎卡)或门禁控制。本文介绍的辅助类的目的是简化在 .NET 应用程序中使用 MiFare 存储卡。特别是,该辅助类实现了以下功能

  1. 读/写 MiFare 卡数据块
  2. 设置读/写权限和卡密钥
  3. 应用程序目录 (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 接口将 MiFareCardMiFare 读卡器的物理实现解耦。 ICardReader 接口定义了以下方法

MiFARECard card = new MiFARECard(new FileCardReader(“test.txt”));

FileCardReader 是一个实现了 ICardReader 接口的类,并简化了 MiFARECard 类的测试。 FileReaderCard 类从磁盘上的文本文件中读取和写入数据。即使没有 MiFare 读卡器,这也可以轻松测试辅助类。

数据块的读/写

为了从卡中读取数据,MiFareCard 类实现了两种机制

  1. 调用 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();
  2. 调用 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 类实现了两种方法

  1. GetSectors(int appId):此方法返回当前由给定应用程序使用的扇区的列表。
  2. 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 日:初始版本
© . All rights reserved.