本例應用場合:對IC卡的讀寫、加密,個人及各企事業單位可以根據自己的加密方式對卡片進行處理后使用。本例在VS2010及以上編譯環境中測試通過。
運行界面:
想調試你得有這些:
德卡D3非接觸式IC卡讀寫器(USB免驅)
IC芯片卡
D3 SDK
在操作之前先了解一下IC卡的一些基礎知識(本例以M1卡為例):
M1卡有16個扇區,即0到15扇區,每個扇區4塊,每塊16個字節,以塊為存取單位,要讀取扇區中的數據,首先要進行密碼校驗(校驗讀卡設備中的密碼和卡上的密碼);要讀取哪個扇區的數據就要校驗哪個扇區的密碼,dc_read或dc_read_hex方法是用的地址是絕對地址(每個扇區4個地址,16個扇區共64個地址,即0到63),校驗完0扇區的密碼后,能讀取0到3地址上的數據,校驗完1扇區的密碼后,能讀取4到7地址上的數據,以此類推。假設扇區號是 sNo,數據塊號是dNo,則:sNo號扇區的最小區塊號為:4 * sNo,最大區塊號為:4 * sNo + 3。
存儲結構
第0扇區的塊0(即絕對地址0塊),它用於存放廠商代碼,已經固化,不可更改。
每個扇區的塊0、塊1、塊2為數據塊,可用於存貯數據。
每個扇區的塊3為控制塊,包括了密碼A、存取控制、密碼B。具體結構如下:
A0 A1 A2 A3 A4 A5 FF 07 80 69 B0 B1 B2 B3 B4 B5
對IC卡操作的基本步驟:
初始化InitIC() -> 尋卡ReadIc() -> 校驗密碼getKeys(string cardID) -> 加密操作LoadKeysToCard(string cardID) -> 關閉串口ExitIC()。
本例測試用卡片的特定加密方式:
- 卡號+“ZMATRIX”+扇區號。
- 經MD5加密后取前12位字符形成字符串。
- 對字符串進行BCD碼加密。
- 組合秘鑰形成完整控制塊數據。
- 寫入卡片進行加密。
核心函數的代碼:
1 /// <summary> 2 /// 尋卡 3 /// </summary> 4 /// <returns>物理卡號</returns> 5 public string ReadIc() 6 { 7 uint st = 4; 8 ulong icCardNo = 0; 9 char str = (char)0; 10 string cardID = ""; 11 int card = dc_card((Int16)_icdev, str, ref icCardNo); 12 if(card == 0) 13 { 14 string strCardID = Ten2Hex(icCardNo); 15 cardID = FormatCardID(String.Format("{0:X}", strCardID)); 16 cardUniID = cardID; 17 MessageBox.Show("尋卡成功!"); 18 } 19 else{ 20 MessageBox.Show("尋卡失敗!"); 21 } 22 return cardID;//16進制 23 }
1 /// <summary> 2 /// 獲取各扇區對應秘鑰,核心函數 3 /// </summary> 4 /// <param name="cardID">卡物理號</param> 5 private void getKeys(string cardID) 6 { 7 int len = 16; 8 byte[] bMoren = { 255, 255, 255, 255, 255, 255 }; 9 byte[] bKey = new byte[6]; 10 byte[] bData = new byte[16]; 11 string[] befEncrypt = new string[len]; 12 string[] aftEncrypt = new string[len]; 13 for(int sector = 0 ; sector < len ; sector++) 14 { 15 befEncrypt[sector] = cardID + "ZMATRIX" + sector.ToString(); 16 aftEncrypt[sector] = MD5.MD5Encrypt(befEncrypt[sector], 32).Substring(0, 12); 17 bKey = BCDEncrypt.str2Bcd(aftEncrypt[sector]); 18 int checkNum = dc_authentication_passaddr(_icdev, 4, (sector * 4 + 3), bKey); 19 if (checkNum == 0) 20 { 21 MessageBox.Show("驗證第" + (sector * 4 + 3) + "塊密碼成功!"); 22 int readData = dc_read(_icdev, sector * 4 + 3, bData); 23 }else{ 24 MessageBox.Show("驗證第" + (sector * 4 + 3) + "塊密碼失敗!"); 25 } 26 } 27 }
1 /// <summary> 2 /// 新卡加密,核心函數 3 /// </summary> 4 /// <param name="cardID">新卡序列號(物理卡號)</param> 5 private void LoadKeysToCard(string cardID) 6 { 7 byte[] bKey = new byte[6]; 8 string[] befEncrypt = new string[16]; 9 string[] aftEncrypt = new string[16]; 10 byte[] bMoren = { 255, 255, 255, 255, 255, 255 }; 11 lbl = getLabel();//Label集 12 lblTips.Text = ""; 13 for (int sector = 0; sector < 16; sector++) 14 { 15 int checkNum = dc_authentication_passaddr(_icdev, 4, (sector * 4 + 3),bMoren); 16 if (checkNum == 0) 17 { 18 befEncrypt[sector] = cardID + "ZMATRIX" + sector.ToString(); 19 aftEncrypt[sector] = MD5.MD5Encrypt(befEncrypt[sector], 32).Substring(0, 12); 20 bKey = BCDEncrypt.str2Bcd(aftEncrypt[sector]); 21 int writeOk = dc_write(_icdev, (sector * 4 + 3), CombineKey(bKey)); 22 if (writeOk == 0) 23 { 24 tip[sector] = 0; 25 }else{ 26 tip[sector] = 1; 27 } 28 }else{ 29 tip[sector] = 1; 30 lblTips.Text = "失敗:【該卡可能已加密】"; 31 lblTips.ForeColor = Color.Red; 32 } 33 } 34 Set_Text = new set_Text(set_LalColor); 35 thread1 = new Thread(new ThreadStart(run)); 36 thread1.Start(); 37 }
源碼下載:關注公眾號『幾行簡碼』,回復【讀卡】即可獲取免費下載鏈接。
原創文章,轉載請務必先查閱公眾號內【轉載須知】。