因为项目需要,第一次接触到了ACR122U NFC读卡器(非接触式)和M1卡,首先介绍一下想要读写应该知道的基本知识。

我就根据我的理解先叙述一下:

ACR122U 是一款连机非接触式智能卡读写器,可以读写 ISO 14443-4 A 类和 B 类卡、MIFARE®卡、
ISO18092 卡以及 FeliCa 标签。由于符合 PC/SC 标准,它可以与现有的 PC/SC 应用相兼容。
作为非接触式标签与个人电脑的中间设备,ACR122U 通过 USB 端口与电脑建立连接并执行电脑发出
的指令,从而实现与非接触式标签的通信或者对外围设备(LED 指示灯或蜂鸣器)进行控制。

具体M1卡的介绍,推荐链接:https://blog.csdn.net/woniu3/article/details/51324483

M1卡里面有16(0-15)个扇区,每个扇区包含4个块,0扇区是0-3区块,1扇区是4-7区块,,,以此类推,15扇区就是60-63。

(1)其中0扇区里的0区块存储的是厂商代码,已经固化,不可更改。

(2)每个扇区的块0(除0扇区外)、块1、块2 为数据块,可用于存贮数据。数据块可作两种应用: 
用作一般的数据保存,可以进行读、写操作。 
用作数据值,可以进行初始化值、加值、减值、读值操作。

(3)每个扇区的块3 为控制块,包括了密码A、存取控制、密码B。

这个图是用破解工具读取出来的M1卡的数据。存储的是16进制的数据。

这是我做的页面

这是窗体的代码

 using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms; namespace WindowsFormsApplication1
{
public partial class NFCCardForm : Form
{
public NFCCardForm()
{
InitializeComponent();
} #region 全局变量声明
public int retCode, hContext, hCard, Protocol, ReaderCount, nBytesRet, blockCount, blockNum, ShanQuNum, yuShu;
public bool connActive = false;
public byte[] SendBuff = new byte[];//最多可以放752个
public byte[] RecvBuff = new byte[];
public byte[] SendBuffAll = new byte[];//全部
public byte[] RecvBuffAll = new byte[];
public byte[] bytes = new byte[];
public int SendLen, RecvLen, ReaderLen, ATRLen, dwState, dwActProtocol;
public int reqType, Aprotocol, dwProtocol, cbPciLength;
public ModWinsCard.SCARD_IO_REQUEST pioSendRequest;
string readStr = "";
public static string writeStr = "";
bool isReadAll = false;
#endregion #region 窗体事件
private void Form1_Load(object sender, EventArgs e)
{
InitMenu();
} /// <summary>
/// 读卡器初始化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void bInit_Click(object sender, EventArgs e)
{
string ReaderList = "" + Convert.ToChar();
int indx;
int pcchReaders = ;
string rName = ""; //Establish Context
retCode = ModWinsCard.SCardEstablishContext(ModWinsCard.SCARD_SCOPE_USER, , , ref hContext); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
displayOut(, retCode, "");
return;
} // 2. List PC/SC card readers installed in the system retCode = ModWinsCard.SCardListReaders(this.hContext, null, null, ref pcchReaders); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
displayOut(, retCode, "");
return;
}
EnableButtons();
byte[] ReadersList = new byte[pcchReaders];
// Fill reader list
retCode = ModWinsCard.SCardListReaders(this.hContext, null, ReadersList, ref pcchReaders);
if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
mMsg.AppendText("SCardListReaders Error: " + ModWinsCard.GetScardErrMsg(retCode));
return;
}
else
{
displayOut(, , " ");
} rName = "";
indx = ; //Convert reader buffer to string
while (ReadersList[indx] != )
{
while (ReadersList[indx] != )
{
rName = rName + (char)ReadersList[indx];
indx = indx + ;
}
//Add reader name to list
cbReader.Items.Add(rName);
rName = "";
indx = indx + ;
} if (cbReader.Items.Count > )
{
cbReader.SelectedIndex = ;
}
} private void bConnect_Click(object sender, EventArgs e)
{
retCode = ModWinsCard.SCardConnect(hContext, cbReader.SelectedItem.ToString(), ModWinsCard.SCARD_SHARE_SHARED,
ModWinsCard.SCARD_PROTOCOL_T1, ref hCard, ref Protocol); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
retCode = ModWinsCard.SCardConnect(hContext, cbReader.SelectedItem.ToString(), ModWinsCard.SCARD_SHARE_DIRECT,
, ref hCard, ref Protocol);
if (retCode != ModWinsCard.SCARD_S_SUCCESS)
displayOut(, retCode, "");
else
{
displayOut(, , "成功连接到" + cbReader.Text);//Successful connection to
}
}
else
{
displayOut(, , "成功连接到" + cbReader.Text);
}
GetUID();
connActive = true;
gbLoadKeys.Enabled = true;
gbAuth.Enabled = true;
gbBinOps.Enabled = true;
groupBox1.Enabled = true;
tKeyNum.Focus();
rbKType1.Checked = true;
btnClear.Enabled = true;
btnRead.Enabled = true;
btnWrite.Enabled = true;
} private void bClear_Click(object sender, EventArgs e)
{
mMsg.Clear();
} private void bReset_Click(object sender, EventArgs e)
{
if (connActive)
{
retCode = ModWinsCard.SCardDisconnect(hCard, ModWinsCard.SCARD_UNPOWER_CARD);
} retCode = ModWinsCard.SCardReleaseContext(hCard);
InitMenu();
} private void bQuit_Click(object sender, EventArgs e)
{
// terminate the application
retCode = ModWinsCard.SCardReleaseContext(hContext);
retCode = ModWinsCard.SCardDisconnect(hCard, ModWinsCard.SCARD_UNPOWER_CARD);
System.Environment.Exit();
} private void bLoadKey_Click(object sender, EventArgs e)
{
byte tmpLong;
string tmpStr; if (tKey1.Text == "" | !byte.TryParse(tKey1.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
{
tKey1.Focus();
tKey1.Text = "";
return;
} if (tKey2.Text == "" | !byte.TryParse(tKey2.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
{
tKey2.Focus();
tKey2.Text = "";
return;
} if (tKey3.Text == "" | !byte.TryParse(tKey3.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
{
tKey3.Focus();
tKey3.Text = "";
return;
} if (tKey4.Text == "" | !byte.TryParse(tKey4.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
{
tKey4.Focus();
tKey4.Text = "";
return;
} if (tKey5.Text == "" | !byte.TryParse(tKey5.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
{
tKey5.Focus();
tKey5.Text = "";
return;
} if (tKey6.Text == "" | !byte.TryParse(tKey6.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
{
tKey6.Focus();
tKey6.Text = "";
return;
} ClearBuffers();
// Load Authentication Keys command
SendBuff[] = 0xFF; // Class
SendBuff[] = 0x82; // INS
SendBuff[] = 0x00; // P1 : Key Structure
SendBuff[] = byte.Parse(tKeyNum.Text, System.Globalization.NumberStyles.HexNumber);
SendBuff[] = 0x06; // P3 : Lc
SendBuff[] = byte.Parse(tKey1.Text, System.Globalization.NumberStyles.HexNumber); // Key 1 value
SendBuff[] = byte.Parse(tKey2.Text, System.Globalization.NumberStyles.HexNumber); // Key 2 value
SendBuff[] = byte.Parse(tKey3.Text, System.Globalization.NumberStyles.HexNumber); // Key 3 value
SendBuff[] = byte.Parse(tKey4.Text, System.Globalization.NumberStyles.HexNumber); // Key 4 value
SendBuff[] = byte.Parse(tKey5.Text, System.Globalization.NumberStyles.HexNumber); // Key 5 value
SendBuff[] = byte.Parse(tKey6.Text, System.Globalization.NumberStyles.HexNumber); // Key 6 value SendLen = ;
RecvLen = ; retCode = SendAPDU(, false, ); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return;
}
else
{
tmpStr = "";
for (int indx = RecvLen - ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
}
if (tmpStr.Trim() != "90 00")
{
displayOut(, , "载入密钥失败!");//Load authentication keys error
}
} private void btnAuth_Click(object sender, EventArgs e)
{
int tempInt, indx;
byte tmpLong;
string tmpStr; // Validate input
if (tBlkNo.Text == "" | !int.TryParse(tBlkNo.Text, out tempInt))
{
tBlkNo.Focus();
tBlkNo.Text = "";
return;
} if (int.Parse(tBlkNo.Text) > )
{
tBlkNo.Text = "";
} if (tAuthenKeyNum.Text == "" | !byte.TryParse(tAuthenKeyNum.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
{
tAuthenKeyNum.Focus();
tAuthenKeyNum.Text = "";
return;
}
else if (int.Parse(tAuthenKeyNum.Text) > )
{
tAuthenKeyNum.Text = "";
return;
} ClearBuffers(); SendBuff[] = 0xFF; // Class
SendBuff[] = 0x86; // INS
SendBuff[] = 0x00; // P1
SendBuff[] = 0x00; // P2
SendBuff[] = 0x05; // Lc
SendBuff[] = 0x01; // Byte 1 : Version number
SendBuff[] = 0x00; // Byte 2
SendBuff[] = (byte)int.Parse(tBlkNo.Text); // Byte 3 : Block number if (rbKType1.Checked == true)
{
SendBuff[] = 0x60;
}
else if (rbKType2.Checked == true)
{
SendBuff[] = 0x61;
} SendBuff[] = byte.Parse(tAuthenKeyNum.Text, System.Globalization.NumberStyles.HexNumber); // Key 5 value SendLen = ;
RecvLen = ; retCode = SendAPDU(, false, ); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return;
}
else
{
tmpStr = "";
for (indx = ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
}
if (tmpStr.Trim() == "90 00")
{
displayOut(, , "验证成功!");//Authentication success
}
else
{
displayOut(, , "验证失败!");//Authentication failed
}
} private void bBinRead_Click(object sender, EventArgs e)
{
string tmpStr;
int indx; // Validate Inputs
tBinData.Text = ""; if (tBinBlk.Text == "")
{
tBinBlk.Focus();
return;
} if (int.Parse(tBinBlk.Text) > )
{
tBinBlk.Text = "";
return;
} if (tBinLen.Text == "")
{
tBinLen.Focus();
return;
} ClearBuffers();
SendBuff[] = 0xFF;
SendBuff[] = 0xB0;
SendBuff[] = 0x00;
SendBuff[] = (byte)int.Parse(tBinBlk.Text);
SendBuff[] = (byte)int.Parse(tBinLen.Text); SendLen = ;
RecvLen = SendBuff[] + ; retCode = SendAPDU(, false, ); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return;
}
else
{
tmpStr = "";
for (indx = RecvLen - ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
}
if (tmpStr.Trim() == "90 00")
{
tmpStr = "";
tmpStr = System.Text.Encoding.Default.GetString(RecvBuff);
byte[] c = new byte[];
if (tmpStr.Contains('?'))
{
if (IsBase64String(tmpStr.Split('?')[]))
{
c = Convert.FromBase64String(tmpStr.Split('?')[]);
tmpStr = System.Text.Encoding.Default.GetString(c);
}
}
else
{
if (IsBase64String(tmpStr))
{
c = Convert.FromBase64String(tmpStr);
tmpStr = System.Text.Encoding.Default.GetString(c);
}
}
tBinData.Text = tmpStr;
displayOut(, , tmpStr);
}
else
{
displayOut(, , "读取块失败!");//Read block error
}
} private void bBinUpd_Click(object sender, EventArgs e)
{
string tmpStr;
int indx, tempInt; if (tBinBlk.Text == "" | !int.TryParse(tBinBlk.Text, out tempInt))
{
tBinBlk.Focus();
tBinBlk.Text = "";
return;
} if (int.Parse(tBinBlk.Text) > )
{
tBinBlk.Text = "";
return;
} if (tBinLen.Text == "" | !int.TryParse(tBinLen.Text, out tempInt))
{
tBinLen.Focus();
tBinLen.Text = "";
return;
} if (tBinData.Text == "")
{
tBinData.Focus();
return;
} tmpStr = tBinData.Text;
byte[] b = System.Text.Encoding.Default.GetBytes(tmpStr);
//转成 Base64 形式的 System.String
tmpStr = Convert.ToBase64String(b);
//将base64转成字符数组然后写入卡中
bytes = System.Text.Encoding.Default.GetBytes(tmpStr);
if (bytes.Length > )
{
MessageBox.Show("写入的数据长度超过16,请重新输入");
return;
}
ClearBuffers();
SendBuff[] = 0xFF; // CLA
SendBuff[] = 0xD6; // INS
SendBuff[] = 0x00; // P1
SendBuff[] = (byte)int.Parse(tBinBlk.Text); // P2 : Starting Block No.
SendBuff[] = (byte)bytes.Length; //(byte)int.Parse(tBinLen.Text); // P3 : Data length for (indx = ; indx <= bytes.Length - ; indx++)
{
SendBuff[indx + ] = bytes[indx];
}
SendLen = SendBuff[] + ;//
RecvLen = 0x02; retCode = SendAPDU(, false, ); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return;
}
else
{
tmpStr = "";
for (indx = ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
}
if (tmpStr.Trim() == "90 00")
{
tBinData.Text = "";
}
else
{
displayOut(, , tmpStr.Trim());//""
}
} private void btnRead_Click(object sender, EventArgs e)
{
string readData = readStr;
AuthAllBootSector();
if (readStr == null)
return; if (IsBase64String(readStr.Split('?')[]))
{
byte[] c = Convert.FromBase64String(readStr);
readData = System.Text.Encoding.Default.GetString(c);
if (readData.Contains("结"))
readData = readData.Substring(, readData.IndexOf("结"));
}
readStr = null;
displayOut(, , readData); } private void btnWrite_Click(object sender, EventArgs e)
{
AuthAllBootSector();
blockCount = ;
} /// <summary>
/// 当文本框里的值发生改变时,动态显示出写入数据的长度
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tBinData_TextChanged(object sender, EventArgs e)
{
string tmpStr = tBinData.Text;
byte[] b = System.Text.Encoding.Default.GetBytes(tmpStr);
//转成 Base64 形式的 System.String
tmpStr = Convert.ToBase64String(b);
//将base64转成字节数组然后写入卡中
bytes = System.Text.Encoding.Default.GetBytes(tmpStr);
lblWriteLength.Text = bytes.Length.ToString();
} /// <summary>
/// 在写入新的内容时,先将卡里的原数据清空
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClear_Click(object sender, EventArgs e)
{
int result;
for (int index = ; index <= ; index += )//验证
{
ClearBuffers();
SendBuff[] = 0xFF; // Class
SendBuff[] = 0x86; // INS
SendBuff[] = 0x00; // P1
SendBuff[] = 0x00; // P2
SendBuff[] = 0x05; // Lc
SendBuff[] = 0x01; // Byte 1 : Version number
SendBuff[] = 0x00; // Byte 2
SendBuff[] = (byte)index;//区块 // Byte 3 : Block number result = PartAuthBlock(, index);
if (result == )
break;
}
}
#endregion #region 自定义方法
private void InitMenu()
{
connActive = false;
cbReader.Text = "";
cbReader.Items.Clear();
mMsg.Text = "";
tKeyNum.SelectedIndex = ;
tAuthenKeyNum.SelectedIndex = ;
bInit.Enabled = true;
bConnect.Enabled = false;
bClear.Enabled = false;
displayOut(, , "程序准备就绪");//Program ready
bReset.Enabled = false;
gbLoadKeys.Enabled = false;
gbAuth.Enabled = false;
gbBinOps.Enabled = false;
groupBox1.Enabled = false;
btnClear.Enabled = false;
btnRead.Enabled = false;
btnWrite.Enabled = false;
} private void displayOut(int errType, int retVal, string PrintText)
{
switch (errType)
{
case :
mMsg.SelectionColor = Color.Green;
break;
case :
mMsg.SelectionColor = Color.Red;
PrintText = ModWinsCard.GetScardErrMsg(retVal);
break;
case :
mMsg.SelectionColor = Color.Black;
PrintText = "<" + PrintText;
break;
case :
mMsg.SelectionColor = Color.Black;
PrintText = ">" + PrintText;
break;
case :
break;
}
mMsg.AppendText(PrintText);
mMsg.AppendText("\n");
mMsg.SelectionColor = Color.Black;
mMsg.Focus();
} private void EnableButtons()
{
bInit.Enabled = false;
bConnect.Enabled = true;
bClear.Enabled = true;
bReset.Enabled = true;
} private void ClearBuffers()
{
long indx; for (indx = ; indx <= ; indx++)
{
RecvBuff[indx] = ;
SendBuff[indx] = ;
RecvBuffAll[indx] = ;
SendBuffAll[indx] = ;
}
} //private static byte[] StringToByteSequence(string sourceString)
//{
// int i = 0, n = 0;
// int j = (sourceString.Length) / 2; // byte[] a = new byte[j];
// for (i = 0, n = 0; n < j; i += 2, n++)
// {
// a[n] = Convert.ToByte(sourceString.Substring(i, 2), 16);
// }
// return a;
//} /// <summary>
///
/// </summary>
/// <param name="handleFlag">是否是更新操作</param>
/// <param name="isReadOrWriteAll">是不是全部读取或写入</param>
/// <returns></returns>
public int SendAPDU(int handleFlag, bool isReadOrWriteAll, int dataLength)
{
int indx;
string tmpStr; pioSendRequest.dwProtocol = Aprotocol;
pioSendRequest.cbPciLength = ; // Display Apdu In
tmpStr = "";
if (handleFlag == )//更新
{
if (isReadOrWriteAll)
{
for (indx = ; indx <= ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuffAll[indx]);//更新的APDU命令
}
for (int i = ; i <= SendLen - ; i++)
{
SendBuffAll[i + ] = bytes[i + dataLength];
}
SendLen = ;
}
else
{
for (indx = ; indx <= ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuff[indx]);//更新的APDU命令
}
for (int i = ; i <= SendLen - ; i++)
{
SendBuff[i + ] = bytes[i];
}
}
}
else if (handleFlag == )//读取
{
if (isReadOrWriteAll)//全部
{
for (indx = ; indx <= SendLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuffAll[indx]);
}
}
else
{
for (indx = ; indx <= SendLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuff[indx]);
}
}
}
else if (handleFlag == )//清空
{
for (indx = ; indx <= ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuffAll[indx]);//更新的APDU命令
}
for (int i = ; i <= SendLen - ; i++)
{
SendBuffAll[i + ] = 0x00;
}
} displayOut(, , tmpStr);
if (!isReadOrWriteAll)
retCode = ModWinsCard.SCardTransmit(hCard, ref pioSendRequest, ref SendBuff[], SendLen, ref pioSendRequest, ref RecvBuff[], ref RecvLen);
else
retCode = ModWinsCard.SCardTransmit(hCard, ref pioSendRequest, ref SendBuffAll[], SendLen, ref pioSendRequest, ref RecvBuffAll[], ref RecvLen); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
displayOut(, retCode, "");
return retCode;
} tmpStr = "";
if (isReadOrWriteAll)
{
for (indx = ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuffAll[indx]);
}
}
else
{
for (indx = ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
}
displayOut(, , tmpStr);
return retCode;
} #region GetUID()
/// <summary>
/// 获取UID
/// </summary>
private void GetUID()
{
// Get the firmaware version of the reader
string tmpStr;
int intIndx;
ClearBuffers(); #region GetFirmware APDU
//SendBuff[0] = 0xFF;
//SendBuff[1] = 0x00;
//SendBuff[2] = 0x48;
//SendBuff[3] = 0x00;
//SendBuff[4] = 0x00;
//SendLen = 5;
//RecvLen = 10;
#endregion SendBuff[] = 0xFF;
SendBuff[] = 0xCA;
SendBuff[] = 0x00;
SendBuff[] = 0x00;
SendBuff[] = 0x00;
SendLen = ;
RecvLen = ;
retCode = SendAPDU(, false, );
if (retCode != ModWinsCard.SCARD_S_SUCCESS)
return; // Interpret firmware data
//tmpStr = "Firmware Version(版本): ";
tmpStr = "UID: ";
for (intIndx = ; intIndx <= RecvLen - ; intIndx++)
{
tmpStr = tmpStr + string.Format("{0:X2}", RecvBuff[intIndx]);
}
displayOut(, , tmpStr);
}
#endregion /// <summary>
/// 验证所有区块
/// </summary>
/// <param name="handleFlag">处理操作的标志handleFlag 0清空,1读取,2写入</param>
private void AuthAllBootSector(int handleFlag)
{
int result; if (handleFlag == )
{
string data = writeStr;//获取要写入的字符串
byte[] b = System.Text.Encoding.Default.GetBytes(data);
//转成 Base64 形式的 System.String
data = Convert.ToBase64String(b);
bytes = System.Text.Encoding.Default.GetBytes(data);
if (bytes.Length % != )
{
b = null;
string endSign = "结结结结结结结";
//for (int i = 0; i < (bytes.Length % 16); i++)
//{
//endSign = "结结结结结结结"; //写入的数据不够填充满16位,最后的base64容易混乱,所以加个汉字,填满16位
//}
string str = writeStr + endSign;
b = System.Text.Encoding.Default.GetBytes(str);
data = "";
data = Convert.ToBase64String(b);
} //将base64转成16进制然后写入卡中
bytes = System.Text.Encoding.Default.GetBytes(data);
//写入的数据需要的区块数量
blockNum = (bytes.Length % == ? (bytes.Length / ) : (bytes.Length / + ));
//需要验证的扇区的数量,把有两个数据块的0扇区加上
ShanQuNum = (blockNum - ) % == ? (blockNum - ) / + : (blockNum - ) / + ;
//获取最后一个扇区的写入的块的数量,yushu==0,则正好写满当前验证块(3块数据块);
//yushu==1,则写入当前验证块;yushu==2,则写入当前验证块+1
yuShu = (blockNum - ) % ;
for (int i = ; i < * ShanQuNum; i += ) //验证 块
{
ClearBuffers();
SendBuff[] = 0xFF; // Class
SendBuff[] = 0x86; // INS
SendBuff[] = 0x00; // P1
SendBuff[] = 0x00; // P2
SendBuff[] = 0x05; // Lc
SendBuff[] = 0x01; // Byte 1 : Version number
SendBuff[] = 0x00; // Byte 2
SendBuff[] = (byte)i; // Byte 3 : Block number result = PartAuthBlock(handleFlag, i);
if (result == )
break;
}
}
else if (handleFlag == )
{
for (int index = ; index <= ; index += )//验证
{
ClearBuffers();
SendBuff[] = 0xFF; // Class
SendBuff[] = 0x86; // INS
SendBuff[] = 0x00; // P1
SendBuff[] = 0x00; // P2
SendBuff[] = 0x05; // Lc
SendBuff[] = 0x01; // Byte 1 : Version number
SendBuff[] = 0x00; // Byte 2
SendBuff[] = (byte)index;//块 // Byte 3 : Block number result = PartAuthBlock(handleFlag, index);
if (result == )
break;
}
}
} /// <summary>
/// 在读取或写入操作前需要验证区块
/// </summary>
/// <param name="handleFlag">是否为写入、更新操作</param>
/// <param name="index">验证的区块号</param>
/// <returns></returns>
private int PartAuthBlock(int handleFlag, int index)
{
int indx;
string tmpStr;
if (rbKType1.Checked == true)
{
SendBuff[] = 0x60;//keyA
}
else if (rbKType2.Checked == true)
{
SendBuff[] = 0x61;//keyB
} SendBuff[] = byte.Parse(tAuthenKeyNum.Text, System.Globalization.NumberStyles.HexNumber); // Key 5 value SendLen = ;
RecvLen = ; retCode = SendAPDU(, false, ); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return ;
}
else
{
tmpStr = "";
for (indx = ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
}
if (tmpStr.Trim() == "90 00")
{
displayOut(, , "验证成功!");//Authentication success
if (handleFlag == )//清空
{
if (index == )
{
index += ;//从块1开始写入
for (int i = index; i <= ; i++)
{
AllBlockClear(i);
}
}
else
{
for (int i = index; i <= index + ; i++)
{
AllBlockClear(i);
}
}
}
else if (handleFlag == )//读取
{
ReadAllBlock(index);
}
else if (handleFlag == )//写入
{
bool isLastBlock = false;
if (index == )
{
index += ;//从块1开始写入
if ((index + ) < blockNum)
{
for (int i = index; i <= index + ; i++)
{
AllBlockWrite(i, false);//这里写每个块的写入循环
}
}
else
{
for (int i = index; i <= blockNum; i++)
{
if (i == blockNum)
isLastBlock = true;
AllBlockWrite(i, isLastBlock);//这里写每个块的写入循环
}
}
}
else
{
int temp = yuShu == ? (ShanQuNum-) * : (ShanQuNum - ) * ;
if (index < (ShanQuNum - ) * )
{
for (int i = index; i < index + ; i++)
{
AllBlockWrite(i, false);//这里写每个块的写入循环
}
}
else
{
if (yuShu == && index == (ShanQuNum - ) * )
{
for (int i = index; i < index + ; i++)
{
if (i == index + )
isLastBlock = true;
AllBlockWrite(i, isLastBlock);//这里写每个块的写入循环
}
}
else
{
for (int i = index; i <= index + yuShu - ; i++)
{
if (i == index + yuShu - )
isLastBlock = true;
AllBlockWrite(i, isLastBlock);//这里写每个块的写入循环
}
}
}
}
}
return ;
}
else
{
displayOut(, , "验证失败!");//Authentication failed
return ;
}
} private void ReadAllBlock(int index)
{
string tmpStr;
int indx;
isReadAll = true;
for (int i = index; i < index + ; i++)
{
ClearBuffers();
SendBuffAll[] = 0xFF;
SendBuffAll[] = 0xB0;
SendBuffAll[] = 0x00;
SendBuffAll[] = (byte)i;//块
SendBuffAll[] = (byte); SendLen = ;
RecvLen = SendBuffAll[] + ; retCode = SendAPDU(, true, ); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return;
}
else
{
tmpStr = "";
for (indx = RecvLen - ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuffAll[indx]);
}
}
if (tmpStr.Trim() == "90 00")
{
tmpStr = "";
tmpStr = System.Text.Encoding.Default.GetString(RecvBuffAll);
byte[] c = new byte[];
if (isReadAll)
{
if (tmpStr.Contains('?'))
{
if (IsBase64String(tmpStr.Split('?')[]))
{
c = Convert.FromBase64String(tmpStr.Split('?')[]);
readStr = readStr + tmpStr.Split('?')[];
}
}
//if (tmpStr.Contains('='))
//{
// string endStr = tmpStr.Split('=')[0] + "=";
// if (IsBase64String(endStr))
// {
// c = Convert.FromBase64String(endStr);
// readStr = readStr + endStr;
// }
// isReadAll = false;
//}
else
{
if (IsBase64String(tmpStr))
{
c = Convert.FromBase64String(tmpStr);
readStr = readStr + tmpStr.Split('?')[];
//tmpStr = System.Text.Encoding.Default.GetString(c);
}
}
}
displayOut(, , tmpStr);
}
else
{
displayOut(, , "读取块失败!");//Read block error
}
}
} /// <summary>
/// 验证读取出来的数据是否是Base64格式
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private bool IsBase64String(string s)
{
try { Convert.FromBase64String(s); }
catch { return false; }
return true;
} /// <summary>
/// 写入\更新所有区块
/// </summary>
/// <param name="index"></param>
/// <param name="isLastBlock"></param>
private void AllBlockWrite(int index, bool isLastBlock)
{
string tmpStr;
int indx, dataLength,leftBytes;
blockCount++; int blolen = bytes.Length % == ? (bytes.Length / ) : bytes.Length / + ;
leftBytes = bytes.Length % == ? : bytes.Length % ;
//int blockNum = (blolen - 2) % 3 == 0 ? (blolen - 2) / 3 : (blolen - 2) / 3 + 1;
ClearBuffers();
SendBuffAll[] = 0xFF; // CLA
SendBuffAll[] = 0xD6; // INS
SendBuffAll[] = 0x00; // P1
SendBuffAll[] = (byte)index; // P2 : Starting Block No.
if (isLastBlock)//最后一段要写入的数据
{
SendBuffAll[] = (byte); //(bytes.Length % 16) // P3 : Data length
dataLength = bytes.Length - leftBytes; //(blockCount - 1) * 16;
blockCount = ;
}
else
{
SendBuffAll[] = (byte); // P3 : Data length
//if (blockCount > blolen)
// blockCount = 0;
dataLength = index == ? : (blockCount - ) * ;
}
if (isLastBlock)
SendLen = leftBytes + ;
else
SendLen = SendBuffAll[] + ;//
RecvLen = 0x02; retCode = SendAPDU(, true, dataLength); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return;
}
else
{
tmpStr = "";
for (indx = ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuffAll[indx]);
}
}
if (tmpStr.Trim() == "90 00")
{
displayOut(, , "写入成功");
}
else
{
displayOut(, , "");
}
} private void AllBlockClear(int index)
{
string tmpStr;
int indx;
ClearBuffers();
SendBuffAll[] = 0xFF; // CLA
SendBuffAll[] = 0xD6; // INS
SendBuffAll[] = 0x00; // P1
SendBuffAll[] = (byte)index; // P2 : Starting Block No.
SendBuffAll[] = (byte); // P3 : Data length
SendLen = SendBuffAll[] + ;
RecvLen = 0x02; retCode = SendAPDU(, true, ); if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return;
}
else
{
tmpStr = "";
for (indx = ; indx <= RecvLen - ; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuffAll[indx]);
}
}
if (tmpStr.Trim() == "90 00")
{
displayOut(, , "写入成功");
}
else
{
displayOut(, , "写卡失败");
}
} /// <summary>
/// 汉字转换到16进制
/// </summary>
/// <param name="s"></param>
/// <param name="charset">编码,如"gb2312","gb2312"</param>
/// <param name="fenge">是否每字符用空格分隔</param>
/// <returns></returns>
//public string ToHex(string s, string charset, bool fenge)
//{
// if ((s.Length % 2) != 0)
// {
// s += " ";//空格
// }
// System.Text.Encoding chs = System.Text.Encoding.GetEncoding(charset);
// byte[] bytes = chs.GetBytes(s);
// string str = "";
// for (int i = 0; i < bytes.Length; i++)
// {
// str += string.Format("{0:X}", bytes[i]);
// if (fenge && (i != bytes.Length - 1))
// {
// str += string.Format("{0}", " ");
// }
// }
// return str.ToUpper();
//} public byte[] ToHex(string s, string charset, bool fenge)
{
if ((s.Length % ) != )
{
s += " ";//空格
}
System.Text.Encoding chs = System.Text.Encoding.GetEncoding(charset);
byte[] bytes = chs.GetBytes(s);
//string str = "";
//for (int i = 0; i < bytes.Length; i++)
//{
// str += string.Format("{0:X}", bytes[i]);
// if (fenge && (i != bytes.Length - 1))
// {
// str += string.Format("{0}", " ");
// }
//}
return bytes;
} /// <summary>
/// 16进制转换成汉字
/// </summary>
/// <param name="hex"></param>
/// <param name="charset">编码,如"gb2312","gb2312"</param>
/// <returns></returns>
public string UnHex(string hex, string charset)
{
if (hex == null)
throw new ArgumentNullException("hex");
hex = hex.Replace(",", "");
hex = hex.Replace("/n", "");
hex = hex.Replace("//", "");
hex = hex.Replace(" ", "");
if (hex.Length % != )
{
hex += "";//空格
}
// 需要将 hex 转换成 byte 数组。
byte[] bytes = new byte[hex.Length / ]; for (int i = ; i < bytes.Length; i++)
{
try
{
// 每两个字符是一个 byte。
bytes[i] = byte.Parse(hex.Substring(i * , ),
System.Globalization.NumberStyles.HexNumber);
}
catch
{
// Rethrow an exception with custom message.
throw new ArgumentException("hex is not a valid hex number!", "hex");
}
}
System.Text.Encoding chs = System.Text.Encoding.GetEncoding(charset);
return chs.GetString(bytes);
}
#endregion
}
}

这个是可以写入中文的,思路大概是这样,先把中文转成base64,然后把base64格式的再转成byte[]。

完整的demo下载地址:https://github.com/wsn931203/DemoDataToNFCCard.git

使用ACR122U NFC读卡器对M1卡进行读写操作(可以读写中文)的更多相关文章

  1. M1卡破解(自从学校升级系统之后,还准备在研究下)【转】

    本文转载自: M1卡说明及使用proxmark3破解方法 看了网上写的一些关于M1卡的文章,多数有些误导之嫌.首先谈谈M1卡的规格,M1卡的容量为1KB,好多网上写8KB,这里其实是有个误区,应该是8 ...

  2. M1卡说明及使用proxmark3破解方法

    看了网上写的一些关于M1卡的文章,多数有些误导之嫌.首先谈谈M1卡的规格,M1卡的容量为1KB,好多网上写8KB,这里其实是有个误区,应该是8K位.1Byte=1B=8位.其实也就是说8k位想到于1K ...

  3. M1卡的工作原理【转】

    本文转载自:https://blog.csdn.net/zmq5411/article/details/52042457 M1卡的工作原理 本篇对M1卡的编程是利用上述第二种方法.M1卡最为重要的优点 ...

  4. 使用NFC读卡器ACR122u读取银行卡信息

    使用NFC读卡器  ACR122u 使用ACR122u Tool 软件发送spdu指令即可 一些运行结果 如上所示,银行卡的卡号,有效期,卡主姓名,身份证号,进期消费记录均可读出

  5. Android NFC M1卡读写&芯片卡读写(CPU卡读写)(RFID读写)

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/sgn5200/article/detai ...

  6. RFID-RC522、FM1702SL、M1卡初探

    catalogue . 引言 . RC522芯片(读卡器)简介 . FM1702SL芯片(读卡器)简介 . RFID M1卡简介 . 读取ID/序列号(arduino uno.MFRC522芯片 Ba ...

  7. M1卡介绍

    本文整理自网络. M1卡是指菲利浦下属子公司恩智浦出品的芯片缩写,全称为NXP Mifare1系列,常用的有S50及S70两种型号,目前都有国产芯片与其兼容,属于非接触式IC卡.最为重要的优点是可读可 ...

  8. 手机NFC模拟门禁卡

    楼主所在的某电子科技类大学,从宿舍楼到实验楼到图书馆办公楼,全部都有门禁,前两天突然在某安软件市场看到一个可以模拟门禁卡的软件,然而可能是我的手机系统太6了,竟然模拟不了,无奈自己动手,从根本上解决问 ...

  9. 射频识别技术漫谈(15)——Mifare1的安全性及7字节序列号M1卡【worlsing笔记】

    Mifare1的安全性主要指卡中数据的安全性,要求卡中的数据不能被非法修改或窃听.数据的安全性主要使用加密技术来保证,加密技术有两个关键因素:加密算法和密钥.现代加密技术的一大特点是加密算法公开,如果 ...

随机推荐

  1. OCC上下文设置显示模式

    #include <AIS_InteractiveContext.hxx> 通过AIS_InteractiveContext::SetDisplayMode()函数来设置 void  Se ...

  2. DataTable行列转置

    DataTable dtNew = new DataTable(); dtNew.Columns.Add("ColumnName", typeof(string)); ; i &l ...

  3. ajax跨域例子

    例子 https://github.com/ruanyf/react-demos/blob/master/demo12/index.html 此网页代码运行在本地, 是可以访问 github 数据的. ...

  4. HDU-6031 Innumerable Ancestors(二分+树上倍增)

    题意 给一棵树,$m$次询问,每次询问给两个点集问从两个点集中各取一个点的$LCA$的最大深度. 思路 二分答案.对于某个二分过程中得到的$Mid$,如果可行则两个点集在$Mid$所在的深度存在公共的 ...

  5. Hadoop yarn任务调度策略介绍(转)

    理想情况下,我们应用对Yarn资源的请求应该立刻得到满足,但现实情况资源往往是有限的,特别是在一个很繁忙的集群,一个应用资源的请求经常需要等待一段时间才能的到相应的资源.在Yarn中,负责给应用分配资 ...

  6. SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)基于SpringMVC+Shiro的用户登录权限验证

    序: 在上一篇中,咱们已经对于项目已经做了基本的配置,这一篇文章开始学习Shiro如何对登录进行验证. 教学: 一.Shiro配置的简要说明. 有心人可能注意到了,在上一章的applicationCo ...

  7. python numpy 间的的数据变算公式

    import numpy as np a = np.arange(100) print(np.sum(a))#求和 print(np.mean(a))#平均值 print(np.max(a))#最大值 ...

  8. PyCharm 项目删除

    Pycharm 删除项目具体操作如下: 1.选择菜单 File   close project 2.选择要删除的项目右上角选择× 3.找到项目所在目录,删除相应文件夹 之后再次打开pycharm 发现 ...

  9. json中的json.dumps()

    Json简介 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于JavaScript(Standard ECMA-262 3rd Edition - ...

  10. m3u8下载转码一次完成

    最近看到有部分网站开始加入视频解析服务,虽然这种服务会损害土豆优酷等视频托管商的权益,但是,烦人的广告也让我们开始寻找有没有什么比较靠谱的解决方法~实际上很多网站都在使用m3u8文件格式,里面都是视频 ...