![](/img/trans.png)
[英]How to write NDEF record across multiple blocks with MIFARE 1k classic?
[英]NFC MIFARE Classic 1K cannot read or write
我有一個 NFC 讀卡器和 MIFARE Classic 1K 卡。 我有一個 Visual C# winforms 項目。 現在我能夠連接到讀卡器並檢測卡並獲取它的 UUID。 我面臨的問題是在寫入和讀取數據時。 我在互聯網上搜索了很多,找到了一些解決方案,甚至測試了 SDK 提供的演示代碼......沒有任何工作。
讓我描述一下我用於編寫、驗證塊、發送 APDU 和讀取塊的工作流程和代碼。
以下是將數據寫入塊 5 的代碼。
String tmpStr = Text;
int indx;
if (authenticateBlock(Block))
{
ClearBuffers();
SendBuff[0] = 0xFF; // CLA
SendBuff[1] = 0xD6; // INS
SendBuff[2] = 0x00; // P1
SendBuff[3] = (byte)int.Parse(Block); // P2 : Starting Block No.
SendBuff[4] = (byte)int.Parse("16"); // P3 : Data length
SendBuff[5] = 0xFF;
SendBuff[6] = 0xFF;
SendBuff[7] = 0xFF;
SendBuff[8] = 0xFF;
SendBuff[9] = 0xFF;
SendBuff[10] = 0xFF;
for (indx = 0; indx <= (tmpStr).Length - 1; indx++)
{
SendBuff[indx + 5] = (byte)tmpStr[indx];
}
SendLen = SendBuff[4] + 5;
RecvLen = 0x02;
retCode = SendAPDUandDisplay(2);
if (retCode != Card.SCARD_S_SUCCESS)
{
MessageBox.Show("fail write");
}
else
{
MessageBox.Show("write success");
}
}
else
{
MessageBox.Show("FailAuthentication");
}
CloseCardConnection();
SendAPDUandDisplay 函數如下
private int SendAPDUandDisplay(int reqType)
{
int indx;
string tmpStr = "";
pioSendRequest.dwProtocol = Aprotocol;
pioSendRequest.cbPciLength = 8;
//Display Apdu In
for (indx = 0; indx <= SendLen - 1; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuff[indx]);
}
retCode = Card.SCardTransmit(hCard, ref pioSendRequest, ref SendBuff[0],
SendLen, ref pioSendRequest, ref RecvBuff[0], ref RecvLen);
if (retCode != Card.SCARD_S_SUCCESS)
{
return retCode;
}
else
{
try
{
tmpStr = "";
switch (reqType)
{
case 0:
for (indx = (RecvLen - 2); indx <= (RecvLen - 1); indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
if ((tmpStr).Trim() != "90 00")
{
//MessageBox.Show("Return bytes are not acceptable.");
return -202;
}
break;
case 1:
for (indx = (RecvLen - 2); indx <= (RecvLen - 1); indx++)
{
tmpStr = tmpStr + string.Format("{0:X2}", RecvBuff[indx]);
}
if (tmpStr.Trim() != "90 00")
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
else
{
tmpStr = "ATR : ";
for (indx = 0; indx <= (RecvLen - 3); indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
}
break;
case 2:
for (indx = 0; indx <= (RecvLen - 1); indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
break;
}
}
catch (IndexOutOfRangeException)
{
return -200;
}
}
return retCode;
}
功能 authenticateBlock 如下
private bool authenticateBlock(String block)
{
ClearBuffers();
/*SendBuff[0] = 0xFF; // CLA
SendBuff[2] = 0x00; // P1: same for all source types
SendBuff[1] = 0x82; // INS: for stored key input
SendBuff[3] = 0x00; // P2 : Memory location; P2: for stored key input
SendBuff[4] = 0x05; // P3: for stored key input
SendBuff[5] = 0x01; // Byte 1: version number
SendBuff[6] = 0x00; // Byte 2
SendBuff[7] = (byte)int.Parse(block); // Byte 3: sectore no. for stored key input
SendBuff[8] = 0x60; // Byte 4 : Key A for stored key input
SendBuff[9] = (byte)int.Parse("1"); // Byte 5 : Session key for non-volatile memory
*/
SendBuff[0] = 0xD4;
SendBuff[1] = 0x4A;
SendBuff[2] = 0x01;
SendBuff[3] = 0x00;
SendBuff[4] = (byte) int.Parse(block);
SendBuff[5] = 0xFF;
SendBuff[6] = 0xFF;
SendBuff[7] = 0xFF;
SendBuff[8] = 0xFF;
SendBuff[9] = 0xFF;
SendBuff[10] = 0xFF;
/*SendLen = 0x0A;
RecvLen = 0x02;*/
SendLen = 4;
RecvLen = 255;
retCode = SendAPDUandDisplay(2);
if (retCode != Card.SCARD_S_SUCCESS)
{
//MessageBox.Show("FAIL Authentication!");
return false;
}
return true;
}
這里要注意的一件奇怪的事情是,無論我在sendBuff中設置什么值,這個函數總是返回真值,並且寫入數據代碼“第一個代碼塊”返回寫入成功消息
但是,當我在我的情況下讀取那個塊“5”時執行寫入數據代碼之后,那里什么都沒有。 我的讀取塊代碼返回一個空字符串,當我嘗試仔細檢查數據是否已寫入並且我的錯誤代碼無法讀取時,我使用外部軟件來驗證是否添加了值,該軟件也不會顯示數據我寫的並得到了寫成功的消息。
好的,下面是我用來讀取塊 5 的代碼。
public string readBlock(String Block)
{
string tmpStr = "";
int indx;
if (authenticateBlock(Block))
{
ClearBuffers();
/*
SendBuff[0] = 0xFF; // CLA
SendBuff[1] = 0xB0;// INS
SendBuff[2] = 0x00;// P1
SendBuff[3] = (byte)int.Parse(Block);// P2 : Block No.
SendBuff[4] = (byte)int.Parse("16");// Le
*/
SendBuff[0] = 0xD4;
SendBuff[1] = 0x40;
SendBuff[2] = 0x01;
SendBuff[3] = 0x30;
SendBuff[4] = byte.Parse(Block.ToString(), System.Globalization.NumberStyles.HexNumber);
SendBuff[5] = 0xFF;
SendBuff[6] = 0xFF;
SendBuff[7] = 0xFF;
SendBuff[8] = 0xFF;
SendBuff[9] = 0xFF;
SendBuff[10] = 0xFF;
//SendLen = 5;
//RecvLen = SendBuff[4] + 2;
SendLen = 5;
RecvLen = 255;
retCode = SendAPDUandDisplay(2);
if (retCode == -200)
{
return "outofrangeexception";
}
if (retCode == -202)
{
return "BytesNotAcceptable";
}
if (retCode != Card.SCARD_S_SUCCESS)
{
return "FailRead";
}
// Display data in text format
for (indx = 0; indx <= RecvLen - 1; indx++)
{
tmpStr = tmpStr + Convert.ToChar(RecvBuff[indx]);
}
return (tmpStr);
}
else
{
return "FailAuthentication";
}
}
請注意,在檢查讀取器是否已連接后調用 readblock 方法,如果是這樣,那么我調用readblock方法並返回一個空字符串
正如您在評論中看到的那樣,我已經嘗試了幾個值,但似乎沒有任何幫助,已經 3 天了,我仍然被困在這里。
有人可以幫我弄清楚我在哪里做錯了,我應該發送什么值來驗證塊?
請幫我一個忙,如果有人知道我的代碼中的問題或想要更正我在sendBuff[]中設置的值,請在C# 代碼中引用它們,以便我可以使用您希望我實施的解決方案
任何真誠的幫助都將受到高度重視,在此先感謝。
我只用 Arduino 試驗了 mifare 1k。
在這種情況下,在檢測到卡並檢索 UUID 后,需要在讀/寫之前選擇卡。 你在做這個選擇卡片的步驟嗎?
由於它是 S50 1K Classic,因此“字節圖”是不同的,並且處理周期雖然表面上相同,但您需要在繼續獲取 ATR/ATS 並對其進行解析以檢索開關設置之前檢查其是否為 S50。 與接觸式ATR,非接觸式ATS在技術上卻是一回事。 在 PCSC 下,這是在詢問閱讀器是否存在卡時詢問 readerchangestate,在發送 APDU 之前完成。 您還可以同時獲取其他設置。 對於 MFS50,您需要使用扇區密鑰執行“S”選擇,然后執行“L”登錄,然后讀取 4 個塊中的前三個扇區,但忽略第一個扇區塊的大部分 - 密鑰與其他控件一起位於第四個塊中字節。 'UID' 在'S'elect 上返回,在'L'ogin 上成功或失敗,在讀取扇區中的塊時返回數據或'E'錯誤。 對於 14443 扇區 0,第一個塊被“制造”數據占用,這取決於構造可以有 4、7 或 12 個字節作為 UID,從數據的角度來看嵌入 CRC 和校驗字節,因此不能用作UID - 它是一個數據映射。 Lights、C、ultralights、EV1 有不同的“字節圖”,在卡或扇區可能有也可能沒有“L”字。 這些是 14443 類型,還有一個 15693 類型,其中只有扇區中的數據。 一些中文 14443 具有可寫的制造塊,但通常是靜態、設置和 OTP 的混合(一旦位設置無法取消設置,用於身份驗證和 NFC 驗證大小!)。
Classic 1K: ident UID: 66908648, requires sector key log in (A read, B
read/write)
Sector 0:
6690864838880400468f76594d100612
00000000000000000000000000000000
00000000000000000000000000000000
ffffffffffffff078069ffffffffffff
...
Sector 15:
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
ffffffffffffff0780bcffffffffffff
Mifare ultralight: UID 0489d802a44080, might require sector login but key held elsewhere.
Sector 0:
0489D8DD
02A44080
66480900
00010001
.
Sector 1:
00000000
00000000
00000000
000000EE
15693: UID D89A1F24500104E0
Sector 0:
50555955
Sector 1:
48485353
Sector 2:
59435300
Sector 3:
00000000
...
Sector 15:
00000000
所以,拿到 ATR/ATS 並計算出你有什么卡,然后相應地處理它。 哦,使用腰帶、大括號和一根繩子的方法 - 寫入卡后再次讀取它以比較寫入的內容與預期的內容。 15693 需要扇區完成寫入,否則該扇區中不會寫入任何內容。 那是類型 2 NFC/NDEF - 還有其他標准。 使用 Zebra 打印機對 NTAG201 的靶心進行實時編碼和打印。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.