因为项目需要,第一次接触到了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 }
这个是可以写入中文的,思路大概是这样,先把中文转成base64,然后把base64格式的再转成byte[]。
完整的demo下载地址:https://github.com/wsn931203/DemoDataToNFCCard.git