⼤结局---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小时内删除。