本小組課程設計題目:基於Z32的虛擬機制做與測試c++
本小組成員:redis
這次實驗中我負責的是算法
學習GPIO原理,閱讀《ARM cortex-m0權威手冊》,參考Z32HUA_DEMO工程函數庫(詳見軟件資料),經過設置經過GPIO1,GPIO2,GPIO3串行通訊控制液晶屏,實現字符顯示功能。數組
12864是一種圖形點陣液晶顯示器。它主要採用動態驅動原理由行驅動—控制器和列驅動器兩部分組成了128(列)×64(行)的全點陣液晶顯示。此顯示器採用了COB的軟封裝方式,經過導電橡膠和壓框鏈接LCD,使其壽命長,鏈接可靠。安全
打開12864液晶屏串行顯示實驗工程文件,如圖所示: 併發
12864
的代碼 LCD.c
分析:LCD12864的代碼包括其初始化、設定顯示位置,以及寫數據的函數:框架
- void lcd_sendbyte(UINT8 byte)函數的做用是串行方式發送一個字節;
- void lcd_wcmd(UINT8 cmd) 函數的做用是寫指令操做到LCD12864,包括寫命令,狀態等指令;
- void lcd_wdat(UINT8 dat)函數是寫數據操做,以並行方式從D0~D7向12864寫入顯示數據,先送高4位,再送低4位;
- void lcd_string(UINT8 *str)是寫字符串操做;
- void lcd_init(void)是12864的初始化操做,首先對串行引腳進行初始化,設置Z32的GPIO-1,2,3爲輸出,分別做爲片選、讀寫口和時鐘端口並初始輸出低電平,而後進行LCD的初始化,包括選擇指令集,顯示設置以及屏幕和光標的基本設定;
- void lcd_pos(UINT8 X,UINT8 Y)是設定12864開始顯示的位置。
== LCD.c
源代碼以下:==函數
/*串行發送一個字節 */ /* */ /*******************************************************************/ void lcd_sendbyte(UINT8 byte) { UINT8 i; for(i=0;i<8;i++) { GPIO_SetVal(CLK,0); GPIO_SetVal(SID,byte&0x80); GPIO_SetVal(CLK,1); byte=(byte<<1); } GPIO_SetVal(CLK,0); } /*******************************************************************/ /* */ /*寫指令數據到LCD */ /* */ /*******************************************************************/ void lcd_wcmd(UINT8 cmd) { GPIO_SetVal(CS,1); delay(5); //串行不支持讀操做,不可檢測忙操做,這裏用延時替代 lcd_sendbyte(0xf8); //送入5個連續的「1「,啓動一個週期,11111,RW(0),RS(0),0 lcd_sendbyte(0xf0&cmd); //取高四位,數據分兩次傳送, //每一個字節的內容被送入兩個字節,高四位放在第一個字節的高四位 lcd_sendbyte(0xf0&(cmd<<4)); //低四位放在第二個字節的高四位 GPIO_SetVal(CS,0); } /*******************************************************************/ /* */ /*寫顯示數據到LCD */ /*RS=H,RW=L,E=高脈衝,D0-D7=數據。 */ /* */ /*******************************************************************/ void lcd_wdat(UINT8 dat) { GPIO_SetVal(CS,1); delay(5); lcd_sendbyte(0xfa); lcd_sendbyte(0xf0&dat); lcd_sendbyte(0xf0&(dat<<4)); GPIO_SetVal(CS,0); } /*******************************************************************/ /* */ /*寫字符串到LCD */ /* */ /*******************************************************************/ void lcd_string(UINT8 *str) { UINT8 *p ; p=str; while(*p!=0) { lcd_wdat(*p++); } } /*******************************************************************/ /* */ /* LCD初始化設定 */ /* */ /*******************************************************************/ void lcd_init(void) { /********串行引腳初始化*******/ GPIO_InOutSet(CS,0); //設置GPIO 1,2,3爲輸出 GPIO_InOutSet(SID,0); GPIO_InOutSet(CLK,0); /********lcd初始化*******/ delay(50); //等待時間要大於40ms lcd_wcmd(0x30); //選擇基本指令集 delay(3); lcd_wcmd(0x0c); //開顯示,無遊標,不反白 delay(3); lcd_wcmd(0x01); //清除顯示屏幕,把DDRAM位址計數器調整爲00H delay(3); lcd_wcmd(0x06); //設定光標右移,總體顯示不移動 delay(3); } /*********************************************************/ /* */ /* 設定顯示位置 */ /* */ /*********************************************************/ void lcd_pos(UINT8 X,UINT8 Y) { UINT8 pos; if (X==0) {X=0x80;} else if (X==1) {X=0x90;} else if (X==2) {X=0x88;} else if (X==3) {X=0x98;} pos = X+Y ; lcd_wcmd(pos); //顯示地址 }
==主函數main.c源代碼以下:==工具
int main(void) { /*********************此段代碼勿動***********************/ //系統中斷向量設置,使能全部中斷 SystemInit (); // 返回boot條件 if(0 == GPIO_GetVal(0)) { BtApiBack(0x55555555, 0xAAAAAAAA); } /*********************此段代碼勿動***********************/ lcd_init(); while(1) { lcd_pos(0,0);//定位第一行 lcd_string("歡迎使用Z32HUA!"); delay(1800); lcd_pos(1,0);//定位第二行 lcd_string("LCD12864液晶測試"); delay(1800); lcd_pos(2,0);//定位第三行 lcd_string("1.2.3.4.5.6.7.8."); delay(1800); lcd_pos(3,0);//定位第四行 lcd_string("A.B.C.D.E.F.G..H."); delay(1800); lcd_wcmd(0x01);//清屏 } } //延時函數,當系統時鐘爲內部OSC時鐘時,延時1ms void delay(int ms) { int i; while(ms--) { for(i=0;i<950;i++) ; } }
一、打開「Z32開發指南\實驗3-12864液晶屏串行顯示」目錄的工程文件。編譯工程,產生後綴名爲.bin的可執行代碼。下圖爲編譯成功的截圖: 性能
二、將實驗箱接入電源,用USB公對公線將實驗箱的USB接口鏈接到電腦的USB接口上,在電腦上找到「Z32開發指南\2.軟件資料\Z32下載調試工具」目錄打開Z32下載調試工具NZDownloadTool.exe。以下圖所示:
三、打開Z32的電源開關前,按住Reboot按鍵不放,兩次打開電源開關,Z32便可被電腦識別,進行下載調試。下圖中設備已鏈接:
四、當左邊框出現「1設備已鏈接」,設備選擇中顯示芯片型號,此時就能夠下載程序了。點擊「下載」,左邊狀態提示框更新顯示「程序下載成功!」實驗3的程序就下載進Z32的實驗板上了。
五、實驗3的內容是LCD12864液晶屏的顯示操做。 關閉Z32電源開關,再打開,程序自動運行,此時能夠看到實驗現象:屏幕上依次顯示如下字符: 「歡迎使用Z32HUA! LCD12864液晶測試 1.2.3.4.5.6.7.8. A.B.C.D.E.F.G.H.」 其中行與行之間顯示的間隔時間約爲1.8s,四行字符所有顯示完成後清屏幕,從新循環顯示。以下圖所示:
閱讀SLE4428 IC數據手冊,學習SLE4428邏輯加密卡操做原理,閱讀《ARM cortex-m0權威手冊》(詳見目錄Z32開發指南\3.參考資料),參考Z32HUA_DEMO工程函數庫(詳見Z32開發指南\2.軟件資料),經過Z32安全模塊對SLE4428 IC卡進行數據讀寫實驗。
邏輯加密存儲器卡:在非加密存儲器卡的基礎上增長了加密邏輯電路,加密邏輯電路經過校驗密碼方式來保護卡內的數據對於外部訪問是否開放,但只是低層次的安全保護,沒法防範惡意性的攻擊。
本實驗所用IC卡:
SLE4428是SIMENS公司設計的邏輯加密IC卡,容量爲1K*8Bit,設有兩個字節的密碼。只有經過了密碼驗證,才能夠對IC卡內的沒有設置寫/擦除保護的內容進行寫/擦除。內部有錯誤計數器(EC),錯誤計數器老是能夠被寫的,若是連續8次教研密碼不成功,IC卡將自動被鎖死,數據只能獨處,不可再對數據進行寫/擦除操做,也不能夠再校驗密碼。每一個字節均可以單獨的設置寫/擦除保護,一單設置了寫/擦除保護功能,這個字節的數據就不能在寫/擦除了,並且寫保護功能只能設置一次。除了密碼區,其餘全部字節在任什麼時候候均可以讀出來。
本此實驗例程的詳細程序請打開「Z32開發指南\實驗7-SLE4428邏輯加密卡」目錄文件夾下的工程文件,下面咱們對程序的主要部分作一下簡單的分析。 打開SLE4428邏輯加密卡實驗工程文件,如圖所示:
/** * @函數: SLE4428初始化和復位 * @voltage:電壓值 - 0: 1.8V (默認) * - 1: 3V * - 2: 3.3V * - 3: 5V * @返回: none */ UINT32 SLE4428_InitAndRST(UINT8 voltage) { UINT32 ATR=0; IOM->CRB &= ~(1<<4); //SCC0接口做爲GPIO口 GPIO_InOutSet(8,0); //CLK輸出使能 GPIO_InOutSet(9,0); //RST輸出使能 GPIO_InOutSet(10,0); //IO輸出使能 GPIO_PuPdSel(8,0); //CLK上拉使能 GPIO_PuPdSel(9,0); //RST上拉使能 GPIO_PuPdSel(10,0); //IO上拉使能 GPIO_SetVal(8,0) ; //CLK輸出0 GPIO_SetVal(9,0) ; //RST輸出0 GPIO_SetVal(10,0) ; //IO輸出0 SCU->SCFGVRCARD |= (voltage<<2); //VCARD0配置爲voltage SCU->SCFGVCCACTRL |= (1<<1) ; //使能vCard0電源 /******開始復位******/ GPIO_SetVal(9,1) ; //RST輸出1 GPIO_SetVal(8,1) ; //CLK輸出1 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 GPIO_SetVal(9,0) ; //RST輸出0 GPIO_InOutSet(10,1); //IO輸入使能 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us for(UINT8 i=0;i<32;i++) { GPIO_SetVal(8,1) ; //CLK輸出1 ATR = ATR|(GPIO_GetVal(10)<<i); //獲取應答 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us } return ATR; } /** * @函數:發送命令控制字 * @S: 控制字 * @addr:10位地址 * @Data: 數據 * @返回:none */ void SLE4428_SendCmd(UINT8 S,UINT16 addr,UINT8 Data) { UINT32 CTL=0; //命令控制字(三個字節24位) CTL |= S; //首6位控制字(S5~S0) CTL |= (addr&0x0300)>>2; //地址的A9,A8 CTL |= (addr&0x00FF)<<8; //地址的A7~A0 CTL |= Data<<16; //數據的D7~D0 GPIO_SetVal(8,0) ; //CLK輸出0 GPIO_SetVal(9,1) ; //RST輸出1 GPIO_InOutSet(10,0); //IO輸出使能 for(UINT8 i = 0 ; i < 0x20 ; i++) ; //等待大約40us for(UINT8 i=0;i<24;i++) //輸出三個字節的控制字 { GPIO_SetVal(10,CTL&0x01) ; //IO輸出數據 GPIO_SetVal(8,1) ; //CLK輸出1 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us CTL = CTL>>1; } GPIO_SetVal(9,0) ; //RST輸出0 GPIO_InOutSet(10,1); //IO輸入使能 } /** * @函數:讀取一個字節 * @addr:10位地址 * @返回:讀取的數據 */ UINT8 SLE4428_ReadByte(UINT16 addr) //輸入10位地址 { UINT8 Data=0; /*****命令001110(讀8位,無保護位)*****/ SLE4428_SendCmd(0x0E,addr,0); /*****過濾接收前的脈衝*****/ GPIO_SetVal(8,1) ; //CLK輸出1 for(UINT8 i = 0 ; i < 0x20 ; i++) ; //等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ; //等待大約40us /*****正式接收一個字節*****/ for(UINT8 i=0;i<8;i++) { GPIO_SetVal(8,1) ; //CLK輸出1 Data = Data|(GPIO_GetVal(10)<<i); //讀取數據 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us } return Data; } /** * @函數:讀取數據 * @addr:10位地址 * @str:1數組首地址 * @n: 讀取長度 * @返回:None */ void SLE4428_ReadData(UINT16 addr,UINT8* str,UINT8 n) { /*****命令001110(讀8位,無保護位)*****/ SLE4428_SendCmd(0x0E,addr,0); /*****過濾接收前的脈衝*****/ GPIO_SetVal(8,1) ; //CLK輸出1 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us /*****正式接收一個字節*****/ for(UINT8 j=0;j<n;j++) { *(str+j) = 0; for(UINT8 i=0;i<8;i++) { GPIO_SetVal(8,1) ; //CLK輸出1 *(str+j) = *(str+j)|(GPIO_GetVal(10)<<i); //讀取數據 for(UINT8 i = 0 ; i < 0x20 ; i++) ; //等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ; //等待大約40us } } } /** * @函數:驗證密碼(地址爲0x03FE,0x03FF) * @PSC1: 第一個字節 * @PSC2: 第二個字節 * @返回:0->驗證失敗,1->驗證成功 */ BOOL SLE4428_PassWord(UINT8 PSC1,UINT8 PSC2) { /*****第一步,寫錯誤寄存器*****/ //命令:110010,地址:0x03FD,數據:讀取該地址的數據右移1位 SLE4428_SendCmd(0x32,0x03FD,(SLE4428_ReadByte(0x03FD)>>1)); //給103個脈衝完成寫操做 for(UINT8 i=0;i<103;i++) { GPIO_SetVal(8,1) ; //CLK輸出1 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us } /********第二步:驗證PSC1*******/ //命令:001101,地址:0x03FE,數據:PSC1 SLE4428_SendCmd(0x0D,0x03FE,PSC1); //給2個脈衝完成操做 for(UINT8 i=0;i<2;i++) { GPIO_SetVal(8,1) ; //CLK輸出1 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us } /********第三步:驗證PSC2*******/ //命令:001101,地址:0x03FF,數據:PSC2 SLE4428_SendCmd(0x0D,0x03FF,PSC2); //給2個脈衝完成操做 for(UINT8 i=0;i<2;i++) { GPIO_SetVal(8,1) ; //CLK輸出1 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us } /********第四步:擦除錯誤計數器*******/ SLE4428_SendCmd(0x33,0x03FD,0xFF); //命令:110011,地址:0x03FD,數據:0xFF //給103個脈衝完成寫操做 for(UINT8 i=0;i<103;i++) { GPIO_SetVal(8,1) ; //CLK輸出1 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us } if(SLE4428_ReadByte(0x03FD)==0xFF) return 1; return 0; } /** * @函數:寫一個字節 * @addr:10位地址 * @Byte: 要寫的數據 * @返回:none */ void SLE4428_Write_Byte(UINT16 addr,UINT8 Byte) { SLE4428_SendCmd(0x33,addr,Byte); //給103個脈衝完成寫操做 for(UINT8 i=0;i<103;i++) { GPIO_SetVal(8,1) ; //CLK輸出1 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us GPIO_SetVal(8,0) ; //CLK輸出0 for(UINT8 i = 0 ; i < 0x20 ; i++) ;//等待大約40us } } /** * @函數:接口釋放,電源下電 * @返回:none */ void SLE4428_Deactivation(void) { GPIO_InOutSet(10,0); //IO輸出使能 GPIO_SetVal(8,0) ; //CLK輸出0 GPIO_SetVal(9,0) ; //RST輸出0 GPIO_SetVal(10,0) ; //IO輸出0 SCU->SCFGVCCACTRL &= ~(1<<1) ;//失能vCard0電源 SCU->CARD0VCTRL &= ~(1<<0); }
==下面介紹主函數,代碼以下:==
int main(void) { /*********************此段代碼勿動***********************/ //系統中斷向量設置,使能全部中斷 SystemInit (); // 返回boot條件 if(0 == GPIO_GetVal(0)) { BtApiBack(0x55555555, 0xAAAAAAAA); } /*********************此段代碼勿動***********************/ /*初始化IC卡插入檢測IO口GPIO6*/ GPIO_Config(6); GPIO_PuPdSel(6,0); //上拉 GPIO_InOutSet(6,1); //輸入 UART_Init(); lcd_init(); KEY_Init(); lcd_pos(0,0);//定位第一行 lcd_string("SLE4428 實驗!"); A: while(1) { lcd_pos(1,0);//定位第二行 lcd_string("請插入IC卡. "); delay(1000); if(GPIO_GetVal(6)==0) break; lcd_pos(1,0);//定位第二行 lcd_string("請插入IC卡.. "); delay(1000); if(GPIO_GetVal(6)==0) break; lcd_pos(1,0);//定位第二行 lcd_string("請插入IC卡..."); delay(1000); if(GPIO_GetVal(6)==0) break; } if(SLE4428_InitAndRST(2)!=0xFFFFFFFF) //收到ATR { lcd_pos(1,0);//定位第二行 lcd_string("已插入SLE4428"); } else { lcd_pos(1,0);//定位第二行 lcd_string("卡不正確 "); SLE4428_Deactivation(); //下電,去激活 delay(1000); goto A; } lcd_pos(2,0);//定位第三行 lcd_string("用戶代碼爲:"); SLE4428_ReadData(0x15,UserCode,6); //讀取用戶代碼 lcd_pos(3,0);//定位第四行 for(UINT8 i=0;i<6;i++) lcd_Hex(UserCode[i]) ; while(KEY_ReadValue()!='A'); //等待A鍵按下 lcd_wcmd(0x01);//清屏 lcd_pos(0,0);//定位第一行 lcd_string("按-A鍵校驗密碼"); lcd_pos(1,0);//定位第二行 lcd_string("校驗0xFF,0xFF"); while(KEY_ReadValue()!='A'); //等待A鍵按下 lcd_pos(2,0);//定位第三行 if(SLE4428_PassWord(0xFF,0xFF)==1) lcd_string("校驗成功"); else lcd_string("校驗失敗"); lcd_pos(3,0);//定位第四行 switch(SLE4428_ReadByte(0x03fd)) //查看剩餘密碼驗證機會 { case 0xff: lcd_string("剩餘機會: 8次");break; case 0x7f: lcd_string("剩餘機會: 7次");break; case 0x3f: lcd_string("剩餘機會: 6次");break; case 0x1f: lcd_string("剩餘機會: 5次");break; case 0x0f: lcd_string("剩餘機會: 4次");break; case 0x07: lcd_string("剩餘機會: 3次");break; case 0x03: lcd_string("剩餘機會: 2次");break; case 0x01: lcd_string("剩餘機會: 1次");break; case 0x00: lcd_string("剩餘機會: 0次");break; default: break; } while(KEY_ReadValue()!='A'); //等待A鍵按下 lcd_wcmd(0x01);//清屏 B: lcd_pos(0,0);//定位第一行 lcd_string("金額:"); Money=SLE4428_ReadByte(0x10); lcd_wdat(0x30+Money/100); lcd_wdat(0x30+Money%100/10); lcd_wdat(0x30+Money%10); lcd_pos(1,0);//定位第一行 lcd_string("輸入金額,A鍵修改"); lcd_pos(2,0);//定位第三行 for(UINT8 j=0;j<3;j++) { do { delay(5); C = KEY_ReadValue(); } while(KeyFlag != 2); //直到按下數字鍵,KeyFlag爲2是表明數字。 lcd_wdat(C); money[j] = C-0x30; } while(KEY_ReadValue()!='A'); //等待A鍵按下 Money = money[0]*100+money[1]*10+money[2]; if(Money>=255) Money = 255; SLE4428_Write_Byte(0x10,Money); lcd_wcmd(0x01);//清屏 goto B; SLE4428_Deactivation(); //下電,去激活,實驗結束 while(1) { } } //延時函數,當系統時鐘爲內部OSC時鐘時,延時1ms void delay(int ms) { int i; while(ms--) { for(i=0;i<950;i++) ; } }
一、打開「Z32開發指南\實驗7-SLE4428邏輯加密卡」目錄的工程文件。編譯工程,產生後綴名爲.bin的可執行代碼。 二、將實驗箱接入電源,用USB公對公線將實驗箱的USB接口鏈接到電腦的USB接口上,在電腦上找到「Z32開發指南\2.軟件資料\Z32下載調試工具」目錄打開Z32下載調試工具NZDownloadTool.exe。 三、打開Z32的電源開關前,按住Reboot按鍵不放,兩次打開電源開關,Z32便可被電腦識別,進行下載調試。 四、當左邊框出現「1設備已鏈接」,設備選擇中顯示芯片型號,此時就能夠下載程序了。
五、點擊「下載」,左邊狀態提示框更新顯示「程序下載成功!」實驗7的程序就下載進Z32的實驗板上了。
實驗7的內容是SLE4428邏輯加密卡實驗,按照程序提示,插入SLE4428邏輯加密卡,A段程序顯示用戶代碼並進行密碼校驗,B段程序讀取卡片存儲的金額信息並修改金額。
關閉Z32電源開關,再打開,程序自動運行,此時能夠看到實驗現象:顯示屏第一行顯示「SLE4428實驗!」,第二行顯示「請插入IC卡...」。
插入SLE4428 IC卡,顯示屏第三行顯示:「用戶代碼爲:」,第四行顯示用戶代碼「D27600000400」。
若插入了正確的卡片,顯示出用戶代碼,再按下矩陣鍵盤的「A」鍵,屏幕第一行顯示提示「按-A鍵校驗密碼」並在第二行顯示兩個字節的校驗密碼「校驗0xFF,0xFF」。
按下矩陣鍵盤的「A」鍵,屏幕第三行顯示「校驗成功」,第四行顯示校驗剩餘機會「剩餘機會:8次」。
再按下矩陣鍵盤的「A」鍵,則屏幕第一行顯示卡內金額數「金額:100」,第二行提示「輸入金額,A鍵修改」。
在矩陣鍵盤上輸入三位修改的金額數560,按下矩陣鍵盤的「A」鍵確認。發現修改變爲了255,這是由於程序中寫不容許大於255,若是大於只顯示255.
可是能夠修改成小於255的值,好比輸入200試試,確認後,金額更新,屏幕上顯示更改後的卡內金額「金額200」,第四行繼續提示「輸入金額,A鍵修改」,能夠再次進行更改。
修改完金額後,就能夠拔出IC卡,實驗結束。
學習SM1加密原理,閱讀《ARM cortex-m0權威手冊》和《Z32HUA國密算法庫用戶手冊》(詳見目錄Z32開發指南\3.參考資料),參考Z32HUA_DEMO工程函數庫(詳見Z32開發指南\2.軟件資料),調用SM1加解密函數,實現對SLE4428 IC的數據加解密操做。
國密SM1(SM1 cryptographic algorithm),國密SM1算法是由國家密碼管理局編制的一種商用密碼分組標準對稱算法。該算法是國家密碼管理部門審批的SM1分組密碼算法,分組長度和密鑰長度都爲128 比特,算法安全保密強度及相關軟硬件實現性能與AES至關,該算法不公開,僅以IP核的形式存在於芯片中。採用該算法已經研製了系列芯片、智能IC卡、智能密碼鑰匙、加密卡、加密機等安全產品,普遍應用於電子政務、電子商務及國民經濟的各個應用領域(包括國家政務通、警務通等重要領域)。
本此實驗例程的詳細程序請打開「Z32開發指南\實驗8-SM1」目錄文件夾下的工程文件,下面咱們對程序的主要部分作一下簡單的分析。
打開SM1加解密實驗工程文件,如圖所示:
在user組下分別雙擊Main.c和SLE4428.c,就能夠看到主函數代碼和SLE4428程序的源代碼。其中工程文件目錄的algorithm文件夾包含了Z32HUA_ALG.ALG函數庫,其中包含了國密的加解密算法相關函數庫,SM1加解密函數的調用須要這個庫的支持。 ==打開Main.c,介紹一下主函數,代碼以下:==
UINT8 jiamiqian[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F}; UINT8 jiamimiyue[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F}; UINT8 jiamihou[16]; UINT8 jiemiqian[16],jiemimiyue[16],jiemihou[16]; UINT8 cuowumiyue[16]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; UINT8 UserCode[5]; UINT8 C; int main(void) { /*********************此段代碼勿動***********************/ //系統中斷向量設置,使能全部中斷 SystemInit (); // 返回boot條件 if(0 == GPIO_GetVal(0)) { BtApiBack(0x55555555, 0xAAAAAAAA); } /*********************此段代碼勿動***********************/ /*初始化IC卡插入檢測IO口GPIO6*/ GPIO_Config(6); GPIO_PuPdSel(6,0); //上拉 GPIO_InOutSet(6,1); //輸入 UART_Init(); lcd_init(); KEY_Init(); lcd_pos(0,0);//定位第一行 lcd_string("SLE4428 實驗!"); A: while(1) { lcd_pos(1,0);//定位第二行 lcd_string("請插入IC卡. "); delay(1000); if(GPIO_GetVal(6)==0) break; lcd_pos(1,0);//定位第二行 lcd_string("請插入IC卡.. "); delay(1000); if(GPIO_GetVal(6)==0) break; lcd_pos(1,0);//定位第二行 lcd_string("請插入IC卡..."); delay(1000); if(GPIO_GetVal(6)==0) break; } if(SLE4428_InitAndRST(2)!=0xFFFFFFFF) //收到ATR { lcd_pos(1,0);//定位第二行 lcd_string("已插入SLE4428"); } else { lcd_pos(1,0);//定位第二行 lcd_string("卡不正確 "); SLE4428_Deactivation(); //下電,去激活 delay(1000); goto A; } lcd_pos(2,0);//定位第三行 lcd_string("用戶代碼爲:"); SLE4428_ReadData(0x15,UserCode,6); //讀取用戶代碼 lcd_pos(3,0);//定位第四行 for(UINT8 i=0;i<6;i++) lcd_Hex(UserCode[i]) ; while(KEY_ReadValue()!='A'); //等待A鍵按下 lcd_wcmd(0x01);//清屏 lcd_pos(0,0);//定位第一行 lcd_string("按-A鍵校驗密碼"); lcd_pos(1,0);//定位第二行 lcd_string("校驗0xFF,0xFF"); while(KEY_ReadValue()!='A'); //等待A鍵按下 lcd_pos(2,0);//定位第三行 if(SLE4428_PassWord(0xFF,0xFF)==1) lcd_string("校驗成功"); else {lcd_string("校驗失敗"); return 0;} lcd_pos(3,0);//定位第四行 switch(SLE4428_ReadByte(0x03fd)) //查看剩餘密碼驗證機會 { case 0xff: lcd_string("剩餘機會: 8次");break; case 0x7f: lcd_string("剩餘機會: 7次");break; case 0x3f: lcd_string("剩餘機會: 6次");break; case 0x1f: lcd_string("剩餘機會: 5次");break; case 0x0f: lcd_string("剩餘機會: 4次");break; case 0x07: lcd_string("剩餘機會: 3次");break; case 0x03: lcd_string("剩餘機會: 2次");break; case 0x01: lcd_string("剩餘機會: 1次");break; case 0x00: lcd_string("剩餘機會: 0次");break; default: break; } while(KEY_ReadValue()!='A'); //等待A鍵按下 B: lcd_wcmd(0x01);//清屏 lcd_pos(0,0);//定位第一行 lcd_string("加密解密實驗"); lcd_pos(1,0);//定位第二行 lcd_string("1.加密"); lcd_pos(2,0);//定位第三行 lcd_string("2.解密"); do { C=KEY_ReadValue(); } while(C!='1'&&C!='2'); //等待1或2鍵按下 lcd_wcmd(0x01);//清屏 if(C=='1') goto jiami; else if(C=='2') goto jiemi; else ; jiami: lcd_pos(0,0);//定位第一行 lcd_string("觀看串口調試助手"); lcd_pos(1,0);//定位第二行 lcd_string("A 鍵確認加密"); UART_SendString("將加密如下數據:\r\n"); for(UINT8 i=0;i<16;i++) { UART_SendHex(jiamiqian[i]); } UART_SendString("\r\n"); UART_SendString("加密密鑰:\r\n"); for(UINT8 i=0;i<16;i++) { UART_SendHex(jiamimiyue[i]); } UART_SendString("\r\n"); while(KEY_ReadValue()!='A'); //等待A鍵按下 SM1_Init(jiamimiyue); //SM1初始化 SM1_Crypto(jiamiqian, 16, 0, 0, 0,jiamihou); //進行加密 SM1_Close(); //關閉安全模塊 UART_SendString("加密後的數據:\r\n"); for(UINT8 i=0;i<16;i++) { UART_SendHex(jiamihou[i]); } UART_SendString("\r\n"); lcd_pos(2,0);//定位第三行 lcd_string("加密完成"); lcd_pos(3,0);//定位第四行 lcd_string("A 鍵存入IC卡"); while(KEY_ReadValue()!='A'); //等待A鍵按下 for(UINT8 i=0;i<16;i++) { SLE4428_Write_Byte(0x20+i,jiamihou[i]); //設置IC卡 0x20地址爲存儲加密數據的地址 } UART_SendString("已將數據寫入IC卡。\r\n"); UART_SendString("\r\n"); goto B; jiemi: lcd_pos(0,0);//定位第一行 lcd_string("觀看串口調試助手"); lcd_pos(1,0);//定位第二行 lcd_string(" A鍵讀取IC卡數據"); while(KEY_ReadValue()!='A'); //等待A鍵按下 SLE4428_ReadData(0x20,jiemiqian,16); UART_SendString("讀取的數據爲:\r\n"); for(UINT8 i=0;i<16;i++) { UART_SendHex(jiemiqian[i]); } UART_SendString("\r\n"); lcd_wcmd(0x01);//清屏 lcd_pos(0,0);//定位第一行 lcd_string("讀取成功"); lcd_pos(1,0);//定位第二行 lcd_string("選擇密鑰解密:"); lcd_pos(2,0);//定位第三行 lcd_string("1.正確密鑰"); lcd_pos(3,0);//定位第四行 lcd_string("2.錯誤密鑰"); do { C=KEY_ReadValue(); } while(C!='1'&&C!='2'); //等待1或2鍵按下 lcd_wcmd(0x01);//清屏 if(C=='1') { for(UINT8 i=0;i<16;i++) jiemimiyue[i] = jiamimiyue[i]; } else if(C=='2') { for(UINT8 i=0;i<16;i++) jiemimiyue[i] = cuowumiyue[i]; } else ; UART_SendString("將使用如下密鑰進行解密:\r\n"); for(UINT8 i=0;i<16;i++) { UART_SendHex(jiemimiyue[i]); } UART_SendString("\r\n"); lcd_pos(0,0);//定位第一行 lcd_string("A 鍵確認解密"); while(KEY_ReadValue()!='A'); //等待A鍵按下 SM1_Init(jiemimiyue); //SM1初始化 SM1_Crypto(jiemiqian, 16, 1, 0, 0,jiemihou); //進行解密 SM1_Close(); //關閉安全模塊 lcd_pos(1,0);//定位第二行 lcd_string("解密完成"); lcd_pos(2,0);//定位第三行 lcd_string("A 鍵返回"); UART_SendString("解密後的數據爲:\r\n"); for(UINT8 i=0;i<16;i++) { UART_SendHex(jiemihou[i]); } UART_SendString("\r\n"); UART_SendString("\r\n"); while(KEY_ReadValue()!='A'); //等待A鍵按下 goto B; SLE4428_Deactivation(); //下電,去激活,實驗結束 while(1) { } } //延時函數,當系統時鐘爲內部OSC時鐘時,延時1ms void delay(int ms) { int i; while(ms--) { for(i=0;i<950;i++) ; } }
加密程序段:
解密程序段:
一、打開「Z32開發指南\實驗8-SM1」目錄的工程文件。編譯工程,產生後綴名爲.bin的可執行代碼。 二、下載程序。 三、實驗8的內容是SM1加解密實驗,待加密的原始數據以及加密祕鑰已經內置到程序中,修改UINT8 jiamiqian[16]數組便可更換待加密數據,修改jiamimiyue[16]數組和cuowumiyue[16]便可修改正確和錯誤的加密密鑰。 四、本實驗一樣使用SLE4428 IC卡做爲加解密介質,按照程序提示,插入SLE4428邏輯加密卡,A段程序顯示用戶代碼並進行密碼校驗,B段程序進行加密/解密選擇,加密程序段進行SM1加密並將加密先後數據經過串口發送至PC機,解密程序段進行SM1解密並將解密先後數據經過串口發送至PC機。 五、咱們用9針串口線將Z32模塊的串口與電腦USB接口鏈接。 六、若是發現鏈接9針串口線後虛擬機仍然沒有反應,能夠在虛擬機中進行鏈接設置,確保虛擬機與Z32芯片正常鏈接。以下圖即爲鏈接成功。
七、首先在電腦上打開串口助手,選擇對應的串口號,設置波特率爲115200,偶校驗(Even),而後打開串口。 八、若是不清楚串口號選擇,可在設備查看器中查看。以下圖:
九、關閉Z32電源開關,再打開,程序自動運行,此時能夠看到實驗現象:顯示屏顯示「SLE4428實驗!請插入IC卡...」。 十、插入SLE4428 IC卡,顯示屏第三行顯示:「用戶代碼爲:」,第四行顯示用戶代碼「D27600000400」。 十一、若是插入錯誤的卡片,則顯示屏第二行顯示:「卡不正確」。 十二、若插入了正確的卡片,顯示出用戶代碼,再按下矩陣鍵盤的「A」鍵,屏幕第一行顯示提示「按-A鍵校驗密碼」並在第二行顯示兩個字節的校驗密碼「校驗0xFF,0xFF」。 1三、按下矩陣鍵盤的「A」鍵,屏幕第三行顯示「校驗成功」,第四行顯示校驗剩餘機會「剩餘機會:8次」。 1四、再按下矩陣鍵盤的「A」鍵,則屏幕第一行顯示「加密解密實驗」,第2、三行分別顯示選項「1.加密」,「2.解密」。
1五、首先進行加密實驗。按「1」鍵選擇加密,屏幕第一行顯示「觀看串口調試助手」,第二行顯示「A鍵確認加密」。此時,串口調試助手顯示原始數據和加密密鑰。
1六、按下「A」鍵確認加密後,屏幕第三行顯示「加密完成」,第四行顯示提示「A鍵存入IC卡」。串口調試助手顯示加密後的數據。
1七、按「A」鍵,將加密數據存入IC卡,此時串口顯示「已將數據寫入IC卡」。屏幕回到加密解密實驗選擇菜單。 1八、下面進行解密實驗。按「2」鍵選擇解密實驗後屏幕顯示「觀看串口調試助手 A鍵讀取IC卡數據」。
1九、按「A」鍵後,此時屏幕顯示「讀取成功 選擇密鑰解密:1.正確密鑰 2.錯誤密鑰」。串口顯示「讀取的數據:爲:0x7E 0xDC 0xA3 0x7B 0xBA 0x53 0x84 0xAC 0x0B 0x75 0x50 0x45 0x2E 0xEC 0x4F 0x4F」。
20、按「1」鍵選擇正確的密鑰後,屏幕提示「A鍵確認解密」,此時串口顯示「將使用如下密鑰進行解密:0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F」。
2一、按「A」 鍵確認解密後,屏幕提示「解密完成 A鍵返回」,此時串口顯示「解密後的數據爲:0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F」。
2二、按「A」鍵返回加/解密選擇菜單。
一、破解軟件MDK4.74過程當中遇到了錯誤提示: **錯誤緣由:**因爲沒有用管理員權限運行該軟件,致使了沒法成功破解。 **解決方案:**右鍵,以管理員身份運行該軟件,再試一次便可成功。
成功截圖:
二、實驗二程序代碼編譯時遇到錯誤,發現了11個error,沒法運行。 **錯誤緣由:**沒有更新c++ redistributable packet 運行庫,致使找不到頭文件stdint.h。 **解決方案:**安裝DirectX修復工具,並檢測且修復。
成功截圖:
三、將Z32模塊連進虛擬機中,沒法連進虛擬機時,能夠根據提示選擇虛擬機
->可移動設備
。選擇Z32HUA-BOOT
來,鏈接到Z32。
四、串口選擇不能選擇錯誤,若是選擇COM1
的話,打開串口
以後,仍然沒法成功。串口沒法顯示內容。
COM5
,串口選擇相應的COM5
,再打開時,能夠成功。