因为项目需要,第一次接触到了ACR122U NFC读卡器(非接触式)和M1卡,首先介绍一下想要读写应该知道的基本知识。
ACR122U 是一款连机非接触式智能卡读写器,可以读写 ISO 14443-4 A 类和 B 类卡、MIFARE®卡、
ISO18092 卡以及 FeliCa 标签。由于符合 PC/SC 标准,它可以与现有的 PC/SC 应用相兼容。
作为非接触式标签与个人电脑的中间设备,ACR122U 通过 USB 端口与电脑建立连接并执行电脑发出
的指令,从而实现与非接触式标签的通信或者对外围设备(LED 指示灯或蜂鸣器)进行控制。
具体M1卡的介绍,推荐链接:
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