簡體   English   中英

NFC MIFARE Classic 1K 無法讀取或寫入

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM