⼤结局---Miracl库下完全实现SM2加密算法
本次博⽂以前⾯的两次⽂章的函数定义、说明为基础进⾏扩展。
并且参考了⼀些其他的优秀博客⽂章,⽐如KDF局部密钥派⽣函数的使⽤、⼗六进制字符串与⼆进制字符串以及普通字符串转换函数(⾃⼰也编写了⼀部分函数)、SM3杂凑签名算法(太懒了,完全拿来⽤了,取其精华,感谢博客主⼈)。
完成本次实验前,进⼀步了解了C语⾔,这种直接⾯对内存进⾏操作的语⾔真的既让⼈爱⼜让⼈恨……
然后,介绍⼀下我实现本算法的⼤概思路:从⽂件读⼊等待加密的明⽂,然后以⼆进制字符串形式(字符数组,定义了很多中间变量,做好准备吧)构造密⽂,中间还涉及⼗六进制形式的字符串,因为我需要把字符串转成16进制再转成⼆进制,并且中间有很多操作也和⼗六进制形式有关。
最后,强调⼀下定义的这些函数都是对字符数组进⾏,然后把结果填充到另⼀个指定地址去,这种思想伴随了整个程序中……
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*/
29static 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
44byte = (unsigned char *)word;
45 temp = byte[0];
46byte[0] = byte[3];
47byte[3] = temp;
48
49 temp = byte[1];
50byte[1] = byte[2];
51byte[2] = temp;
52return word;
53 }
54
55/*
56* T
57*/
58 unsigned int T(int i)
59 {
60if (i >= 0 && i <= 15)
61return0x79CC4519;
62else if (i >= 16 && i <= 63)
63return0x7A879D8A;
64else
65return0;
67
68/*
69* FF
70*/
71 unsigned int FF(unsigned int X, unsigned int Y, unsigned int Z, int i)
72 {
73if (i >= 0 && i <= 15)
74return X ^ Y ^ Z;
75else if (i >= 16 && i <= 63)
76return (X & Y) | (X & Z) | (Y & Z);
77else
78return0;
79 }
80
81/*
82* GG
83*/
84 unsigned int GG(unsigned int X, unsigned int Y, unsigned int Z, int i)
85 {
86if (i >= 0 && i <= 15)
87return X ^ Y ^ Z;
88else if (i >= 16 && i <= 63)
89return (X & Y) | (~X & Z);
90else
91return0;
92 }
93
94/*
95* P0
96*/
97 unsigned int P0(unsigned int X)
98 {
99return X ^ LeftRotate(X, 9) ^ LeftRotate(X, 17);
100 }
101
102/*
103* P1
104*/
105 unsigned int P1(unsigned int X)
106 {
107return X ^ LeftRotate(X, 15) ^ LeftRotate(X, 23);
108 }
109
110/*
111* 初始化函数
112*/
113void 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*/
128void SM3ProcessMessageBlock(SM3Context *context)
129 {
130int 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");
137for (i = 0; i < 16; i++)
138 {
139 W[i] = *(unsigned int *)(context->messageBlock + i * 4);
140if (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 }
146for (i = 16; i < 68; i++)
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");
156for (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);
176for (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 }
16进制字符串转16进制数组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/* 对前⾯的消息分组进⾏处理 */
214for (i = 0; i < messageLen / 64; i++) //i是Bi分组数⽬(512bits),只有⼀组则不处理,因为0< 0不成⽴
215 {
216 ssageBlock, message + i * 64, 64);
217 SM3ProcessMessageBlock(&context);
218 }
219
220/* 填充消息分组,并处理 */
221 bitLen = messageLen * 8; //消息的⽐特长度,⽤于待会的填充
222if (IsLittleEndian())
223 ReverseWord(&bitLen);
224 remainder = messageLen % 64;
225 ssageBlock, message + i * 64, remainder);
226 ssageBlock[remainder] = 0x80;
227if (remainder <= 55)
229 ssageBlock + remainder + 1, 0, 64 - remainder - 1 - 8 + 4);
230 ssageBlock + 64 - 4, &bitLen, 4); //最后四字节存放信息长度
231 SM3ProcessMessageBlock(&context);
232 }
233else
234 {
235 ssageBlock + remainder + 1, 0, 64 - remainder - 1);//本组余下的全填零
236 SM3ProcessMessageBlock(&context);
237 ssageBlock, 0, 64 - 4);
238 ssageBlock + 64 - 4, &bitLen, 4);
239 SM3ProcessMessageBlock(&context);
240 }
241
242/* 返回结果 */
243if (IsLittleEndian())
244for (i = 0; i < 8; i++)
245 ReverseWord(context.intermediateHash + i);
246 memcpy(digest,context.intermediateHash, SM3_HASH_SIZE);
247
248return digest;
249 }
1int KDF(const char* cdata, int datalen, int keybitlen, char* retdata)
2 {
3int nRet = -1;
4char* hexstring[512]={0};
5char* bytestring[256]={0};
6 unsigned char *pRet;
7 unsigned char *pData;
8 unsigned char cdgst[32]={0};
9 unsigned char cCnt[4] = {0};
10int nCnt = 1;
11int nDgst = 32;
12int keybytelen=keybitlen/8; //keybytelen是明⽂(未来密钥)的字节长度
13int nTimes = (keybytelen+31)/32;
14int i=0;
15if(cdata==NULL || datalen<=0 || keybitlen<=0)
16goto err;
17if(NULL == (pRet=(unsigned char *)malloc(keybytelen)))
18goto err;
19if(NULL == (pData=(unsigned char *)malloc(datalen+4)))
20goto err;
21 memset(pRet, 0, keybytelen);
22 memset(pData, 0, datalen+4);
23 memcpy(pData, cdata, datalen);
24for(; 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,⽽⾮⽐特串34if(i == nTimes-1) //最后⼀次计算,根据keybytelen/32是否整除,截取摘要的值
35if(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:
45if(pRet)
46free(pRet);
47if(pData)
48free(pData);
49
50return nRet;
51 }
1int main(){ //前⾯定义很多变量,不再⼀⼀介绍,后⾯⽤到再提
2 big a,b,p,Gx,Gy,n,db,k;
3 big x1,y1,x2,y2;
4int kbitlen;
5char plain[1024]={0}; //存放⽂件中读取的明⽂字符串
6char plain_bin[8192]={0}; //存放明⽂的⼆进制字符串
7char C2_bin[8192]={0}; //存放解密出明⽂的⼆进制字符串
8char sm3_dgst[33]={0}; //存放 sm3 32字节的杂凑摘要
9char crypt[3072]={0}; //存放加密⽣成的密⽂的⼆进制形式
10char Hexstring1[65]={0};
11char Hexstring2[65]={0};
12char Hexstring3[2048]={0};
13char HexTemp[2048]={0};
14char t1[8192]={0};
15char Binarystring1[257]={0};
16char Binarystring2[257]={0};
17char 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("","r+"); //fp指向同⽬录下存放参数的⽂件
40if(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();
75if(epoint_set(Gx,Gy,0,G)) //验证、⽣成基点 G
76 printf("基点G⽣成成功\n");
77else{
78 printf("基点G⽣成失败!\n"); return1;
79 }
80 ecurve_mult(db,G,Pb); //Pb=db * G ,倍点运算----点的乘法函数
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论