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

问题描述 投票:0回答:4

我有一个始终报告 64 位的读卡器,并且可以读取具有 4 或 7 字节 UID 的卡。

举个例子,我看到它可以报告:

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

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

uniqueidentifier rfid mifare smartcard-reader contactless-smartcard
4个回答
3
投票

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

什么也没有。 UID 的格式(MIFARE 卡使用的格式)在 ISO/IEC 14443-3 中定义。特别是对于 MIFARE 卡,NXP 有(或至少有?)一些针对 4 字节 UID 的进一步分配逻辑,但这不是公开可用的。

这两种情况可以区分吗?

如果读者完全按照示例中所示的形式输出 UID,那么答案是“否”(至少不可靠)。然而,一些阅读器以 8 字节输出 UID,并包含 7 字节 UID 的级联标签。因此,对于这些读取器来说,所有 7 字节 UID 都以 0x88 开头。您的读者似乎并非如此。 有可能的策略来区分这两种情况吗?

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

    7 字节 UID 的第一个字节是制造商代码(如 ISO/IEC 7816-6 中定义(请参阅
  1. 如何使用 Android 从 NFC 标签检测制造商?

    了解如何获取列表)。因此,如果您的制造商有限(例如,如果您仅使用带有 NXP 芯片的 MIFARE 卡),您可以将以 NXP 制造商代码 (0x04) 开头的所有 UID 解释为 7 字节 UID。不过,您应该注意4 字节 UID 也允许以 0x04 开头。因此,此方法不是 100% 可靠,在某些情况下可能会失败。

  2. 4 字节 UID 的第一个字节不得包含以下任何值:“x8”(其中 x!=“0”)、“xF”。如果您发现第一个字节与这些值中的任何一个相匹配,则可以假设 UID 由 7 个字节组成。

0
投票

br


0
投票
pdf

的附件 6 中。 万一该页面出现故障,下面将给出该页面的无耻抄袭。 如果您在下面的代码片段中发现任何和所有错误,那么这些错误都属于恩智浦人员,而不是我。

但是你怎么知道标签是 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。附件,从双倍大小 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); }



0
投票

(这是 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的第一个四个字节,而今天它已经不正确了。

© www.soinside.com 2019 - 2024. All rights reserved.