• 使用ACR122U NFC读卡器对M1卡进行读写操作(可以读写中文)


    因为项目需要,第一次接触到了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进制的数据。

     

    这是我做的页面

    这是窗体的代码

       1 using System;
       2 using System.Drawing;
       3 using System.Linq;
       4 using System.Windows.Forms;
       5 
       6 namespace WindowsFormsApplication1
       7 {
       8     public partial class NFCCardForm : Form
       9     {
      10         public NFCCardForm()
      11         {
      12             InitializeComponent();
      13         }
      14 
      15         #region 全局变量声明
      16         public int retCode, hContext, hCard, Protocol, ReaderCount, nBytesRet, blockCount, blockNum, ShanQuNum, yuShu;
      17         public bool connActive = false;
      18         public byte[] SendBuff = new byte[263];//最多可以放752个
      19         public byte[] RecvBuff = new byte[263];
      20         public byte[] SendBuffAll = new byte[263];//全部
      21         public byte[] RecvBuffAll = new byte[263];
      22         public byte[] bytes = new byte[263];
      23         public int SendLen, RecvLen, ReaderLen, ATRLen, dwState, dwActProtocol;
      24         public int reqType, Aprotocol, dwProtocol, cbPciLength;
      25         public ModWinsCard.SCARD_IO_REQUEST pioSendRequest;
      26         string readStr = "";
      27         public static string writeStr = "";
      28         bool isReadAll = false;
      29         #endregion
      30 
      31         #region 窗体事件
      32         private void Form1_Load(object sender, EventArgs e)
      33         {
      34             InitMenu();
      35         }
      36 
      37         /// <summary>
      38         /// 读卡器初始化
      39         /// </summary>
      40         /// <param name="sender"></param>
      41         /// <param name="e"></param>
      42         private void bInit_Click(object sender, EventArgs e)
      43         {
      44             string ReaderList = "" + Convert.ToChar(0);
      45             int indx;
      46             int pcchReaders = 0;
      47             string rName = "";
      48 
      49             //Establish Context
      50             retCode = ModWinsCard.SCardEstablishContext(ModWinsCard.SCARD_SCOPE_USER, 0, 0, ref hContext);
      51 
      52             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
      53             {
      54                 displayOut(1, retCode, "");
      55                 return;
      56             }
      57 
      58             // 2. List PC/SC card readers installed in the system
      59 
      60             retCode = ModWinsCard.SCardListReaders(this.hContext, null, null, ref pcchReaders);
      61 
      62             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
      63             {
      64                 displayOut(1, retCode, "");
      65                 return;
      66             }
      67             EnableButtons();
      68             byte[] ReadersList = new byte[pcchReaders];
      69             // Fill reader list
      70             retCode = ModWinsCard.SCardListReaders(this.hContext, null, ReadersList, ref pcchReaders);
      71             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
      72             {
      73                 mMsg.AppendText("SCardListReaders Error: " + ModWinsCard.GetScardErrMsg(retCode));
      74                 return;
      75             }
      76             else
      77             {
      78                 displayOut(0, 0, " ");
      79             }
      80 
      81             rName = "";
      82             indx = 0;
      83 
      84             //Convert reader buffer to string
      85             while (ReadersList[indx] != 0)
      86             {
      87                 while (ReadersList[indx] != 0)
      88                 {
      89                     rName = rName + (char)ReadersList[indx];
      90                     indx = indx + 1;
      91                 }
      92                 //Add reader name to list
      93                 cbReader.Items.Add(rName);
      94                 rName = "";
      95                 indx = indx + 1;
      96             }
      97 
      98             if (cbReader.Items.Count > 0)
      99             {
     100                 cbReader.SelectedIndex = 0;
     101             }
     102         }
     103 
     104         private void bConnect_Click(object sender, EventArgs e)
     105         {
     106             retCode = ModWinsCard.SCardConnect(hContext, cbReader.SelectedItem.ToString(), ModWinsCard.SCARD_SHARE_SHARED,
     107                                            ModWinsCard.SCARD_PROTOCOL_T1, ref hCard, ref Protocol);
     108 
     109             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
     110             {
     111                 retCode = ModWinsCard.SCardConnect(hContext, cbReader.SelectedItem.ToString(), ModWinsCard.SCARD_SHARE_DIRECT,
     112                                             0, ref hCard, ref Protocol);
     113                 if (retCode != ModWinsCard.SCARD_S_SUCCESS)
     114                     displayOut(1, retCode, "");
     115                 else
     116                 {
     117                     displayOut(0, 0, "成功连接到" + cbReader.Text);//Successful connection to
     118                 }
     119             }
     120             else
     121             {
     122                 displayOut(0, 0, "成功连接到" + cbReader.Text);
     123             }
     124             GetUID();
     125             connActive = true;
     126             gbLoadKeys.Enabled = true;
     127             gbAuth.Enabled = true;
     128             gbBinOps.Enabled = true;
     129             groupBox1.Enabled = true;
     130             tKeyNum.Focus();
     131             rbKType1.Checked = true;
     132             btnClear.Enabled = true;
     133             btnRead.Enabled = true;
     134             btnWrite.Enabled = true;
     135         }
     136 
     137         private void bClear_Click(object sender, EventArgs e)
     138         {
     139             mMsg.Clear();
     140         }
     141 
     142         private void bReset_Click(object sender, EventArgs e)
     143         {
     144             if (connActive)
     145             {
     146                 retCode = ModWinsCard.SCardDisconnect(hCard, ModWinsCard.SCARD_UNPOWER_CARD);
     147             }
     148 
     149             retCode = ModWinsCard.SCardReleaseContext(hCard);
     150             InitMenu();
     151         }
     152 
     153         private void bQuit_Click(object sender, EventArgs e)
     154         {
     155             // terminate the application
     156             retCode = ModWinsCard.SCardReleaseContext(hContext);
     157             retCode = ModWinsCard.SCardDisconnect(hCard, ModWinsCard.SCARD_UNPOWER_CARD);
     158             System.Environment.Exit(0);
     159         }
     160 
     161         private void bLoadKey_Click(object sender, EventArgs e)
     162         {
     163             byte tmpLong;
     164             string tmpStr;
     165 
     166             if (tKey1.Text == "" | !byte.TryParse(tKey1.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
     167             {
     168                 tKey1.Focus();
     169                 tKey1.Text = "";
     170                 return;
     171             }
     172 
     173             if (tKey2.Text == "" | !byte.TryParse(tKey2.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
     174             {
     175                 tKey2.Focus();
     176                 tKey2.Text = "";
     177                 return;
     178             }
     179 
     180             if (tKey3.Text == "" | !byte.TryParse(tKey3.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
     181             {
     182                 tKey3.Focus();
     183                 tKey3.Text = "";
     184                 return;
     185             }
     186 
     187             if (tKey4.Text == "" | !byte.TryParse(tKey4.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
     188             {
     189                 tKey4.Focus();
     190                 tKey4.Text = "";
     191                 return;
     192             }
     193 
     194             if (tKey5.Text == "" | !byte.TryParse(tKey5.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
     195             {
     196                 tKey5.Focus();
     197                 tKey5.Text = "";
     198                 return;
     199             }
     200 
     201             if (tKey6.Text == "" | !byte.TryParse(tKey6.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
     202             {
     203                 tKey6.Focus();
     204                 tKey6.Text = "";
     205                 return;
     206             }
     207 
     208             ClearBuffers();
     209             // Load Authentication Keys command
     210             SendBuff[0] = 0xFF;                                                                        // Class
     211             SendBuff[1] = 0x82;                                                                        // INS
     212             SendBuff[2] = 0x00;                                                                        // P1 : Key Structure
     213             SendBuff[3] = byte.Parse(tKeyNum.Text, System.Globalization.NumberStyles.HexNumber);
     214             SendBuff[4] = 0x06;                                                                        // P3 : Lc
     215             SendBuff[5] = byte.Parse(tKey1.Text, System.Globalization.NumberStyles.HexNumber);        // Key 1 value
     216             SendBuff[6] = byte.Parse(tKey2.Text, System.Globalization.NumberStyles.HexNumber);        // Key 2 value
     217             SendBuff[7] = byte.Parse(tKey3.Text, System.Globalization.NumberStyles.HexNumber);        // Key 3 value
     218             SendBuff[8] = byte.Parse(tKey4.Text, System.Globalization.NumberStyles.HexNumber);        // Key 4 value
     219             SendBuff[9] = byte.Parse(tKey5.Text, System.Globalization.NumberStyles.HexNumber);        // Key 5 value
     220             SendBuff[10] = byte.Parse(tKey6.Text, System.Globalization.NumberStyles.HexNumber);       // Key 6 value
     221 
     222             SendLen = 11;
     223             RecvLen = 2;
     224 
     225             retCode = SendAPDU(1, false, 0);
     226 
     227             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
     228             {
     229                 return;
     230             }
     231             else
     232             {
     233                 tmpStr = "";
     234                 for (int indx = RecvLen - 2; indx <= RecvLen - 1; indx++)
     235                 {
     236                     tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
     237                 }
     238             }
     239             if (tmpStr.Trim() != "90 00")
     240             {
     241                 displayOut(4, 0, "载入密钥失败!");//Load authentication keys error
     242             }
     243         }
     244 
     245         private void btnAuth_Click(object sender, EventArgs e)
     246         {
     247             int tempInt, indx;
     248             byte tmpLong;
     249             string tmpStr;
     250 
     251             // Validate input
     252             if (tBlkNo.Text == "" | !int.TryParse(tBlkNo.Text, out tempInt))
     253             {
     254                 tBlkNo.Focus();
     255                 tBlkNo.Text = "";
     256                 return;
     257             }
     258 
     259             if (int.Parse(tBlkNo.Text) > 319)
     260             {
     261                 tBlkNo.Text = "319";
     262             }
     263 
     264             if (tAuthenKeyNum.Text == "" | !byte.TryParse(tAuthenKeyNum.Text, System.Globalization.NumberStyles.HexNumber, null, out tmpLong))
     265             {
     266                 tAuthenKeyNum.Focus();
     267                 tAuthenKeyNum.Text = "";
     268                 return;
     269             }
     270             else if (int.Parse(tAuthenKeyNum.Text) > 1)
     271             {
     272                 tAuthenKeyNum.Text = "1";
     273                 return;
     274             }
     275 
     276             ClearBuffers();
     277 
     278             SendBuff[0] = 0xFF;                             // Class
     279             SendBuff[1] = 0x86;                             // INS
     280             SendBuff[2] = 0x00;                             // P1
     281             SendBuff[3] = 0x00;                             // P2
     282             SendBuff[4] = 0x05;                             // Lc
     283             SendBuff[5] = 0x01;                             // Byte 1 : Version number
     284             SendBuff[6] = 0x00;                             // Byte 2
     285             SendBuff[7] = (byte)int.Parse(tBlkNo.Text);     // Byte 3 : Block number
     286 
     287             if (rbKType1.Checked == true)
     288             {
     289                 SendBuff[8] = 0x60;
     290             }
     291             else if (rbKType2.Checked == true)
     292             {
     293                 SendBuff[8] = 0x61;
     294             }
     295 
     296             SendBuff[9] = byte.Parse(tAuthenKeyNum.Text, System.Globalization.NumberStyles.HexNumber);        // Key 5 value
     297 
     298             SendLen = 10;
     299             RecvLen = 2;
     300 
     301             retCode = SendAPDU(1, false, 0);
     302 
     303             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
     304             {
     305                 return;
     306             }
     307             else
     308             {
     309                 tmpStr = "";
     310                 for (indx = 0; indx <= RecvLen - 1; indx++)
     311                 {
     312                     tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
     313                 }
     314             }
     315             if (tmpStr.Trim() == "90 00")
     316             {
     317                 displayOut(0, 0, "验证成功!");//Authentication success
     318             }
     319             else
     320             {
     321                 displayOut(4, 0, "验证失败!");//Authentication failed
     322             }
     323         }
     324 
     325         private void bBinRead_Click(object sender, EventArgs e)
     326         {
     327             string tmpStr;
     328             int indx;
     329 
     330             // Validate Inputs
     331             tBinData.Text = "";
     332 
     333             if (tBinBlk.Text == "")
     334             {
     335                 tBinBlk.Focus();
     336                 return;
     337             }
     338 
     339             if (int.Parse(tBinBlk.Text) > 319)
     340             {
     341                 tBinBlk.Text = "319";
     342                 return;
     343             }
     344 
     345             if (tBinLen.Text == "")
     346             {
     347                 tBinLen.Focus();
     348                 return;
     349             }
     350 
     351             ClearBuffers();
     352             SendBuff[0] = 0xFF;
     353             SendBuff[1] = 0xB0;
     354             SendBuff[2] = 0x00;
     355             SendBuff[3] = (byte)int.Parse(tBinBlk.Text);
     356             SendBuff[4] = (byte)int.Parse(tBinLen.Text);
     357 
     358             SendLen = 5;
     359             RecvLen = SendBuff[4] + 2;
     360 
     361             retCode = SendAPDU(1, false, 0);
     362 
     363             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
     364             {
     365                 return;
     366             }
     367             else
     368             {
     369                 tmpStr = "";
     370                 for (indx = RecvLen - 2; indx <= RecvLen - 1; indx++)
     371                 {
     372                     tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
     373                 }
     374             }
     375             if (tmpStr.Trim() == "90 00")
     376             {
     377                 tmpStr = "";
     378                 tmpStr = System.Text.Encoding.Default.GetString(RecvBuff);
     379                 byte[] c = new byte[263];
     380                 if (tmpStr.Contains('?'))
     381                 {
     382                     if (IsBase64String(tmpStr.Split('?')[0]))
     383                     {
     384                         c = Convert.FromBase64String(tmpStr.Split('?')[0]);
     385                         tmpStr = System.Text.Encoding.Default.GetString(c);
     386                     }
     387                 }
     388                 else
     389                 {
     390                     if (IsBase64String(tmpStr))
     391                     {
     392                         c = Convert.FromBase64String(tmpStr);
     393                         tmpStr = System.Text.Encoding.Default.GetString(c);
     394                     }
     395                 }
     396                 tBinData.Text = tmpStr;
     397                 displayOut(3, 0, tmpStr);
     398             }
     399             else
     400             {
     401                 displayOut(4, 0, "读取块失败!");//Read block error
     402             }
     403         }
     404 
     405         private void bBinUpd_Click(object sender, EventArgs e)
     406         {
     407             string tmpStr;
     408             int indx, tempInt;
     409 
     410             if (tBinBlk.Text == "" | !int.TryParse(tBinBlk.Text, out tempInt))
     411             {
     412                 tBinBlk.Focus();
     413                 tBinBlk.Text = "";
     414                 return;
     415             }
     416 
     417             if (int.Parse(tBinBlk.Text) > 319)
     418             {
     419                 tBinBlk.Text = "319";
     420                 return;
     421             }
     422 
     423             if (tBinLen.Text == "" | !int.TryParse(tBinLen.Text, out tempInt))
     424             {
     425                 tBinLen.Focus();
     426                 tBinLen.Text = "";
     427                 return;
     428             }
     429 
     430             if (tBinData.Text == "")
     431             {
     432                 tBinData.Focus();
     433                 return;
     434             }
     435 
     436             tmpStr = tBinData.Text;
     437             byte[] b = System.Text.Encoding.Default.GetBytes(tmpStr);
     438             //转成 Base64 形式的 System.String  
     439             tmpStr = Convert.ToBase64String(b);
     440             //将base64转成字符数组然后写入卡中
     441             bytes = System.Text.Encoding.Default.GetBytes(tmpStr);
     442             if (bytes.Length > 16)
     443             {
     444                 MessageBox.Show("写入的数据长度超过16,请重新输入");
     445                 return;
     446             }
     447             ClearBuffers();
     448             SendBuff[0] = 0xFF;                                     // CLA
     449             SendBuff[1] = 0xD6;                                     // INS
     450             SendBuff[2] = 0x00;                                     // P1
     451             SendBuff[3] = (byte)int.Parse(tBinBlk.Text);            // P2 : Starting Block No.
     452             SendBuff[4] = (byte)bytes.Length;  //(byte)int.Parse(tBinLen.Text);            // P3 : Data length
     453 
     454             for (indx = 0; indx <= bytes.Length - 1; indx++)
     455             {
     456                 SendBuff[indx + 5] = bytes[indx];
     457             }
     458             SendLen = SendBuff[4] + 5;// 
     459             RecvLen = 0x02;
     460 
     461             retCode = SendAPDU(2, false, 0);
     462 
     463             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
     464             {
     465                 return;
     466             }
     467             else
     468             {
     469                 tmpStr = "";
     470                 for (indx = 0; indx <= RecvLen - 1; indx++)
     471                 {
     472                     tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
     473                 }
     474             }
     475             if (tmpStr.Trim() == "90 00")
     476             {
     477                 tBinData.Text = "";
     478             }
     479             else
     480             {
     481                 displayOut(2, 0, tmpStr.Trim());//""
     482             }
     483         }
     484 
     485         private void btnRead_Click(object sender, EventArgs e)
     486         {
     487             string readData = readStr;
     488             AuthAllBootSector(1);
     489             if (readStr == null)
     490                 return;
     491 
     492             if (IsBase64String(readStr.Split('?')[0]))
     493             {
     494                 byte[] c = Convert.FromBase64String(readStr);
     495                 readData = System.Text.Encoding.Default.GetString(c);
     496                 if (readData.Contains(""))
     497                     readData = readData.Substring(0, readData.IndexOf(""));
     498             }
     499             readStr = null;
     500             displayOut(3, 0, readData);
     501 
     502         }
     503 
     504         private void btnWrite_Click(object sender, EventArgs e)
     505         {
     506             AuthAllBootSector(2);
     507             blockCount = 0;
     508         }
     509 
     510         /// <summary>
     511         /// 当文本框里的值发生改变时,动态显示出写入数据的长度
     512         /// </summary>
     513         /// <param name="sender"></param>
     514         /// <param name="e"></param>
     515         private void tBinData_TextChanged(object sender, EventArgs e)
     516         {
     517             string tmpStr = tBinData.Text;
     518             byte[] b = System.Text.Encoding.Default.GetBytes(tmpStr);
     519             //转成 Base64 形式的 System.String  
     520             tmpStr = Convert.ToBase64String(b);
     521             //将base64转成字节数组然后写入卡中
     522             bytes = System.Text.Encoding.Default.GetBytes(tmpStr);
     523             lblWriteLength.Text = bytes.Length.ToString();
     524         }
     525 
     526         /// <summary>
     527         /// 在写入新的内容时,先将卡里的原数据清空
     528         /// </summary>
     529         /// <param name="sender"></param>
     530         /// <param name="e"></param>
     531         private void btnClear_Click(object sender, EventArgs e)
     532         {
     533             int result;
     534             for (int index = 0; index <= 63; index += 4)//验证
     535             {
     536                 ClearBuffers();
     537                 SendBuff[0] = 0xFF;                             // Class
     538                 SendBuff[1] = 0x86;                             // INS
     539                 SendBuff[2] = 0x00;                             // P1
     540                 SendBuff[3] = 0x00;                             // P2
     541                 SendBuff[4] = 0x05;                             // Lc
     542                 SendBuff[5] = 0x01;                             // Byte 1 : Version number
     543                 SendBuff[6] = 0x00;                             // Byte 2
     544                 SendBuff[7] = (byte)index;//区块                  // Byte 3 : Block number
     545 
     546                 result = PartAuthBlock(0, index);
     547                 if (result == 0)
     548                     break;
     549             }
     550         }
     551         #endregion
     552 
     553         #region 自定义方法
     554         private void InitMenu()
     555         {
     556             connActive = false;
     557             cbReader.Text = "";
     558             cbReader.Items.Clear();
     559             mMsg.Text = "";
     560             tKeyNum.SelectedIndex = 0;
     561             tAuthenKeyNum.SelectedIndex = 0;
     562             bInit.Enabled = true;
     563             bConnect.Enabled = false;
     564             bClear.Enabled = false;
     565             displayOut(0, 0, "程序准备就绪");//Program ready
     566             bReset.Enabled = false;
     567             gbLoadKeys.Enabled = false;
     568             gbAuth.Enabled = false;
     569             gbBinOps.Enabled = false;
     570             groupBox1.Enabled = false;
     571             btnClear.Enabled = false;
     572             btnRead.Enabled = false;
     573             btnWrite.Enabled = false;
     574         }
     575 
     576         private void displayOut(int errType, int retVal, string PrintText)
     577         {
     578             switch (errType)
     579             {
     580                 case 0:
     581                     mMsg.SelectionColor = Color.Green;
     582                     break;
     583                 case 1:
     584                     mMsg.SelectionColor = Color.Red;
     585                     PrintText = ModWinsCard.GetScardErrMsg(retVal);
     586                     break;
     587                 case 2:
     588                     mMsg.SelectionColor = Color.Black;
     589                     PrintText = "<" + PrintText;
     590                     break;
     591                 case 3:
     592                     mMsg.SelectionColor = Color.Black;
     593                     PrintText = ">" + PrintText;
     594                     break;
     595                 case 4:
     596                     break;
     597             }
     598             mMsg.AppendText(PrintText);
     599             mMsg.AppendText("
    ");
     600             mMsg.SelectionColor = Color.Black;
     601             mMsg.Focus();
     602         }
     603 
     604         private void EnableButtons()
     605         {
     606             bInit.Enabled = false;
     607             bConnect.Enabled = true;
     608             bClear.Enabled = true;
     609             bReset.Enabled = true;
     610         }
     611 
     612         private void ClearBuffers()
     613         {
     614             long indx;
     615 
     616             for (indx = 0; indx <= 262; indx++)
     617             {
     618                 RecvBuff[indx] = 0;
     619                 SendBuff[indx] = 0;
     620                 RecvBuffAll[indx] = 0;
     621                 SendBuffAll[indx] = 0;
     622             }
     623         }
     624 
     625         //private static byte[] StringToByteSequence(string sourceString)
     626         //{
     627         //    int i = 0, n = 0;
     628         //    int j = (sourceString.Length) / 2;
     629 
     630         //    byte[] a = new byte[j];
     631         //    for (i = 0, n = 0; n < j; i += 2, n++)
     632         //    {
     633         //        a[n] = Convert.ToByte(sourceString.Substring(i, 2), 16);
     634         //    }
     635         //    return a;
     636         //}
     637 
     638         /// <summary>
     639         /// 
     640         /// </summary>
     641         /// <param name="handleFlag">是否是更新操作</param>
     642         /// <param name="isReadOrWriteAll">是不是全部读取或写入</param>
     643         /// <returns></returns>
     644         public int SendAPDU(int handleFlag, bool isReadOrWriteAll, int dataLength)
     645         {
     646             int indx;
     647             string tmpStr;
     648 
     649             pioSendRequest.dwProtocol = Aprotocol;
     650             pioSendRequest.cbPciLength = 8;
     651 
     652             // Display Apdu In
     653             tmpStr = "";
     654             if (handleFlag == 2)//更新
     655             {
     656                 if (isReadOrWriteAll)
     657                 {
     658                     for (indx = 0; indx <= 4; indx++)
     659                     {
     660                         tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuffAll[indx]);//更新的APDU命令
     661                     }
     662                     for (int i = 0; i <= SendLen - 6; i++)
     663                     {
     664                         SendBuffAll[i + 5] = bytes[i + dataLength];
     665                     }
     666                     SendLen = 21;
     667                 }
     668                 else
     669                 {
     670                     for (indx = 0; indx <= 4; indx++)
     671                     {
     672                         tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuff[indx]);//更新的APDU命令
     673                     }
     674                     for (int i = 0; i <= SendLen - 6; i++)
     675                     {
     676                         SendBuff[i + 5] = bytes[i];
     677                     }
     678                 }
     679             }
     680             else if (handleFlag == 1)//读取
     681             {
     682                 if (isReadOrWriteAll)//全部
     683                 {
     684                     for (indx = 0; indx <= SendLen - 1; indx++)
     685                     {
     686                         tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuffAll[indx]);
     687                     }
     688                 }
     689                 else
     690                 {
     691                     for (indx = 0; indx <= SendLen - 1; indx++)
     692                     {
     693                         tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuff[indx]);
     694                     }
     695                 }
     696             }
     697             else if (handleFlag == 0)//清空
     698             {
     699                 for (indx = 0; indx <= 4; indx++)
     700                 {
     701                     tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuffAll[indx]);//更新的APDU命令
     702                 }
     703                 for (int i = 0; i <= SendLen - 6; i++)
     704                 {
     705                     SendBuffAll[i + 5] = 0x00;
     706                 }
     707             }
     708             
     709             displayOut(2, 0, tmpStr);
     710             if (!isReadOrWriteAll)
     711                 retCode = ModWinsCard.SCardTransmit(hCard, ref pioSendRequest, ref SendBuff[0], SendLen, ref pioSendRequest, ref RecvBuff[0], ref RecvLen);
     712             else
     713                 retCode = ModWinsCard.SCardTransmit(hCard, ref pioSendRequest, ref SendBuffAll[0], SendLen, ref pioSendRequest, ref RecvBuffAll[0], ref RecvLen);
     714 
     715             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
     716             {
     717                 displayOut(1, retCode, "");
     718                 return retCode;
     719             }
     720 
     721             tmpStr = "";
     722             if (isReadOrWriteAll)
     723             {
     724                 for (indx = 0; indx <= RecvLen - 1; indx++)
     725                 {
     726                     tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuffAll[indx]);
     727                 }
     728             }
     729             else
     730             {
     731                 for (indx = 0; indx <= RecvLen - 1; indx++)
     732                 {
     733                     tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
     734                 }
     735             }
     736             displayOut(3, 0, tmpStr);
     737             return retCode;
     738         }
     739 
     740         #region GetUID()
     741         /// <summary>
     742         /// 获取UID
     743         /// </summary>
     744         private void GetUID()
     745         {
     746             // Get the firmaware version of the reader
     747             string tmpStr;
     748             int intIndx;
     749             ClearBuffers();
     750 
     751             #region GetFirmware APDU
     752             //SendBuff[0] = 0xFF;
     753             //SendBuff[1] = 0x00;
     754             //SendBuff[2] = 0x48;
     755             //SendBuff[3] = 0x00;
     756             //SendBuff[4] = 0x00;
     757             //SendLen = 5;
     758             //RecvLen = 10; 
     759             #endregion
     760 
     761             SendBuff[0] = 0xFF;
     762             SendBuff[1] = 0xCA;
     763             SendBuff[2] = 0x00;
     764             SendBuff[3] = 0x00;
     765             SendBuff[4] = 0x00;
     766             SendLen = 5;
     767             RecvLen = 10;
     768             retCode = SendAPDU(1, false, 0);
     769             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
     770                 return;
     771 
     772             // Interpret firmware data
     773             //tmpStr = "Firmware Version(版本): ";
     774             tmpStr = "UID: ";
     775             for (intIndx = 0; intIndx <= RecvLen - 3; intIndx++)
     776             {
     777                 tmpStr = tmpStr + string.Format("{0:X2}", RecvBuff[intIndx]);
     778             }
     779             displayOut(3, 0, tmpStr);
     780         }
     781         #endregion
     782 
     783         /// <summary>
     784         /// 验证所有区块
     785         /// </summary>
     786         /// <param name="handleFlag">处理操作的标志handleFlag 0清空,1读取,2写入</param>
     787         private void AuthAllBootSector(int handleFlag)
     788         {
     789             int result;
     790 
     791             if (handleFlag == 2)
     792             {
     793                 string data = writeStr;//获取要写入的字符串
     794                 byte[] b = System.Text.Encoding.Default.GetBytes(data);
     795                 //转成 Base64 形式的 System.String  
     796                 data = Convert.ToBase64String(b);
     797                 bytes = System.Text.Encoding.Default.GetBytes(data);
     798                 if (bytes.Length % 16 != 0)
     799                 {
     800                     b = null;
     801                     string endSign = "结结结结结结结";
     802                     //for (int i = 0; i < (bytes.Length % 16); i++)
     803                     //{
     804                         //endSign = "结结结结结结结"; //写入的数据不够填充满16位,最后的base64容易混乱,所以加个汉字,填满16位
     805                     //}
     806                     string str = writeStr + endSign;
     807                     b = System.Text.Encoding.Default.GetBytes(str);
     808                     data = "";
     809                     data = Convert.ToBase64String(b);
     810                 }
     811 
     812                 //将base64转成16进制然后写入卡中
     813                 bytes = System.Text.Encoding.Default.GetBytes(data);
     814                 //写入的数据需要的区块数量
     815                 blockNum = (bytes.Length % 16 == 0 ? (bytes.Length / 16) : (bytes.Length / 16 + 1));
     816                 //需要验证的扇区的数量,把有两个数据块的0扇区加上
     817                 ShanQuNum = (blockNum - 2) % 3 == 0 ? (blockNum - 2) / 3 + 1 : (blockNum - 2) / 3 + 2;
     818                 //获取最后一个扇区的写入的块的数量,yushu==0,则正好写满当前验证块(3块数据块);
     819                 //yushu==1,则写入当前验证块;yushu==2,则写入当前验证块+1
     820                 yuShu = (blockNum - 2) % 3;
     821                 for (int i = 0; i < 4 * ShanQuNum; i += 4) //验证 块  
     822                 {
     823                     ClearBuffers();
     824                     SendBuff[0] = 0xFF;                             // Class
     825                     SendBuff[1] = 0x86;                             // INS
     826                     SendBuff[2] = 0x00;                             // P1
     827                     SendBuff[3] = 0x00;                             // P2
     828                     SendBuff[4] = 0x05;                             // Lc
     829                     SendBuff[5] = 0x01;                             // Byte 1 : Version number
     830                     SendBuff[6] = 0x00;                             // Byte 2
     831                     SendBuff[7] = (byte)i;                   // Byte 3 : Block number
     832 
     833                     result = PartAuthBlock(handleFlag, i);
     834                     if (result == 0)
     835                         break;
     836                 }
     837             }
     838             else if (handleFlag == 1)
     839             {
     840                 for (int index = 0; index <= 63; index += 4)//验证
     841                 {
     842                     ClearBuffers();
     843                     SendBuff[0] = 0xFF;                             // Class
     844                     SendBuff[1] = 0x86;                             // INS
     845                     SendBuff[2] = 0x00;                             // P1
     846                     SendBuff[3] = 0x00;                             // P2
     847                     SendBuff[4] = 0x05;                             // Lc
     848                     SendBuff[5] = 0x01;                             // Byte 1 : Version number
     849                     SendBuff[6] = 0x00;                             // Byte 2
     850                     SendBuff[7] = (byte)index;//// Byte 3 : Block number
     851 
     852                     result = PartAuthBlock(handleFlag, index);
     853                     if (result == 0)
     854                         break;
     855                 }
     856             }
     857         }
     858 
     859         /// <summary>
     860         /// 在读取或写入操作前需要验证区块
     861         /// </summary>
     862         /// <param name="handleFlag">是否为写入、更新操作</param>
     863         /// <param name="index">验证的区块号</param>
     864         /// <returns></returns>
     865         private int PartAuthBlock(int handleFlag, int index)
     866         {
     867             int indx;
     868             string tmpStr;
     869             if (rbKType1.Checked == true)
     870             {
     871                 SendBuff[8] = 0x60;//keyA
     872             }
     873             else if (rbKType2.Checked == true)
     874             {
     875                 SendBuff[8] = 0x61;//keyB
     876             }
     877 
     878             SendBuff[9] = byte.Parse(tAuthenKeyNum.Text, System.Globalization.NumberStyles.HexNumber);        // Key 5 value
     879 
     880             SendLen = 10;
     881             RecvLen = 2;
     882 
     883             retCode = SendAPDU(1, false, 0);
     884 
     885             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
     886             {
     887                 return 2;
     888             }
     889             else
     890             {
     891                 tmpStr = "";
     892                 for (indx = 0; indx <= RecvLen - 1; indx++)
     893                 {
     894                     tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
     895                 }
     896             }
     897             if (tmpStr.Trim() == "90 00")
     898             {
     899                 displayOut(0, 0, "验证成功!");//Authentication success
     900                 if (handleFlag == 0)//清空
     901                 {
     902                     if (index == 0)
     903                     {
     904                         index += 1;//从块1开始写入
     905                         for (int i = index; i <= 2; i++)
     906                         {
     907                             AllBlockClear(i);
     908                         }
     909                     }
     910                     else
     911                     {
     912                         for (int i = index; i <= index + 2; i++)
     913                         {
     914                             AllBlockClear(i);
     915                         }
     916                     }
     917                 }
     918                 else if (handleFlag == 1)//读取
     919                 {
     920                     ReadAllBlock(index);
     921                 }
     922                 else if (handleFlag == 2)//写入
     923                 {
     924                     bool isLastBlock = false;
     925                     if (index == 0)
     926                     {
     927                         index += 1;//从块1开始写入
     928                         if ((index + 1) < blockNum)
     929                         {
     930                             for (int i = index; i <= index + 1; i++)
     931                             {
     932                                 AllBlockWrite(i, false);//这里写每个块的写入循环
     933                             }
     934                         }
     935                         else
     936                         {
     937                             for (int i = index; i <= blockNum; i++)
     938                             {
     939                                 if (i == blockNum)
     940                                     isLastBlock = true;
     941                                 AllBlockWrite(i, isLastBlock);//这里写每个块的写入循环
     942                             }
     943                         }
     944                     }
     945                     else
     946                     {
     947                         int temp = yuShu == 0 ? (ShanQuNum-1) * 4 : (ShanQuNum - 2) * 4;
     948                         if (index < (ShanQuNum - 1) * 4)
     949                         {
     950                             for (int i = index; i < index + 3; i++)
     951                             {
     952                                 AllBlockWrite(i, false);//这里写每个块的写入循环
     953                             }
     954                         }
     955                         else
     956                         {
     957                             if (yuShu == 0 && index == (ShanQuNum - 1) * 4)
     958                             {
     959                                 for (int i = index; i < index + 3; i++)
     960                                 {
     961                                     if (i == index + 2)
     962                                         isLastBlock = true;
     963                                     AllBlockWrite(i, isLastBlock);//这里写每个块的写入循环
     964                                 }
     965                             }
     966                             else
     967                             {
     968                                 for (int i = index; i <= index + yuShu - 1; i++)
     969                                 {
     970                                     if (i == index + yuShu - 1)
     971                                         isLastBlock = true;
     972                                     AllBlockWrite(i, isLastBlock);//这里写每个块的写入循环
     973                                 }
     974                             }
     975                         }
     976                     }
     977                 }
     978                 return 1;
     979             }
     980             else
     981             {
     982                 displayOut(4, 0, "验证失败!");//Authentication failed
     983                 return 0;
     984             }
     985         }
     986 
     987         private void ReadAllBlock(int index)
     988         {
     989             string tmpStr;
     990             int indx;
     991             isReadAll = true;
     992             for (int i = index; i < index + 4; i++)
     993             {
     994                 ClearBuffers();
     995                 SendBuffAll[0] = 0xFF;
     996                 SendBuffAll[1] = 0xB0;
     997                 SendBuffAll[2] = 0x00;
     998                 SendBuffAll[3] = (byte)i;//
     999                 SendBuffAll[4] = (byte)16;
    1000 
    1001                 SendLen = 5;
    1002                 RecvLen = SendBuffAll[4] + 2;
    1003 
    1004                 retCode = SendAPDU(1, true, 0);
    1005 
    1006                 if (retCode != ModWinsCard.SCARD_S_SUCCESS)
    1007                 {
    1008                     return;
    1009                 }
    1010                 else
    1011                 {
    1012                     tmpStr = "";
    1013                     for (indx = RecvLen - 2; indx <= RecvLen - 1; indx++)
    1014                     {
    1015                         tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuffAll[indx]);
    1016                     }
    1017                 }
    1018                 if (tmpStr.Trim() == "90 00")
    1019                 {
    1020                     tmpStr = "";
    1021                     tmpStr = System.Text.Encoding.Default.GetString(RecvBuffAll);
    1022                     byte[] c = new byte[263];
    1023                     if (isReadAll)
    1024                     {
    1025                         if (tmpStr.Contains('?'))
    1026                         {
    1027                             if (IsBase64String(tmpStr.Split('?')[0]))
    1028                             {
    1029                                 c = Convert.FromBase64String(tmpStr.Split('?')[0]);
    1030                                 readStr = readStr + tmpStr.Split('?')[0];
    1031                             }
    1032                         }
    1033                         //if (tmpStr.Contains('='))
    1034                         //{
    1035                         //    string endStr = tmpStr.Split('=')[0] + "=";
    1036                         //    if (IsBase64String(endStr))
    1037                         //    {
    1038                         //        c = Convert.FromBase64String(endStr);
    1039                         //        readStr = readStr + endStr;
    1040                         //    }
    1041                         //    isReadAll = false;
    1042                         //}
    1043                         else
    1044                         {
    1045                             if (IsBase64String(tmpStr))
    1046                             {
    1047                                 c = Convert.FromBase64String(tmpStr);
    1048                                 readStr = readStr + tmpStr.Split('?')[0];
    1049                                 //tmpStr = System.Text.Encoding.Default.GetString(c);
    1050                             }
    1051                         }
    1052                     }
    1053                     displayOut(3, 0, tmpStr);
    1054                 }
    1055                 else
    1056                 {
    1057                     displayOut(4, 0, "读取块失败!");//Read block error
    1058                 }
    1059             }
    1060         }
    1061 
    1062         /// <summary>
    1063         /// 验证读取出来的数据是否是Base64格式
    1064         /// </summary>
    1065         /// <param name="s"></param>
    1066         /// <returns></returns>
    1067         private bool IsBase64String(string s)
    1068         {
    1069             try { Convert.FromBase64String(s); }
    1070             catch { return false; }
    1071             return true;
    1072         }
    1073 
    1074         /// <summary>
    1075         /// 写入更新所有区块
    1076         /// </summary>
    1077         /// <param name="index"></param>
    1078         /// <param name="isLastBlock"></param>
    1079         private void AllBlockWrite(int index, bool isLastBlock)
    1080         {
    1081             string tmpStr;
    1082             int indx, dataLength,leftBytes;
    1083             blockCount++;
    1084 
    1085             int blolen = bytes.Length % 16 == 0 ? (bytes.Length / 16) : bytes.Length / 16 + 1;
    1086             leftBytes = bytes.Length % 16 == 0 ? 16 : bytes.Length % 16;
    1087             //int blockNum = (blolen - 2) % 3 == 0 ? (blolen - 2) / 3 : (blolen - 2) / 3 + 1;
    1088             ClearBuffers();
    1089             SendBuffAll[0] = 0xFF;                                     // CLA
    1090             SendBuffAll[1] = 0xD6;                                     // INS
    1091             SendBuffAll[2] = 0x00;                                     // P1
    1092             SendBuffAll[3] = (byte)index;                                  // P2 : Starting Block No.
    1093             if (isLastBlock)//最后一段要写入的数据
    1094             {
    1095                 SendBuffAll[4] = (byte)16; //(bytes.Length % 16)              // P3 : Data length
    1096                 dataLength = bytes.Length - leftBytes; //(blockCount - 1) * 16;
    1097                 blockCount = 0;
    1098             }
    1099             else
    1100             {
    1101                 SendBuffAll[4] = (byte)16;                                 // P3 : Data length
    1102                 //if (blockCount > blolen)
    1103                 //    blockCount = 0;
    1104                 dataLength = index == 1 ? 0 : (blockCount - 1) * 16;
    1105             }
    1106             if (isLastBlock)
    1107                 SendLen = leftBytes + 5;
    1108             else
    1109                 SendLen = SendBuffAll[4] + 5;// 
    1110             RecvLen = 0x02;
    1111 
    1112             retCode = SendAPDU(2, true, dataLength);
    1113 
    1114             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
    1115             {
    1116                 return;
    1117             }
    1118             else
    1119             {
    1120                 tmpStr = "";
    1121                 for (indx = 0; indx <= RecvLen - 1; indx++)
    1122                 {
    1123                     tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuffAll[indx]);
    1124                 }
    1125             }
    1126             if (tmpStr.Trim() == "90 00")
    1127             {
    1128                 displayOut(3, 0, "写入成功");
    1129             }
    1130             else
    1131             {
    1132                 displayOut(2, 0, "");
    1133             }
    1134         }
    1135 
    1136         private void AllBlockClear(int index)
    1137         {
    1138             string tmpStr;
    1139             int indx;
    1140             ClearBuffers();
    1141             SendBuffAll[0] = 0xFF;                                     // CLA
    1142             SendBuffAll[1] = 0xD6;                                     // INS
    1143             SendBuffAll[2] = 0x00;                                     // P1
    1144             SendBuffAll[3] = (byte)index;                                  // P2 : Starting Block No.
    1145             SendBuffAll[4] = (byte)16;                                 // P3 : Data length
    1146             SendLen = SendBuffAll[4] + 5;
    1147             RecvLen = 0x02;
    1148 
    1149             retCode = SendAPDU(0, true, 0);
    1150 
    1151             if (retCode != ModWinsCard.SCARD_S_SUCCESS)
    1152             {
    1153                 return;
    1154             }
    1155             else
    1156             {
    1157                 tmpStr = "";
    1158                 for (indx = 0; indx <= RecvLen - 1; indx++)
    1159                 {
    1160                     tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuffAll[indx]);
    1161                 }
    1162             }
    1163             if (tmpStr.Trim() == "90 00")
    1164             {
    1165                 displayOut(3, 0, "写入成功");
    1166             }
    1167             else
    1168             {
    1169                 displayOut(2, 0, "写卡失败");
    1170             }
    1171         }
    1172 
    1173         /// <summary>
    1174         ///  汉字转换到16进制
    1175         /// </summary>
    1176         /// <param name="s"></param>
    1177         /// <param name="charset">编码,如"gb2312","gb2312"</param>
    1178         /// <param name="fenge">是否每字符用空格分隔</param>
    1179         /// <returns></returns>
    1180         //public string ToHex(string s, string charset, bool fenge)
    1181         //{
    1182         //    if ((s.Length % 2) != 0)
    1183         //    {
    1184         //        s += " ";//空格
    1185         //    }
    1186         //    System.Text.Encoding chs = System.Text.Encoding.GetEncoding(charset);
    1187         //    byte[] bytes = chs.GetBytes(s);
    1188         //    string str = "";
    1189         //    for (int i = 0; i < bytes.Length; i++)
    1190         //    {
    1191         //        str += string.Format("{0:X}", bytes[i]);
    1192         //        if (fenge && (i != bytes.Length - 1))
    1193         //        {
    1194         //            str += string.Format("{0}", " ");
    1195         //        }
    1196         //    }
    1197         //    return str.ToUpper();
    1198         //}
    1199 
    1200         public byte[] ToHex(string s, string charset, bool fenge)
    1201         {
    1202             if ((s.Length % 2) != 0)
    1203             {
    1204                 s += " ";//空格
    1205             }
    1206             System.Text.Encoding chs = System.Text.Encoding.GetEncoding(charset);
    1207             byte[] bytes = chs.GetBytes(s);
    1208             //string str = "";
    1209             //for (int i = 0; i < bytes.Length; i++)
    1210             //{
    1211             //    str += string.Format("{0:X}", bytes[i]);
    1212             //    if (fenge && (i != bytes.Length - 1))
    1213             //    {
    1214             //        str += string.Format("{0}", " ");
    1215             //    }
    1216             //}
    1217             return bytes;
    1218         }
    1219 
    1220         /// <summary>
    1221         /// 16进制转换成汉字
    1222         /// </summary>
    1223         /// <param name="hex"></param>
    1224         /// <param name="charset">编码,如"gb2312","gb2312"</param>
    1225         /// <returns></returns>
    1226         public string UnHex(string hex, string charset)
    1227         {
    1228             if (hex == null)
    1229                 throw new ArgumentNullException("hex");
    1230             hex = hex.Replace(",", "");
    1231             hex = hex.Replace("/n", "");
    1232             hex = hex.Replace("//", "");
    1233             hex = hex.Replace(" ", "");
    1234             if (hex.Length % 2 != 0)
    1235             {
    1236                 hex += "20";//空格
    1237             }
    1238             // 需要将 hex 转换成 byte 数组。 
    1239             byte[] bytes = new byte[hex.Length / 2];
    1240 
    1241             for (int i = 0; i < bytes.Length; i++)
    1242             {
    1243                 try
    1244                 {
    1245                     // 每两个字符是一个 byte。 
    1246                     bytes[i] = byte.Parse(hex.Substring(i * 2, 2),
    1247                     System.Globalization.NumberStyles.HexNumber);
    1248                 }
    1249                 catch
    1250                 {
    1251                     // Rethrow an exception with custom message. 
    1252                     throw new ArgumentException("hex is not a valid hex number!", "hex");
    1253                 }
    1254             }
    1255             System.Text.Encoding chs = System.Text.Encoding.GetEncoding(charset);
    1256             return chs.GetString(bytes);
    1257         }
    1258         #endregion
    1259     }
    1260 }
    View Code

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

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

  • 相关阅读:
    让history命令 显示执行命令的时间
    实现SSH免密登录
    数据库表空间一夜之间爆满 查看最大的表却才几百M 原来是大字段对象CLOB造成的
    Python-集合的操作
    Vim使用技巧
    Linux的内部命令和外部命令
    Redis缓存穿透和雪崩
    网络编程学习一:IP地址转换函数
    每日一问15:C++中的.h,cpp以及.hpp文件
    每日一问14: 缓存和缓冲的区别
  • 原文地址:https://www.cnblogs.com/wsn1203/p/9100007.html
Copyright © 2020-2023  润新知