1. 程式人生 > >大結局---Miracl庫下完全實現SM2加密演算法

大結局---Miracl庫下完全實現SM2加密演算法

 本次博文以前面的兩次文章的函式定義、說明為基礎進行擴充套件。

  並且參考了一些其他的優秀部落格文章,比如KDF區域性金鑰派生函式的使用、十六進位制字串與二進位制字串以及普通字串轉換函式(自己也編寫了一部分函式)、SM3雜湊簽名演算法(太懶了,完全拿來用了,取其精華,感謝部落格主人)。

  完成本次實驗前,進一步瞭解了C語言,這種直接面對記憶體進行操作的語言真的既讓人愛又讓人恨……

  然後,介紹一下我實現本演算法的大概思路:從檔案讀入等待加密的明文,然後以二進位制字串形式(字元陣列,定義了很多中間變數,做好準備吧)構造密文,中間還涉及十六進位制形式的字串,因為我需要把字串轉成16進位制再轉成二進位制,並且中間有很多操作也和十六進位制形式有關。

   最後,強調一下定義的這些函式都是對字元陣列進行,然後把結果填充到另一個指定地址去,這種思想伴隨了整個程式中……


 sm3標頭檔案程式碼(參考與網址 https://blog.csdn.net/a344288106/ article/details/80094878 ):

  1 #include <stdio.h>
  2 #include <memory.h>
  3 #ifndef _SM3_H_
  4 #define _SM3_H_
  5  
  6 /*
  7 * SM3演算法產生的雜湊值大小(單位:位元組)
  8
*/ 9 #define SM3_HASH_SIZE 32 10 11 /* 12 * SM3上下文 13 */ 14 typedef struct SM3Context 15 { 16 unsigned int intermediateHash[SM3_HASH_SIZE / 4]; 17 unsigned char messageBlock[64]; 18 } SM3Context; 19 20 /* 21 * SM3計算函式 22 */ 23 unsigned char *SM3Calc(const unsigned char *message,unsigned int
messageLen, unsigned char digest[SM3_HASH_SIZE]); 24 25 #endif // _SM3_H_ 26 /* 27 * 判斷執行環境是否為小端 28 */ 29 static const int endianTest = 1; 30 #define IsLittleEndian() (*(char *)&endianTest == 1) 31 32 /* 33 * 向左迴圈移位 34 */ 35 #define LeftRotate(word, bits) ( (word) << (bits) | (word) >> (32 - (bits)) ) 36 37 /* 38 * 反轉四位元組整型位元組序 39 */ 40 unsigned int *ReverseWord(unsigned int *word) 41 { 42 unsigned char *byte, temp; 43 44 byte = (unsigned char *)word; 45 temp = byte[0]; 46 byte[0] = byte[3]; 47 byte[3] = temp; 48 49 temp = byte[1]; 50 byte[1] = byte[2]; 51 byte[2] = temp; 52 return word; 53 } 54 55 /* 56 * T 57 */ 58 unsigned int T(int i) 59 { 60 if (i >= 0 && i <= 15) 61 return 0x79CC4519; 62 else if (i >= 16 && i <= 63) 63 return 0x7A879D8A; 64 else 65 return 0; 66 } 67 68 /* 69 * FF 70 */ 71 unsigned int FF(unsigned int X, unsigned int Y, unsigned int Z, int i) 72 { 73 if (i >= 0 && i <= 15) 74 return X ^ Y ^ Z; 75 else if (i >= 16 && i <= 63) 76 return (X & Y) | (X & Z) | (Y & Z); 77 else 78 return 0; 79 } 80 81 /* 82 * GG 83 */ 84 unsigned int GG(unsigned int X, unsigned int Y, unsigned int Z, int i) 85 { 86 if (i >= 0 && i <= 15) 87 return X ^ Y ^ Z; 88 else if (i >= 16 && i <= 63) 89 return (X & Y) | (~X & Z); 90 else 91 return 0; 92 } 93 94 /* 95 * P0 96 */ 97 unsigned int P0(unsigned int X) 98 { 99 return X ^ LeftRotate(X, 9) ^ LeftRotate(X, 17); 100 } 101 102 /* 103 * P1 104 */ 105 unsigned int P1(unsigned int X) 106 { 107 return X ^ LeftRotate(X, 15) ^ LeftRotate(X, 23); 108 } 109 110 /* 111 * 初始化函式 112 */ 113 void SM3Init(SM3Context *context) 114 { 115 context->intermediateHash[0] = 0x7380166F; 116 context->intermediateHash[1] = 0x4914B2B9; 117 context->intermediateHash[2] = 0x172442D7; 118 context->intermediateHash[3] = 0xDA8A0600; 119 context->intermediateHash[4] = 0xA96F30BC; 120 context->intermediateHash[5] = 0x163138AA; 121 context->intermediateHash[6] = 0xE38DEE4D; 122 context->intermediateHash[7] = 0xB0FB0E4E; 123 } 124 125 /* 126 * 處理訊息塊 127 */ 128 void SM3ProcessMessageBlock(SM3Context *context) 129 { 130 int i; 131 unsigned int W[68]; 132 unsigned int W_[64]; 133 unsigned int A, B, C, D, E, F, G, H, SS1, SS2, TT1, TT2; 134 135 /* 訊息擴充套件 */ 136 //printf("擴充套件後的訊息 W0-W67:\n"); 137 for (i = 0; i < 16; i++) 138 { 139 W[i] = *(unsigned int *)(context->messageBlock + i * 4); 140 if (IsLittleEndian()) 141 ReverseWord(W + i); 142 //if((i % 8) == 0) printf("%02d: ",i); 143 //printf(" %08x",W[i]); 144 //if(((i+1) % 8) == 0) printf("\n"); 145 } 146 for (i = 16; i < 68; i++) 147 { 148 W[i] = P1(W[i - 16] ^ W[i - 9] ^ LeftRotate(W[i - 3], 15)) 149 ^ LeftRotate(W[i - 13], 7) 150 ^ W[i - 6]; 151 //if((i % 8) == 0) printf("%02d: ",i); 152 //printf(" %08x", W[i]); 153 //if(((i+1) % 8) == 0) printf("\n"); 154 } 155 //printf("\n擴充套件後的訊息 W'0-W'63:\n"); 156 for (i = 0; i < 64; i++) 157 { 158 W_[i] = W[i] ^ W[i + 4]; 159 //if((i % 8) == 0) printf("%02d: ",i); 160 //printf(" %08x",W_[i]); 161 //if(((i+1) % 8) == 0) printf("\n"); 162 } 163 164 /* 訊息壓縮 */ 165 A = context->intermediateHash[0]; 166 B = context->intermediateHash[1]; 167 C = context->intermediateHash[2]; 168 D = context->intermediateHash[3]; 169 E = context->intermediateHash[4]; 170 F = context->intermediateHash[5]; 171 G = context->intermediateHash[6]; 172 H = context->intermediateHash[7]; 173 //printf("迭代壓縮中間值:\n"); 174 //printf("i A B C D E F G H\n"); 175 //printf(" %08x %08x %08x %08x %08x %08x %08x %08x\n",A,B,C,D,E,F,G,H); 176 for (i = 0; i < 64; i++) 177 { 178 SS1 = LeftRotate((LeftRotate(A, 12) + E + LeftRotate(T(i), i)), 7); 179 SS2 = SS1 ^ LeftRotate(A, 12); 180 TT1 = FF(A, B, C, i) + D + SS2 + W_[i]; 181 TT2 = GG(E, F, G, i) + H + SS1 + W[i]; 182 D = C; 183 C = LeftRotate(B, 9); 184 B = A; 185 A = TT1; 186 H = G; 187 G = LeftRotate(F, 19); 188 F = E; 189 E = P0(TT2); 190 //printf("%02d %08x %08x %08x %08x %08x %08x %08x %08x\n",i,A,B,C,D,E,F,G,H); 191 } 192 context->intermediateHash[0] ^= A; 193 context->intermediateHash[1] ^= B; 194 context->intermediateHash[2] ^= C; 195 context->intermediateHash[3] ^= D; 196 context->intermediateHash[4] ^= E; 197 context->intermediateHash[5] ^= F; 198 context->intermediateHash[6] ^= G; 199 context->intermediateHash[7] ^= H; 200 } 201 202 /* 203 * SM3演算法主函式 204 */ 205 unsigned char *SM3Calc(const unsigned char *message,unsigned int messageLen, unsigned char digest[SM3_HASH_SIZE]) 206 { 207 208 SM3Context context; 209 unsigned int i, remainder, bitLen; 210 /* 初始化上下文 */ 211 SM3Init(&context); 212 213 /* 對前面的訊息分組進行處理 */ 214 for (i = 0; i < messageLen / 64; i++) //i是Bi分組數目(512bits),只有一組則不處理,因為0< 0不成立 215 { 216 memcpy(context.messageBlock, message + i * 64, 64); 217 SM3ProcessMessageBlock(&context); 218 } 219 220 /* 填充訊息分組,並處理 */ 221 bitLen = messageLen * 8; //訊息的位元長度,用於待會的填充 222 if (IsLittleEndian()) 223 ReverseWord(&bitLen); 224 remainder = messageLen % 64; 225 memcpy(context.messageBlock, message + i * 64, remainder); 226 context.messageBlock[remainder] = 0x80; 227 if (remainder <= 55) 228 { 229 memset(context.messageBlock + remainder + 1, 0, 64 - remainder - 1 - 8 + 4); 230 memcpy(context.messageBlock + 64 - 4, &bitLen, 4); //最後四位元組存放資訊長度 231 SM3ProcessMessageBlock(&context); 232 } 233 else 234 { 235 memset(context.messageBlock + remainder + 1, 0, 64 - remainder - 1);//本組餘下的全填零 236 SM3ProcessMessageBlock(&context); 237 memset(context.messageBlock, 0, 64 - 4); 238 memcpy(context.messageBlock + 64 - 4, &bitLen, 4); 239 SM3ProcessMessageBlock(&context); 240 } 241 242 /* 返回結果 */ 243 if (IsLittleEndian()) 244 for (i = 0; i < 8; i++) 245 ReverseWord(context.intermediateHash + i); 246 memcpy(digest,context.intermediateHash, SM3_HASH_SIZE); 247 248 return digest; 249 }


 

下面是KDF函式定義(參考與網址https://blog.csdn.net/heidlyn/article/details/53993002 )

 1 int KDF(const char* cdata, int datalen, int keybitlen, char* retdata)
 2 {
 3     int nRet = -1;
 4     char* hexstring[512]={0};
 5     char* bytestring[256]={0};
 6     unsigned char *pRet;
 7     unsigned char *pData;
 8     unsigned char cdgst[32]={0};
 9     unsigned char cCnt[4] = {0};
10     int nCnt  = 1;
11     int nDgst = 32; 
12     int keybytelen=keybitlen/8; //keybytelen是明文(未來金鑰)的位元組長度
13     int nTimes = (keybytelen+31)/32;
14     int i=0;
15     if(cdata==NULL || datalen<=0 || keybitlen<=0)
16         goto err;
17     if(NULL == (pRet=(unsigned char *)malloc(keybytelen)))
18         goto err;
19     if(NULL == (pData=(unsigned char *)malloc(datalen+4)))
20         goto err;
21     memset(pRet,  0, keybytelen);
22     memset(pData, 0, datalen+4);
23     memcpy(pData, cdata, datalen);
24     for(; i<nTimes; i++)
25     {
26         cCnt[0] =  (nCnt>>24) & 0xFF;
27         cCnt[1] =  (nCnt>>16) & 0xFF;
28         cCnt[2] =  (nCnt>> 8) & 0xFF;
29         cCnt[3] =  (nCnt    ) & 0xFF;
30         memcpy(pData+datalen, cCnt, 4);
31         Bin2Hex(pData,hexstring,datalen+4);//二進位制字串長度為datalen+4
32         Hex2Byte(hexstring,bytestring,datalen/4+1);//十六進位制字串長度為1/4(datalen+4)
33         SM3Calc(bytestring,(datalen+4)/8,cdgst); //字串長度為1/8(datalen+4);應該傳入字串bytestring,而非位元串
34         if(i == nTimes-1) //最後一次計算,根據keybytelen/32是否整除,擷取摘要的值
35             if(keybytelen%32 != 0)
36                 nDgst = keybytelen%32;  
37         memcpy(pRet+32*i, cdgst, nDgst);
38         nCnt ++;  //計數器
39     }
40     bzero(hexstring,sizeof(hexstring));
41     Str2Hex(pRet,hexstring,keybytelen);
42     Hex2Bin(hexstring,retdata,strlen(hexstring));
43     nRet = 0;
44 err:
45     if(pRet)
46         free(pRet);
47     if(pData)
48         free(pData);
49 
50     return nRet;
51 }


 好的,下面就是SM2主函式加解密程式碼:

  1 int main(){  //前面定義很多變數,不再一一介紹,後面用到再提
  2     big a,b,p,Gx,Gy,n,db,k;
  3     big x1,y1,x2,y2;
  4     int kbitlen;
  5     char plain[1024]={0}; //存放檔案中讀取的明文字串
  6     char plain_bin[8192]={0}; //存放明文的二進位制字串
  7     char C2_bin[8192]={0};    //存放解密出明文的二進位制字串
  8     char sm3_dgst[33]={0};  //存放 sm3 32位元組的雜湊摘要
  9     char crypt[3072]={0};   //存放加密生成的密文的二進位制形式
 10     char Hexstring1[65]={0};    
 11     char Hexstring2[65]={0};
 12     char Hexstring3[2048]={0};    
 13     char HexTemp[2048]={0};
 14     char t1[8192]={0};    
 15     char Binarystring1[257]={0};
 16     char Binarystring2[257]={0};    
 17     char Binarystring3[513]={0};
 18     FILE *fp; //存放的檔案存放推薦的引數a、b、p、Gx、Gy、n等等
 19     FILE *input_string;//存放明文
 20     epoint* G=NULL;  //基點G
 21     epoint* Pb=NULL; //公鑰點Pb
 22     epoint* T1=NULL; //點T1(x1,y1)=[k]G
 23     epoint* T2=NULL;    
 24     epoint* D1=NULL;
 25     epoint* D2=NULL;
 26     miracl* mip=mirsys(1000,16);//初始化大數庫
 27     a=mirvar(0);    
 28     b=mirvar(0); 
 29     p=mirvar(0); //p 256 bits
 30     Gx=mirvar(0);    
 31     Gy=mirvar(0);    
 32     n=mirvar(0);
 33     k=mirvar(0);    
 34     db=mirvar(0);//使用者私鑰數字
 35     x1=mirvar(0);    
 36     y1=mirvar(0);    
 37     x2=mirvar(0);    
 38     y2=mirvar(0);
 39     fp=fopen("abp.txt","r+");  //fp指向同目錄下存放參數的檔案
 40     if(fp==0)
 41     {
 42         printf("檔案開啟失敗!");
 43         exit(1);
 44     }
 45     mip->IOBASE=16;//下面依次讀取十六進位制的引數
 46     cinnum(a,fp);    
 47     cinnum(b,fp);    
 48     cinnum(p,fp);    
 49     cinnum(Gx,fp);
 50     cinnum(Gy,fp);
 51     cinnum(n,fp);    
 52     fclose(fp);//關閉引數檔案指標
 53     system("color E");
 54     printf("---------引數生成---------\n");  //列印已知引數
 55     printf("引數a=");    
 56     cotnum(a,stdout);
 57     printf("引數b=");    
 58     cotnum(b,stdout);
 59     printf("有限域素數p=");    
 60     cotnum(p,stdout);
 61     printf("基點橫座標Gx=");
 62     cotnum(Gx,stdout);
 63     printf("基點縱座標Gy=");
 64     cotnum(Gy,stdout);
 65     printf("基點的階n=");    
 66     cotnum(n,stdout); 
 67     bigrand(n,db);           //db<n-1,隨機生成私鑰,然後列印
 68     printf("選取私鑰數字db=");    
 69     cotnum(db,stdout);
 70     ecurve_init(a,b,p,MR_PROJECTIVE);//定義、初始化曲線方程
 71     G=epoint_init();    
 72     Pb=epoint_init();//初始化重要的點
 73     T1=epoint_init();    
 74     T2=epoint_init();
 75     if(epoint_set(Gx,Gy,0,G))  //驗證、生成基點 G
 76         printf("基點G生成成功\n");
 77     else{
 78         printf("基點G生成失敗!\n"); return 1;
 79     }
 80     ecurve_mult(db,G,Pb);   //Pb=db * G ,倍點運算----點的乘法函式
 81     printf("公鑰點Pb生成成功!\n");
 82     printf("--------------加密過程---------------\n");
 83     bigrand(n,k);  //k<n 隨機生成k,然後列印
 84     printf("選取隨機數k=");    
 85     cotnum(k,stdout);
 86     ecurve_mult(k,G,T1);  //生成點T1座標(x1,y1)=[k]G
 87     printf("點T1生成成功!\n");
 88     epoint_get(T1,x1,y1);//獲取點x1、y1座標
 89     cotstr(x1,Hexstring1);//x1存入十六進位制字串陣列
 90     cotstr(y1,Hexstring2);//y1存入十六進位制字串陣列
 91     //用函式把十六進位制轉成二進位制
 92     Hex2Bin(Hexstring1,Binarystring1,strlen(Hexstring1));
 93     Hex2Bin(Hexstring2,Binarystring2,strlen(Hexstring2));
 94     //把C1 即x1|y1填入密文二進位制陣列最開始的部分
 95     sprintf(crypt,"%s%s",Binarystring1,Binarystring2);     
 96     printf("\n目前的密文長度為:%d,內容:\n",strlen(crypt));
 97     puts(crypt); 
 98     bzero(Hexstring1,sizeof(Hexstring1));//清空一下用過的中間陣列
 99     bzero(Hexstring2,sizeof(Hexstring2));
100     bzero(Binarystring1,sizeof(Binarystring1));
101     bzero(Binarystring2,sizeof(Binarystring2));
102     input_string=fopen("input.txt","r+");//從檔案讀取明文字串
103     fgets(plain,sizeof(plain),input_string);
104     fclose(input_string);
105     //printf("請輸入明文字串:");//可以自己輸入
106     //gets(plain);
107     kbitlen=strlen(plain)*8; //明文bit長度
108     printf("輸入明文是%s,明文位元長度為%d.\n",plain,kbitlen);
109     //將明文以二進位制形式填充進plain_bin字串內
110     Str2Hex(plain,Hexstring3,strlen(plain)); 
111     //Hexstring3只是一箇中間媒介,存放明文16進位制資訊,後面用得到!!!
112     Hex2Bin(Hexstring3,plain_bin,strlen(Hexstring3));
113     ecurve_mult(k,Pb,T2); //T2座標(x2,y2)=[k]Pb
114     printf("點T2生成成功!\n");
115     epoint_get(T2,x2,y2); 
116     cotstr(x2,Hexstring1);
117     cotstr(y2,Hexstring2);
118     //HexTemp存放十六進位制形式的 x2|M|y2
119     sprintf(HexTemp,"%s%s%s",Hexstring1,Hexstring3,Hexstring2);
120     Hex2Bin(Hexstring1,Binarystring1,strlen(Hexstring1));
121     Hex2Bin(Hexstring2,Binarystring2,strlen(Hexstring2));
122     //Binarystring3目前存放x2|y2,用於後面的KDF計算
123     sprintf(Binarystring3,"%s%s",Binarystring1,Binarystring2);    
124     bzero(Hexstring1,sizeof(Hexstring1));  //清空一波
125     bzero(Hexstring2,sizeof(Hexstring2));
126     bzero(Hexstring3,sizeof(Hexstring3));
127     bzero(Binarystring1,sizeof(Binarystring1));
128     bzero(Binarystring2,sizeof(Binarystring2));
129     //返回結果t1存放kbitlen長度的金鑰
130     KDF(Binarystring3,512,kbitlen,t1);        
131     if(strlen(plain_bin)==strlen(t1))
132         printf("長度一致,可以進行異或!\n");
133     //把C2 = t1^M 填充到最後的密文中,如果成功返回值應該是0
134     if(Bin_XOR(plain_bin,t1,crypt+strlen(crypt))!=0) 
135         printf("異或出錯!");
136     printf("\n目前的密文長度為:%d,內容:\n",strlen(crypt));
137     puts(crypt); 
138     bzero(t1,sizeof(t1));
139     bzero(plain,sizeof(plain));//銷燬明文字串陣列,保證解密準確性
140     //暫時拿plain存放byte形式的C2:x2|M|y2
141     Hex2Byte(HexTemp,plain,strlen(HexTemp));    
142     bzero(HexTemp,sizeof(HexTemp));
143     //計算sm3雜湊值C3 = Hash(x2 ∥ M ∥ y2),存放到sm3_dgst byte型別
144     SM3Calc(plain,strlen(plain),sm3_dgst);
145     Str2Hex(sm3_dgst,Hexstring1,strlen(sm3_dgst));
146     //雜湊結果轉二進位制型別,寫入密文crypt的中間部分
147     Hex2Bin(Hexstring1,crypt+strlen(crypt),strlen(Hexstring1));
148     bzero(Hexstring1,sizeof(Hexstring1));
149     printf("\n目前的密文長度為:%d,至此,加密成功!密文內容:\n",strlen(crypt));
150     puts(crypt);  
151     //後續處理,清空一切不需要的陣列,只保留必要的資訊
152     bzero(plain,sizeof(plain));    bzero(plain_bin,sizeof(plain_bin));
153     bzero(sm3_dgst,sizeof(sm3_dgst));
154     epoint_free(T1);    
155     epoint_free(T2);//釋放epoint型別點座標
156     x1=mirvar(0);
157     y1=mirvar(0);//座標值清零,後面還會用到
158     x2=mirvar(0);    
159     y2=mirvar(0);
160     printf("------------解密過程--------------\n");
161     printf("現在知道的資訊有:收到的密文crypt\n C1部分長度為512bits,分別儲存x1、y1的座標資訊\n kbitlen:代表明文的位元長度,對應密文C2部分的長度\n 解密者自己的私鑰db\n");
162     strncpy(Binarystring1,crypt,256);        // x1二進位制
163     strncpy(Binarystring2,crypt+256,256);  // y1二進位制
164     Bin2Hex(Binarystring1,Hexstring1,256); // x1十六進位制
165     Bin2Hex(Binarystring2,Hexstring2,256); // y1十六進位制
166     mip->IOBASE=16;
167     cinstr(x1,Hexstring1);
168     cinstr(y1,Hexstring2);
169     bzero(Binarystring1,sizeof(Binarystring1));
170     bzero(Binarystring2,sizeof(Binarystring2));
171     bzero(Hexstring1,sizeof(Hexstring1));
172     bzero(Hexstring2,sizeof(Hexstring2));
173     D1=epoint_init(); //初始化解密過程中將要用到的點
174     D2=epoint_init();
175     if(epoint_set(x1,y1,0,D1))
176             printf("點D1生成成功\n");
177     else{
178         printf("點D1生成失敗!\n");
179         return 0;
180     }
181     ecurve_mult(db,D1,D2); //點乘得到D2,解密非常關鍵的一步!!!
182     epoint_get(D2,x2,y2); //獲取D2座標資訊一直轉到二進位制型別
183     cotstr(x2,Hexstring1);    cotstr(y2,Hexstring2);
184     Hex2Bin(Hexstring1,Binarystring1,strlen(Hexstring1));
185     Hex2Bin(Hexstring2,Binarystring2,strlen(Hexstring2));
186     sprintf(Binarystring3,"%s%s",Binarystring1,Binarystring2);//Binarystring3目前存放x2|y2
187     bzero(Hexstring3,sizeof(Hexstring3));
188     bzero(Binarystring1,sizeof(Binarystring1));
189     bzero(Binarystring2,sizeof(Binarystring2));
190     //計算t1=KDF(x2' ∥ y2', klen)
191     KDF(Binarystring3,512,kbitlen,t1);      
192     bzero(Binarystring3,sizeof(Binarystring3));
193     //從C中取出位元串C2bin,計算M ′ = C2 ⊕ t'
194     strncpy(C2_bin,crypt+512,kbitlen);     
195     Bin_XOR(t1,C2_bin,plain_bin);    // M'是 二進位制 plain_bin
196     //M'是 十六進位制 Hexstring3
197     Bin2Hex(plain_bin,Hexstring3,strlen(plain_bin));
198     //HexTemp 存放hex形式的 x2|M'|y2
199     sprintf(HexTemp,"%s%s%s",Hexstring1,Hexstring3,Hexstring2);
200     bzero(Hexstring1,sizeof(Hexstring1));
201     bzero(Hexstring2,sizeof(Hexstring2));
202     // 拿plain存放字串形式的C2:x2|M'|y2
203     Hex2Byte(HexTemp,plain,strlen(HexTemp));
204     // u = Hash(x2 ∥ M '∥ y2) 還是存在變數sm3_dgst內
205     SM3Calc(plain,strlen(plain),sm3_dgst);
206     // u轉成16進位制hash值
207     Str2Hex(sm3_dgst,Hexstring1,strlen(sm3_dgst));
208     // u轉成二進位制 256 bits hash值
209     Hex2Bin(Hexstring1,Binarystring1,strlen(Hexstring1));
210     //從密文裡面提取出最後的一部分資訊賦給Binarystring2
211     strncpy(Binarystring2,crypt+512+kbitlen,256);    
212     if(strcmp(Binarystring1,Binarystring2)==0){  //匹配
213         printf("*********************匹配成功!!!!**********************\n");
214         bzero(plain,sizeof(plain));
215         Hex2Byte(Hexstring3,plain,strlen(Hexstring3));
216         printf("解密得到:\n");
217         puts(plain);
218     }
219     bzero(Hexstring3,sizeof(Hexstring3));
220     bzero(Hexstring1,sizeof(Hexstring1));
221     bzero(plain,sizeof(plain));
222     bzero(Binarystring1,sizeof(Binarystring1));
223     printf("----------------------------結束----------------------------\n");  //後續處理
224     mirkill(a);    
225     mirkill(b);    
226     mirkill(p);
227     mirkill(n);
228     mirkill(Gx);
229     mirkill(Gy);
230     mirkill(db);
231     mirkill(k);
232     mirkill(x1);    
233     mirkill(x2);    
234     mirkill(y1);
235     mirkill(y2);
236     epoint_free(G);    
237     epoint_free(Pb);    
238     epoint_free(D1);    
239     epoint_free(D2);
240     mirexit();
241     return 0;
242 }

abp.txt內使用國密推薦引數以及提供的一段明文:



執行效果:

(圖不完整,右邊還有很長的資料……)

解密成功!