我有一台NFC读卡器和MIFARE Classic 1K卡片。我有一个Visual C# winforms项目。现在,我能够连接到读卡器并检测到卡片并获取其UUID。我遇到的问题是在写入和读取数据时。我在互联网上搜索了很多,并找到了一些解决方案,甚至测试了SDK提供的演示代码...但都没有起作用。
让我描述一下我用于写入、认证块、发送APDU和读取块的工作流程和代码。
以下是写入数据到块5的代码。
函数SendAPDUandDisplay的代码如下:
函数authenticateBlock的代码如下所示。
One strange thing to notice here is that no matter what values are set in sendBuff, this function always returns a true value and the "write data" code block (the very first code block) returns a message of "write success". However, after executing the "write data" code, when attempting to read block 5 (in my case), there is no data present. The "read block" code block returns an empty string. To double-check whether the data was written but my code was unable to read it, I used external software to verify the added value. However, even the external software did not show the data that was supposedly successfully written.
The following is the code used to read block 5:
请注意,read block方法在检查是否连接读卡器后调用,如果是,则调用readblock方法并返回一个空字符串。
我尝试了几个值,如您在注释中看到的,但没有任何帮助,已经困扰了我三天。
请问有人能帮我找出问题所在,并指导我应该发送什么值以验证块?
如果有人了解我的代码问题或想更正我在sendBuff[]中设置的值,请以C#代码形式引用它们,以便我可以完全实现您要求的解决方案。
非常感谢任何真诚的帮助。
让我描述一下我用于写入、认证块、发送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;
}
One strange thing to notice here is that no matter what values are set in sendBuff, this function always returns a true value and the "write data" code block (the very first code block) returns a message of "write success". However, after executing the "write data" code, when attempting to read block 5 (in my case), there is no data present. The "read block" code block returns an empty string. To double-check whether the data was written but my code was unable to read it, I used external software to verify the added value. However, even the external software did not show the data that was supposedly successfully written.
The following is the code used to read block 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方法并返回一个空字符串。
我尝试了几个值,如您在注释中看到的,但没有任何帮助,已经困扰了我三天。
请问有人能帮我找出问题所在,并指导我应该发送什么值以验证块?
如果有人了解我的代码问题或想更正我在sendBuff[]中设置的值,请以C#代码形式引用它们,以便我可以完全实现您要求的解决方案。
非常感谢任何真诚的帮助。