NF C MIFARE Classi c 1K не может читать или писать - PullRequest
2 голосов
/ 07 января 2020

У меня есть считыватель NF C вместе с картой MIFARE Classi c 1K. У меня есть проект Visual C# winforms. Прямо сейчас я могу подключиться к ридеру, определить карту и получить ее UUID. Проблема, с которой я сталкиваюсь, заключается в написании и чтении данных. Я много искал по inte rnet, нашел какое-то решение, даже протестировал демонстрационный код, поставляемый с 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 , эта функция всегда возвращает истинное значение, а код записи данных «Самый первый блок кода» возвращает запись success message

Но после выполнения кода записи данных, когда я читаю тот самый блок "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";
            }
        }

Обратите внимание, что метод read block вызывается после проверки, подключен ли считыватель, если это так, тогда я вызываю метод readblock , и он возвращает пустую строку

Я пробовал несколько значений, как вы могли видеть в комментариях, но, похоже, ничего не помогло, прошло 3 долгих дня, и я все еще застрял здесь.

Может кто-нибудь, пожалуйста помогите мне понять, где я делаю это неправильно и какие значения я должен отправить для аутентификации блока?

Пожалуйста, сделайте мне одолжение, если кто-то узнает о проблеме в моем коде или захочет исправить значения, которые я задаю в sendBuff [] , тогда, пожалуйста, укажите их в C# кода, чтобы я мог использовать именно то решение, которое вы хотите, чтобы я реализовал

Любая искренняя помощь будет высоко оценена, заранее спасибо.

1 Ответ

0 голосов
/ 21 января 2020

Я только экспериментировал с mifare 1k, используя Arduino.

В этом случае, после обнаружения карты и получения UUID, она должна выбрать карту перед чтением / записью. Вы делаете этот шаг выбора карты?

...