3

我有一个 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# 代码中引用它们,以便我可以使用您希望我实现的解决方案

任何真诚的帮助都将受到高度重视,在此先感谢。

4

1 回答 1

0

我只用 Arduino 试验了 mifare 1k。

在这种情况下,在检测到卡并检索 UUID 后,需要在读/写之前选择卡。你在做这个选择卡片的步骤吗?

于 2020-01-21T14:01:57.577 回答