我有一个始终报告 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 设置为零?这是否包含在规范中?如果是的话,哪个规格?
什么也没有。 UID 的格式(MIFARE 卡使用的格式)在 ISO/IEC 14443-3 中定义。特别是对于 MIFARE 卡,NXP 有(或至少有?)一些针对 4 字节 UID 的进一步分配逻辑,但这不是公开可用的。
如果读者完全按照示例中所示的形式输出 UID,那么答案是“否”(至少不可靠)。然而,一些阅读器以 8 字节输出 UID,并包含 7 字节 UID 的级联标签。因此,对于这些读取器来说,所有 7 字节 UID 都以 0x88 开头。您的读者似乎并非如此。 有可能的策略来区分这两种情况吗?
了解如何获取列表)。因此,如果您的制造商有限(例如,如果您仅使用带有 NXP 芯片的 MIFARE 卡),您可以将以 NXP 制造商代码 (0x04) 开头的所有 UID 解释为 7 字节 UID。不过,您应该注意4 字节 UID 也允许以 0x04 开头。因此,此方法不是 100% 可靠,在某些情况下可能会失败。
br
的附件 6 中。 万一该页面出现故障,下面将给出该页面的无耻抄袭。 如果您在下面的代码片段中发现任何和所有错误,那么这些错误都属于恩智浦人员,而不是我。
但是你怎么知道标签是 4 字节还是 7 字节 uid 呢?来自 ATQA 回复。请参阅文件
1第15/36页和文件2第8/15页。 如果文档失败,这里是文档的相关摘录
1MF1S50yyX/V1 使用 ATQA 值应答 REQA 或 WUPA 命令 如表 11 所示,并连接至 Select CL1 命令(7 字节 UID 变体的 CL2),SAK 值如表 12 所示。6。附件,从双倍大小 UID 中导出 NUID 的源代码备注:第 7 位和第 8 位中的 ATQA 编码根据 ISO/IEC 14443 指示 UID 大小,与 UID 用途的设置无关。
#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);
}
(这是 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的第一个四个字节,而今天它已经不正确了。