【问题标题】:Get mifare card serial number with WinSCard library使用 WinSCard 库获取 mifare 卡序列号
【发布时间】:2013-05-31 11:50:01
【问题描述】:

我正在开发一个需要读取 mifare 卡序列号的应用程序,我使用的语言是 C#。

我是 mifare reader 编程的新手,所以很抱歉提出愚蠢的问题。 首先我想知道Mifare UID和Mifare序列号是否不同。

我已经在 WinSCard 库的帮助下获得了 UID,但我不知道如何获得应该是 10 位数字的卡序列号。

如果您能指出正确的方向,我将不胜感激。

提前感谢您的帮助。 问候

【问题讨论】:

    标签: c# .net rfid mifare winscard


    【解决方案1】:

    SCardTransmit 方法的 C# 签名

    [StructLayout(LayoutKind.Sequential)]
    public struct SCARD_IO_REQUEST
    {
       public int dwProtocol;
       public int cbPciLength;
    }
    
    [DllImport("winscard.dll")]
    public static extern int SCardTransmit(int hCard, ref SCARD_IO_REQUEST pioSendRequest,    ref byte SendBuff, int SendBuffLen, ref SCARD_IO_REQUEST pioRecvRequest,
    ref byte RecvBuff, ref int RecvBuffLen);
    

    读取mifare卡UID的代码示例

    private SmartcardErrorCode GetUID(ref byte[] UID)
        {
            byte[] receivedUID = new byte[10];
            UnsafeNativeMethods.SCARD_IO_REQUEST request = new UnsafeNativeMethods.SCARD_IO_REQUEST();
            request.dwProtocol = 1; //SCARD_PROTOCOL_T1);
            request.cbPciLength =    System.Runtime.InteropServices.Marshal.SizeOf(typeof(UnsafeNativeMethods.SCARD_IO_REQUEST));
            byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x04 }; //get UID command      for Mifare cards
    
            int outBytes = receivedUID.Length;
            int status = SCardTransmit(_hCard, ref request, ref sendBytes[0], sendBytes.Length,  ref request, ref receivedUID[0], ref outBytes);
    
            UID = receivedUID.Take(8).ToArray(); 
            return status;
        }
    

    【讨论】:

    【解决方案2】:

    所选答案不适用于 x64 环境。

    这是一个完整的示例代码,在 Windows 10 x64 上测试并运行。 这是做什么的:

    • 检索可用读者列表
    • 选择使用第一个可用的阅读器
    • 检查读卡器中是否有卡并连接。
    • 向卡发送命令以检索其 UID
    • 将 UID 转换为十六进制字符串。

      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Linq;
      using System.Runtime.InteropServices;
      using System.Text;
      
      namespace DXCutcsa.VO.Common
      {
          public class SmartCardReader
          {
              #region Atributos
      
          private bool _disposed = false;
          private IntPtr _ReaderContext = IntPtr.Zero;
          private string _ReaderName = string.Empty;
          private List<string> _AvailableReaders = new List<string>();
      
          #endregion
      
          #region Win32 APIs
      
          [DllImport("WinScard.dll")]
          static extern int SCardEstablishContext(uint dwScope,
              IntPtr notUsed1,
              IntPtr notUsed2,
              out IntPtr phContext);
      
          [DllImport("WinScard.dll")]
          static extern int SCardReleaseContext(IntPtr phContext);
      
          [DllImport("WinScard.dll")]
          static extern int SCardConnect(IntPtr hContext,
              string cReaderName,
              uint dwShareMode,
              uint dwPrefProtocol,
              ref IntPtr phCard,
              ref IntPtr ActiveProtocol);
      
          [DllImport("WinScard.dll")]
          static extern int SCardDisconnect(IntPtr hCard, int Disposition);
      
          [DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
          static extern int SCardListReaders(
              IntPtr hContext,
              byte[] mszGroups,
              byte[] mszReaders,
              ref UInt32 pcchReaders);
      
          [DllImport("winscard.dll")]
          static extern int SCardStatus(
                 uint hCard,
                 IntPtr szReaderName,
                 ref int pcchReaderLen,
                 ref int pdwState,
                 ref uint pdwProtocol,
                 byte[] pbAtr,
                 ref int pcbAtrLen);
      
          [DllImport("winscard.dll")]
          static extern int SCardTransmit(
              IntPtr hCard,
              ref SCARD_IO_REQUEST pioSendRequest,
              ref byte SendBuff,
              uint SendBuffLen,
              ref SCARD_IO_REQUEST pioRecvRequest,
              byte[] RecvBuff,
              ref uint RecvBuffLen);
      
          [DllImport("winscard.dll", SetLastError = true)]
          static extern int SCardGetAttrib(
             IntPtr hCard,            // Valor retornado en funcion ScardConnect
             UInt32 dwAttrId,         // Identificacion de atributos a obtener
             byte[] pbAttr,           // Puntero al vector atributos recividos 
             ref IntPtr pcbAttrLen    // Tamaño del vector
          );
      
          [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
          public struct ReaderState
          {
              public ReaderState(string sName)
              {
                  this.szReader = sName;
                  this.pvUserData = IntPtr.Zero;
                  this.dwCurrentState = 0;
                  this.dwEventState = 0;
                  this.cbATR = 0;
                  this.rgbATR = null;
              }
      
              internal string szReader;
              internal IntPtr pvUserData;
              internal uint dwCurrentState;
              internal uint dwEventState;
              internal uint cbATR;    // count of bytes in rgbATR
              [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24, ArraySubType = UnmanagedType.U1)]
              internal byte[] rgbATR;
          }
      
          [StructLayout(LayoutKind.Sequential)]
          public struct SCARD_IO_REQUEST
          {
              public UInt32 dwProtocol;
              public UInt32 cbPciLength;
          }
      
      
          /*****************************************************************/
          [DllImport("kernel32.dll", SetLastError = true)]
          private extern static IntPtr LoadLibrary(string lpFileName);
      
          [DllImport("kernel32.dll")]
          private extern static void FreeLibrary(IntPtr handle);
      
          [DllImport("kernel32.dll")]
          private extern static IntPtr GetProcAddress(IntPtr handle, string procName);
      
          #endregion
      
          #region Error codes
          public const uint S_SUCCESS = 0x00000000;
          public const uint F_INTERNAL_ERROR = 0x80100001;
          public const uint E_CANCELLED = 0x80100002;
          public const uint E_INVALID_HANDLE = 0x80100003;
          public const uint E_INVALID_PARAMETER = 0x80100004;
          public const uint E_INVALID_TARGET = 0x80100005;
          public const uint E_NO_MEMORY = 0x80100006;
          public const uint F_WAITED_TOO_LONG = 0x80100007;
          public const uint E_INSUFFICIENT_BUFFER = 0x80100008;
          public const uint E_UNKNOWN_READER = 0x80100009;
          public const uint E_TIMEOUT = 0x8010000A;
          public const uint E_SHARING_VIOLATION = 0x8010000B;
          public const uint E_NO_SMARTCARD = 0x8010000C;
          public const uint E_UNKNOWN_CARD = 0x8010000D;
          public const uint E_CANT_DISPOSE = 0x8010000E;
          public const uint E_PROTO_MISMATCH = 0x8010000F;
          public const uint E_NOT_READY = 0x80100010;
          public const uint E_INVALID_VALUE = 0x80100011;
          public const uint E_SYSTEM_CANCELLED = 0x80100012;
          public const uint F_COMM_ERROR = 0x80100013;
          public const uint F_UNKNOWN_ERROR = 0x80100014;
          public const uint E_INVALID_ATR = 0x80100015;
          public const uint E_NOT_TRANSACTED = 0x80100016;
          public const uint E_READER_UNAVAILABLE = 0x80100017;
          public const uint P_SHUTDOWN = 0x80100018;
          public const uint E_PCI_TOO_SMALL = 0x80100019;
          public const uint E_READER_UNSUPPORTED = 0x8010001A;
          public const uint E_DUPLICATE_READER = 0x8010001B;
          public const uint E_CARD_UNSUPPORTED = 0x8010001C;
          public const uint E_NO_SERVICE = 0x8010001D;
          public const uint E_SERVICE_STOPPED = 0x8010001E;
          public const uint E_UNEXPECTED = 0x8010001F;
          public const uint E_ICC_INSTALLATION = 0x80100020;
          public const uint E_ICC_CREATEORDER = 0x80100021;
          public const uint E_UNSUPPORTED_FEATURE = 0x80100022;
          public const uint E_DIR_NOT_FOUND = 0x80100023;
          public const uint E_FILE_NOT_FOUND = 0x80100024;
          public const uint E_NO_DIR = 0x80100025;
          public const uint E_NO_FILE = 0x80100026;
          public const uint E_NO_ACCESS = 0x80100027;
          public const uint E_WRITE_TOO_MANY = 0x80100028;
          public const uint E_BAD_SEEK = 0x80100029;
          public const uint E_INVALID_CHV = 0x8010002A;
          public const uint E_UNKNOWN_RES_MNG = 0x8010002B;
          public const uint E_NO_SUCH_CERTIFICATE = 0x8010002C;
          public const uint E_CERTIFICATE_UNAVAILABLE = 0x8010002D;
          public const uint E_NO_READERS_AVAILABLE = 0x8010002E;
          public const uint E_COMM_DATA_LOST = 0x8010002F;
          public const uint E_NO_KEY_CONTAINER = 0x80100030;
          public const uint W_UNSUPPORTED_CARD = 0x80100065;
          public const uint W_UNRESPONSIVE_CARD = 0x80100066;
          public const uint W_UNPOWERED_CARD = 0x80100067;
          public const uint W_RESET_CARD = 0x80100068;
          public const uint W_REMOVED_CARD = 0x80100069;
          public const uint W_SECURITY_VIOLATION = 0x8010006A;
          public const uint W_WRONG_CHV = 0x8010006B;
          public const uint W_CHV_BLOCKED = 0x8010006C;
          public const uint W_EOF = 0x8010006D;
          public const uint W_CANCELLED_BY_USER = 0x8010006E;
          public const uint W_CARD_NOT_AUTHENTICATED = 0x8010006F;
          #endregion
      
          #region Constructor
      
          public SmartCardReader()
          {
      
          }
          #endregion
      
          #region Metodos
      
          public long GetUID(ref byte[] UID)
          {
              long _result = 0;
              bool cardInserted = false;
      
      
              IntPtr _CardContext = IntPtr.Zero;
              IntPtr ActiveProtocol = IntPtr.Zero;
      
              // Establish Reader context:
              if (this._ReaderContext == IntPtr.Zero)
              {
                  _result = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out this._ReaderContext);
      
                  #region Get List of Available Readers
      
                  uint pcchReaders = 0;
                  int nullindex = -1;
                  char nullchar = (char)0;
      
                  // First call with 3rd parameter set to null gets readers buffer length.
                  _result = SCardListReaders(this._ReaderContext, null, null, ref pcchReaders);
      
                  byte[] mszReaders = new byte[pcchReaders];
      
                  // Fill readers buffer with second call.
                  _result = SCardListReaders(this._ReaderContext, null, mszReaders, ref pcchReaders);
      
                  // Populate List with readers.
                  string currbuff = new ASCIIEncoding().GetString(mszReaders);
                  int len = (int)pcchReaders;
      
                  if (len > 0)
                  {
                      while (currbuff[0] != nullchar)
                      {
                          nullindex = currbuff.IndexOf(nullchar);   // Get null end character.
                          string reader = currbuff.Substring(0, nullindex);
                          this._AvailableReaders.Add(reader);
                          len = len - (reader.Length + 1);
                          currbuff = currbuff.Substring(nullindex + 1, len);
                      }
                  }
      
                  #endregion
      
                  // Select the first reader:
                  this._ReaderName = this._AvailableReaders[0];
              }
      
              try
              {
                  //Check if there is a Card in the reader:
      
                  //dwShareMode: SCARD_SHARE_SHARED = 0x00000002 - This application will allow others to share the reader
                  //dwPreferredProtocols: SCARD_PROTOCOL_T0 - Use the T=0 protocol (value = 0x00000001)
      
                  if (this._ReaderContext != IntPtr.Zero)
                  {
                      _result = SCardConnect(this._ReaderContext, this._ReaderName, 0x00000002, 0x00000001, ref _CardContext, ref ActiveProtocol);
                      if (_result == 0)
                      {
                          cardInserted = true;
      
                          SCARD_IO_REQUEST request = new SCARD_IO_REQUEST()
                          {
                              dwProtocol = (uint)ActiveProtocol,
                              cbPciLength = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(SCARD_IO_REQUEST))
                          };
      
                          byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; //<- get UID command for iClass cards
                          byte[] ret_Bytes = new byte[33];
                          uint sendLen = (uint)sendBytes.Length;
                          uint ret_Len = (uint)ret_Bytes.Length;
      
                          _result = SCardTransmit(_CardContext, ref request, ref sendBytes[0], sendLen, ref request, ret_Bytes, ref ret_Len);
                          if (_result == 0)
                          {
                              UID = ret_Bytes.Take(4).ToArray(); //only take the first 8, the last 2 bytes are not part of the UID of the card                                                           
                              string dataOut = byteToHexa(UID, UID.Length, true).Trim(); //Devolver la respuesta en Hexadecimal
                          }
                      }
                  }
              }
              finally
              {
                  SCardDisconnect(_CardContext, 0);
                  SCardReleaseContext(this._ReaderContext);
              }
              return _result;
          }
      
      
          private string byteToHexa(byte[] byReadBuffer, int leng, bool bSpace)
          {
              string text2 = "";
              for (short num1 = 0; num1 < leng; num1 = (short)(num1 + 1))
              {
                  short num2 = byReadBuffer[num1];
      
                  text2 = text2 + System.Convert.ToString(num2, 16).PadLeft(2, '0');
      
                  if (bSpace)
                  {
                      text2 = text2 + " ";
                  }
              }
              return text2.ToUpper();
          }
      
      
          //Get the address of Pci from "Winscard.dll".
          private IntPtr GetPciT0()
          {
              IntPtr handle = LoadLibrary("Winscard.dll");
              IntPtr pci = GetProcAddress(handle, "g_rgSCardT0Pci");
              FreeLibrary(handle);
              return pci;
          }
      
          #endregion
      
      
      }// Fin de la Clase
      }
      

    PInvoke 文档帮助很大:https://www.pinvoke.net/default.aspx/winscard.scardtransmit

    【讨论】:

    • 在您编写的代码中:UID = ret_Bytes.Take(4).ToArray(); //只取前8个字节,后2个字节不属于卡的UID。 --> 现在你做了一个 take(4) 但注释它占用 8 个字节。现在哪一个是正确的? 8个还是4个?因为这正是我目前挣扎的地方,因为野外有 4 字节或 8 字节 UID 的 MF1k 卡,我需要动态处理。
    • 是的,这是一个错字,你只需要 4 个字节,你的 UID 应该是这样的:FF.FF.FF.FF 不仅适用于 MF1k,而且适用于几乎所有这些。如果您发现我的代码有用,请点赞,谢谢。
    • 其实这不正确。根据 NXP,您将需要 4、7 或 10 个字节。请看这里(直接在第一页):nxp.com/docs/en/application-note/AN10927.pdf
    • 嗯,在 MF1k 的情况下,您只需要前 4 个字节,这就是您问题的答案,我的代码就是这样做的。
    • 谢谢!!!!这非常有效,我不明白为什么你在 1 年内没有任何支持!
    猜你喜欢
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 2013-07-10
    • 2012-12-25
    • 2015-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多