使用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("\n");
 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

猜你喜欢

转载自www.cnblogs.com/wsn1203/p/9100007.html