Mifare卡:区分4字节和7字节UID

时间:2016-06-15 14:02:48

标签: uniqueidentifier rfid mifare smartcard-reader contactless-smartcard

我有一个总是报告64位的读卡器,可以读取4或7字节UID的卡。

作为一个例子,我看到它可以报告:

  • 04-18-c5-82-00-00-00-00 - uid0-uid1-uid2-uid3-00-00-00-00
  • 形式的4字节UID
  • 04-18-c5-82-f1-3b-81-00 - uid0-uid1-uid2-uid3-uid4-uid5-uid6-00
  • 形式的7字节UID

什么阻止7字节的UID将uid4,uid5和uid6设置为零?这是否包含在规范中?如果是这样,哪个规格?

4 个答案:

答案 0 :(得分:1)

什么阻止7字节UID将uid4,uid5和uid6设置为零?

无。 UID的格式(由MIFARE卡使用)在ISO / IEC 14443-3中定义。特别是对于MIFARE卡,恩智浦已经(或者至少有)一些4字节UID的进一步分配逻辑,但这不是公开的。

是否可以区分这两种情况?

如果阅读器完全以您在示例中显示的形式输出UID,则答案是(至少不可靠)。但是,有些读者会输出8字节的UID,并包含7字节UID的级联标记。因此,对于那些读者来说,所有7字节UID都以0x88开头。您的读者似乎并非如此。

是否有可能的策略来区分这两种情况?

我想到了一些策略来区分4字节UID和7字节UID。

  1. 7字节UID的第一个字节是制造商代码(在ISO / IEC 7816-6中定义(有关如何获取列表,请参阅How to detect manufacturer from NFC tag using Android?。)因此,如果您有一组有限的制造商(例如,如果您只使用带有恩智浦芯片的MIFARE卡),您可以将所有以NXP制造商代码(0x04)开头的UID解释为7字节UID。但是,您应该知道4字节-UID也允许以0x04开头。因此,这种方法不是100%可靠,在某些情况下可能会失败。

  2. 4字节UID的第一个字节不得包含以下任何值:'x8'(带x!='0'),'xF'。如果找到匹配任何这些值的第一个字节,则可以假设UID由7个字节组成。

答案 1 :(得分:0)

如果您能获得ATQA响应,您可以区分它。 ATQA的低字节显示UID的长度。 (4/7 / 10Byte)据我所知,没有其他方法可以区分100%保证

BR

答案 2 :(得分:0)

我知道晚会晚了一点,但是对于任何一个有同样疑问的人来说; 在pdf的附件6中,从4字节UID中创建7字节UID的记录方法。

如果页面出现故障,下面将对该页面进行无耻的剥夺。 如果您在下面的代码片段中正确找到了所有错误,则归恩智浦所有,而不是我。

但是您怎么知道标签是4字节还是7字节uid?

来自ATQA响应。请参阅文档1的第15/36页和文档2的第8/15页。

如果文档出现故障,这是文档1的相关摘录。

  

MF1S50yyX / V1用ATQA值回答REQA或WUPA命令   表11所示,并发送到Select CL1命令(7字节UID变体为CL2),其SAK值如表12所示。

     

注释:第7位和第8位中的ATQA编码根据ISO / IEC 14443指示UID大小,而与UID使用情况的设置无关。

6。附件,从Double Size UID派生NUID的源代码

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>
#define BYTE unsigned char
unsigned short UpdateCrc(unsigned char ch, unsigned short *lpwCrc)
{
ch = (ch^(unsigned char)((*lpwCrc) & 0x00FF));
ch = (ch^(ch<<4));
*lpwCrc = (*lpwCrc >> 8)^((unsigned short)ch << 8)^((unsigned
short)ch<<3)^((unsigned short)ch>>4);
return(*lpwCrc);
}
void ComputeCrc(unsigned short wCrcPreset, unsigned char *Data, int
Length, unsigned short &usCRC)
{
unsigned char chBlock;
do {
chBlock = *Data++;
UpdateCrc(chBlock, &wCrcPreset);
} while (--Length);
usCRC = wCrcPreset;
return;
}
void Convert7ByteUIDTo4ByteNUID(unsigned char *uc7ByteUID, unsigned char
*uc4ByteUID)
{
unsigned short CRCPreset = 0x6363;
unsigned short CRCCalculated = 0x0000;
ComputeCrc(CRCPreset, uc7ByteUID, 3,CRCCalculated);
uc4ByteUID[0] = (CRCCalculated >>8)&0xFF;//MSB
uc4ByteUID[1] = CRCCalculated &0xFF; //LSB
CRCPreset = CRCCalculated;
ComputeCrc(CRCPreset, uc7ByteUID+3, 4,CRCCalculated);
uc4ByteUID[2] = (CRCCalculated >>8)&0xFF;//MSB
uc4ByteUID[3] = CRCCalculated &0xFF; //LSB
uc4ByteUID[0] = uc4ByteUID[0]|0x0F;
uc4ByteUID[0] = uc4ByteUID[0]& 0xEF;
}
int main(void)
{
 int i;
 unsigned char uc7ByteUID[7] =
{0x04,0x18,0x3F,0x09,0x32,0x1B,0x85};//4F505D7D

 unsigned char uc4ByteUID[4] = {0x00};

 Convert7ByteUIDTo4ByteNUID(uc7ByteUID,uc4ByteUID);
 printf("7-byte UID = ");
 for(i = 0;i<7;i++)
 printf("%02X",uc7ByteUID[i]);
 printf("\t4-byte FNUID = ");
 for(i = 0;i<4;i++)
 printf("%02X",uc4ByteUID[i]);
 getch();
return(0);
}

答案 3 :(得分:0)

如果您是来这里(像我一样)找到一种适当的方法来自动从卡中独立获取UID(如果它是4、7或10字节的UID),那么我将按照以下方式动态进行操作(在互联网,但找不到合适的信用额。(未测试的10字节):

(这是C#代码,在后台使用winscard.dll):

public static UInt64 getCardUIDasUInt64()     // *** only for mifare 1k cards ***
    {
        UInt64 UID = 0;
        byte[] receivedUID = new byte[10];  // *** 
        Card.SCARD_IO_REQUEST request = new Card.SCARD_IO_REQUEST();
        request.dwProtocol = (UInt32)Protocol;  // *** use the detected protocol instead of statically assigned protocol type *** // Card.SCARD_PROTOCOL_T1;
        request.cbPciLength = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(Card.SCARD_IO_REQUEST));

        byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; //get UID command      for Mifare cards
        //byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x04 }; //get UID command      for Mifare cards

        int receivedBytesLength = receivedUID.Length;
        int status = Card.SCardTransmit(hCard, ref request, ref sendBytes[0], sendBytes.Length, ref request, ref receivedUID[0], ref receivedBytesLength);

        if (status == Card.SCARD_S_SUCCESS)
        {
            if (receivedBytesLength >= 2)
            {
                // do we have an error
                if ((receivedUID[receivedBytesLength - 2] != 0x90) ||
                    (receivedUID[receivedBytesLength - 1] != 0x00))
                {
                    throw new Exception(receivedUID[receivedBytesLength - 2].ToString());
                }
                else if (receivedBytesLength > 2)
                {

                    for (UInt32 i = 0; i != receivedBytesLength - 2; i++)
                    {
                        UID <<= 8;
                        UID |= (UInt64)(receivedUID[i]);
                    };

                }

            }
            else
            {
                throw new Exception(ResourceHandling.getTextResource("Error_Card_Read"));
            }

        }

        return UID;
    }

如果您需要十六进制的UID,请使用此代码(除了上面的代码):

 public static string getCardUIDasHex()      // *** only for mifare 1k cards ***
 {
    UInt64 cardUID = getCardUIDasUInt64();
    return string.Format("{0:X}", cardUID);               
 }

也许这对其他人也有帮助,因为在互联网中(也在SO中),有很多地方只读取UID的第1个第4个字节,而今天这已经不正确了。