OpenSSL入门-SM2实践

MIRACL

下载MIRACL:https://github.com/miracl/MIRACL ,打开x64 Native Tools Command Prompt for VS 2022,工作目录改为source下,并将include目录内所有文件拷贝到source目录下,并运行../lib/ms64doit_cpp.bat。于是在source目录下生成miracl.lib,接下来工程需要链接该.lib。

SM2加密

需要复制来miracl.h和mirdef.h头文件。

test.c:

1
2
3
4
#include "SM2_ENC.h"
void main() {
SM2_ENC_SelfTest();
}

SM2_ENC.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#include "miracl.h"
#include "mirdef.h"
#include "SM2_ENC.h"
#include "kdf.h"
#pragma comment(lib,"mymiracl.lib")
unsigned char SM2_p[32] = { 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
unsigned char SM2_a[32] = { 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC };
unsigned char SM2_b[32] = { 0x28,0xE9,0xFA,0x9E,0x9D,0x9F,0x5E,0x34,0x4D,0x5A,0x9E,0x4B,0xCF,0x65,0x09,0xA7,0xF3,0x97,0x89,0xF5,0x15,0xAB,0x8F,0x92,0xDD,0xBC,0xBD,0x41,0x4D,0x94,0x0E,0x93 };
unsigned char SM2_n[32] = { 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x72,0x03,0xDF,0x6B,0x21,0xC6,0x05,0x2B,0x53,0xBB,0xF4,0x09,0x39,0xD5,0x41,0x23 };
unsigned char SM2_Gx[32] = { 0x32,0xC4,0xAE,0x2C,0x1F,0x19,0x81,0x19,0x5F,0x99,0x04,0x46,0x6A,0x39,0xC9,0x94,0x8F,0xE3,0x0B,0xBF,0xF2,0x66,0x0B,0xE1,0x71,0x5A,0x45,0x89,0x33,0x4C,0x74,0xC7 };
unsigned char SM2_Gy[32] = { 0xBC,0x37,0x36,0xA2,0xF4,0xF6,0x77,0x9C,0x59,0xBD,0xCE,0xE3,0x6B,0x69,0x21,0x53,0xD0,0xA9,0x87,0x7C,0xC6,0x2A,0x47,0x40,0x02,0xDF,0x32,0xE5,0x21,0x39,0xF0,0xA0 };
unsigned char SM2_h[32] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 };
int Test_Point(epoint* point) {
big x, y, x_3, tmp;
x = mirvar(0);
y = mirvar(0);
x_3 = mirvar(0);
tmp = mirvar(0);
//test if y^2=x^3+ax+b
epoint_get(point, x, y);
power(x, 3, para_p, x_3); //x_3=x^3 mod p
multiply(x, para_a, x); //x=a*x
divide(x, para_p, tmp); //x=a*x mod p , tmp=a*x/p
add(x_3, x, x); //x=x^3+ax
add(x, para_b, x); //x=x^3+ax+b
divide(x, para_p, tmp); //x=x^3+ax+b mod p
power(y, 2, para_p, y); //y=y^2 mod p
if (mr_compare(x, y) != 0)
return ERR_NOT_VALID_POINT;
else
return 0;
}
int Test_PubKey(epoint* pubKey) {
big x, y, x_3, tmp;
epoint* nP;
x = mirvar(0);
y = mirvar(0);
x_3 = mirvar(0);
tmp = mirvar(0);
nP = epoint_init();
//test if the pubKey is the point at infinity
if (point_at_infinity(pubKey))// if pubKey is point at infinity, return error;
return ERR_INFINITY_POINT;
//test if x<p and y<p both hold
epoint_get(pubKey, x, y);
if ((mr_compare(x, para_p) != -1) || (mr_compare(y, para_p) != -1))
return ERR_NOT_VALID_ELEMENT;
if (Test_Point(pubKey) != 0)
return ERR_NOT_VALID_POINT;
//test if the order of pubKey is equal to n
ecurve_mult(para_n, pubKey, nP); // nP=[n]P
if (!point_at_infinity(nP)) // if np is point NOT at infinity, return error;
return ERR_ORDER;
return 0;
}
int Test_Null(unsigned char array[], int len) {
int i = 0;
for (i = 0; i < len; i++)
if (array[i] != 0x00)
return 0;
return 1;
}
int SM2_Init() {
epoint* nG;
para_p = mirvar(0);
para_a = mirvar(0);
para_b = mirvar(0);
para_n = mirvar(0);
para_Gx = mirvar(0);
para_Gy = mirvar(0);
para_h = mirvar(0);
G = epoint_init();
nG = epoint_init();
bytes_to_big(SM2_NUMWORD, SM2_p, para_p);
bytes_to_big(SM2_NUMWORD, SM2_a, para_a);
bytes_to_big(SM2_NUMWORD, SM2_b, para_b);
bytes_to_big(SM2_NUMWORD, SM2_n, para_n);
bytes_to_big(SM2_NUMWORD, SM2_Gx, para_Gx);
bytes_to_big(SM2_NUMWORD, SM2_Gy, para_Gy);
bytes_to_big(SM2_NUMWORD, SM2_h, para_h);
ecurve_init(para_a, para_b, para_p, MR_PROJECTIVE);//Initialises GF(p) elliptic curve.
//MR_PROJECTIVE specifying projective coordinates
if (!epoint_set(para_Gx, para_Gy, 0, G))//initialise point G
return ERR_ECURVE_INIT;
ecurve_mult(para_n, G, nG);
if (!point_at_infinity(nG)) //test if the order of the point is n
return ERR_ORDER;
return 0;
}
int SM2_KeyGeneration(big priKey, epoint* pubKey) {
int i = 0;
big x, y;
x = mirvar(0);
y = mirvar(0);
ecurve_mult(priKey, G, pubKey);//通过大数和基点产生公钥
epoint_get(pubKey, x, y);
if (Test_PubKey(pubKey) != 0)
return 1;
else
return 0;
}
int SM2_Encrypt(unsigned char* randK, epoint* pubKey, unsigned char M[], int klen, unsigned char C[]) { //加密函数 结果长度为明文长度+SM2_NUMWORD*3
big C1x, C1y, x2, y2, rand;
epoint* C1, * kP, * S;
int i = 0;
unsigned char x2y2[SM2_NUMWORD * 2] = { 0 };
SM3_STATE md;
C1x = mirvar(0);
C1y = mirvar(0);
x2 = mirvar(0);
y2 = mirvar(0);
rand = mirvar(0);
C1 = epoint_init();
kP = epoint_init();
S = epoint_init();
//Step2. calculate C1=[k]G=(rGx,rGy)
bytes_to_big(SM2_NUMWORD, randK, rand);
ecurve_mult(rand, G, C1); //C1=[k]G
epoint_get(C1, C1x, C1y);
big_to_bytes(SM2_NUMWORD, C1x, C, 1);
big_to_bytes(SM2_NUMWORD, C1y, C + SM2_NUMWORD, 1);
//Step3. test if S=[h]pubKey if the point at infinity
ecurve_mult(para_h, pubKey, S);
if (point_at_infinity(S))// if S is point at infinity, return error;
return ERR_INFINITY_POINT;
//Step4. calculate [k]PB=(x2,y2)
ecurve_mult(rand, pubKey, kP); //kP=[k]P
epoint_get(kP, x2, y2);
//Step5. KDF(x2||y2,klen)
big_to_bytes(SM2_NUMWORD, x2, x2y2, 1);
big_to_bytes(SM2_NUMWORD, y2, x2y2 + SM2_NUMWORD, 1);
SM3_KDF(x2y2, SM2_NUMWORD * 2, klen, C + SM2_NUMWORD * 3);
if (Test_Null(C + SM2_NUMWORD * 3, klen) != 0)
return ERR_ARRAY_NULL;
//Step6. C2=M^t
for (i = 0; i < klen; i++)
C[SM2_NUMWORD * 3 + i] = M[i] ^ C[SM2_NUMWORD * 3 + i];
//Step7. C3=hash(x2,M,y2)
SM3_init(&md);
SM3_process(&md, x2y2, SM2_NUMWORD);
SM3_process(&md, M, klen);
SM3_process(&md, x2y2 + SM2_NUMWORD, SM2_NUMWORD);
SM3_done(&md, C + SM2_NUMWORD * 2);
return 0;
}
int SM2_Decrypt(big dB, unsigned char C[], int Clen, unsigned char M[]) { //解密函数
SM3_STATE md;
int i = 0;
unsigned char x2y2[SM2_NUMWORD * 2] = { 0 };
unsigned char hash[SM2_NUMWORD] = { 0 };
big C1x, C1y, x2, y2;
epoint* C1, * S, * dBC1;
C1x = mirvar(0);
C1y = mirvar(0);
x2 = mirvar(0);
y2 = mirvar(0);
C1 = epoint_init();
S = epoint_init();
dBC1 = epoint_init();
//Step1. test if C1 fits the curve
bytes_to_big(SM2_NUMWORD, C, C1x);
bytes_to_big(SM2_NUMWORD, C + SM2_NUMWORD, C1y);
epoint_set(C1x, C1y, 0, C1);
i = Test_Point(C1);
if (i != 0)
return i;
//Step2. S=[h]C1 and test if S is the point at infinity
ecurve_mult(para_h, C1, S);
if (point_at_infinity(S))// if S is point at infinity, return error;
return ERR_INFINITY_POINT;
//Step3. [dB]C1=(x2,y2)
ecurve_mult(dB, C1, dBC1);
epoint_get(dBC1, x2, y2);
big_to_bytes(SM2_NUMWORD, x2, x2y2, 1);
big_to_bytes(SM2_NUMWORD, y2, x2y2 + SM2_NUMWORD, 1);
//Step4. t=KDF(x2||y2,klen)
SM3_KDF(x2y2, SM2_NUMWORD * 2, Clen - SM2_NUMWORD * 3, M);
if (Test_Null(M, Clen - SM2_NUMWORD * 3) != 0)
return ERR_ARRAY_NULL;
//Step5. M=C2^t
for (i = 0; i < Clen - SM2_NUMWORD * 3; i++)
M[i] = M[i] ^ C[SM2_NUMWORD * 3 + i];
//Step6. hash(x2,m,y2)
SM3_init(&md);
SM3_process(&md, x2y2, SM2_NUMWORD);
SM3_process(&md, M, Clen - SM2_NUMWORD * 3);
SM3_process(&md, x2y2 + SM2_NUMWORD, SM2_NUMWORD);
SM3_done(&md, hash);
if (memcmp(hash, C + SM2_NUMWORD * 2, SM2_NUMWORD) != 0)
return ERR_C3_MATCH;
else
return 0;
}
int SM2_ENC_SelfTest() { //对第一个字节数组加密并解密 比较来判断是否成功
int tmp = 0, i = 0;
unsigned char Cipher[115] = { 0 };
unsigned char M[19] = { 0 };
unsigned char kGxy[SM2_NUMWORD * 2] = { 0 };
big ks, x, y;
epoint* kG;
//standard data
unsigned char std_priKey[32] = { 0x39,0x45,0x20,0x8F,0x7B,0x21,0x44,0xB1,0x3F,0x36,0xE3,0x8A,0xC6,0xD3,0x9F,0x95,0x88,0x93,0x93,0x69,0x28,0x60,0xB5,0x1A,0x42,0xFB,0x81,0xEF,0x4D,0xF7,0xC5,0xB8 };
unsigned char std_pubKey[64] = { 0x09,0xF9,0xDF,0x31,0x1E,0x54,0x21,0xA1,0x50,0xDD,0x7D,0x16,0x1E,0x4B,0xC5,0xC6,0x72,0x17,0x9F,0xAD,0x18,0x33,0xFC,0x07,0x6B,0xB0,0x8F,0xF3,0x56,0xF3,0x50,0x20,0xCC,0xEA,0x49,0x0C,0xE2,0x67,0x75,0xA5,0x2D,0xC6,0xEA,0x71,0x8C,0xC1,0xAA,0x60,0x0A,0xED,0x05,0xFB,0xF3,0x5E,0x08,0x4A,0x66,0x32,0xF6,0x07,0x2D,0xA9,0xAD,0x13 };
unsigned char std_rand[32] = { 0x59,0x27,0x6E,0x27,0xD5,0x06,0x86,0x1A,0x16,0x68,0x0F,0x3A,0xD9,0xC0,0x2D,0xCC,0xEF,0x3C,0xC1,0xFA,0x3C,0xDB,0xE4,0xCE,0x6D,0x54,0xB8,0x0D,0xEA,0xC1,0xBC,0x21 };
unsigned char std_Message[19] = { 0x65,0x6E,0x63,0x72,0x79,0x70,0x74,0x69,0x6F,0x6E,0x20,0x73,0x74,0x61,0x6E,0x64,0x61,0x72,0x64 };
unsigned char std_Cipher[115] = { 0x04,0xEB,0xFC,0x71,0x8E,0x8D,0x17,0x98,0x62,0x04,0x32,0x26,0x8E,0x77,0xFE,0xB6,0x41,0x5E,0x2E,0xDE,0x0E,0x07,0x3C,0x0F,0x4F,0x64,0x0E,0xCD,0x2E,0x14,0x9A,0x73,0xE8,0x58,0xF9,0xD8,0x1E,0x54,0x30,0xA5,0x7B,0x36,0xDA,0xAB,0x8F,0x95,0x0A,0x3C,0x64,0xE6,0xEE,0x6A,0x63,0x09,0x4D,0x99,0x28,0x3A,0xFF,0x76,0x7E,0x12,0x4D,0xF0,0x59,0x98,0x3C,0x18,0xF8,0x09,0xE2,0x62,0x92,0x3C,0x53,0xAE,0xC2,0x95,0xD3,0x03,0x83,0xB5,0x4E,0x39,0xD6,0x09,0xD1,0x60,0xAF,0xCB,0x19,0x08,0xD0,0xBD,0x87,0x66,0x21,0x88,0x6C,0xA9,0x89,0xCA,0x9C,0x7D,0x58,0x08,0x73,0x07,0xCA,0x93,0x09,0x2D,0x65,0x1E,0xFA };
mip = mirsys(1000, 16);
mip->IOBASE = 16;
x = mirvar(0);
y = mirvar(0);
ks = mirvar(0);
kG = epoint_init();
bytes_to_big(32, std_priKey, ks); //ks is the standard private key
//initiate SM2 curve
SM2_Init();
//generate key pair
tmp = SM2_KeyGeneration(ks, kG);
if (tmp != 0)
return tmp;
epoint_get(kG, x, y);
big_to_bytes(SM2_NUMWORD, x, kGxy, 1);
big_to_bytes(SM2_NUMWORD, y, kGxy + SM2_NUMWORD, 1);
if (memcmp(kGxy, std_pubKey, SM2_NUMWORD * 2) != 0)
return ERR_SELFTEST_KG;
puts("原文:");
for (i = 0; i < 19; i++) {
if (i > 0 && i % 8 == 0)
printf("\n");
printf("0x%x,", std_Message[i]);
}
//encrypt data and compare the result with the standard data
tmp = SM2_Encrypt(std_rand, kG, std_Message, 19, Cipher);
if (tmp != 0)
return tmp;
if (memcmp(Cipher, std_Cipher, 19 + SM2_NUMWORD * 3) != 0)
return ERR_SELFTEST_ENC;
puts("\n\n密文:");
for (i = 0; i < 19 + SM2_NUMWORD * 3; i++) {
if (i > 0 && i % 8 == 0)
printf("\n");
printf("0x%x,", Cipher[i]);
}
//decrypt cipher and compare the result with the standard data
tmp = SM2_Decrypt(ks, Cipher, 115, M);
if (tmp != 0)
return tmp;
puts("\n\n解密结果:");
for (i = 0; i < 19; i++) {
if (i > 0 && i % 8 == 0)
printf("\n");
printf("0x%x,", M[i]);
}
if (memcmp(M, std_Message, 19) != 0)
return ERR_SELFTEST_DEC;
puts("\n解密成功");
return 0;
}

kdf.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#include "kdf.h"
void BiToW(unsigned long Bi[], unsigned long W[]) {
int i;
unsigned long tmp;
for (i = 0; i <= 15; i++)
W[i] = Bi[i];
for (i = 16; i <= 67; i++) {
tmp = W[i - 16] ^ W[i - 9] ^ SM3_rotl32(W[i - 3], 15);
W[i] = SM3_p1(tmp) ^ (SM3_rotl32(W[i - 13], 7)) ^ W[i - 6];
}
}
void WToW1(unsigned long W[], unsigned long W1[]) { //W到W'转换
int i;
for (i = 0; i <= 63; i++)
W1[i] = W[i] ^ W[i + 4];
}
void CF(unsigned long W[], unsigned long W1[], unsigned long V[]) {
unsigned long SS1;
unsigned long SS2;
unsigned long TT1;
unsigned long TT2;
unsigned long A, B, C, D, E, F, G, H;
unsigned long T = SM3_T1;
unsigned long FF;
unsigned long GG;
int j;
//reg init,set ABCDEFGH=V0
A = V[0];
B = V[1];
C = V[2];
D = V[3];
E = V[4];
F = V[5];
G = V[6];
H = V[7];
for (j = 0; j <= 63; j++) {
//SS1
if (j == 0)
T = SM3_T1;
else if (j == 16)
T = SM3_rotl32(SM3_T2, 16);
else
T = SM3_rotl32(T, 1);
SS1 = SM3_rotl32((SM3_rotl32(A, 12) + E + T), 7);
//SS2
SS2 = SS1 ^ SM3_rotl32(A, 12);
//TT1
if (j <= 15)
FF = SM3_ff0(A, B, C);
else
FF = SM3_ff1(A, B, C);
TT1 = FF + D + SS2 + *W1;
W1++;
//TT2
if (j <= 15)
GG = SM3_gg0(E, F, G);
else
GG = SM3_gg1(E, F, G);
TT2 = GG + H + SS1 + *W;
W++;
//D
D = C;
//C
C = SM3_rotl32(B, 9);
//B
B = A;
//A
A = TT1;
//H
H = G;
//G
G = SM3_rotl32(F, 19);
//F
F = E;
//E
E = SM3_p0(TT2);
}
//update V
V[0] = A ^ V[0];
V[1] = B ^ V[1];
V[2] = C ^ V[2];
V[3] = D ^ V[3];
V[4] = E ^ V[4];
V[5] = F ^ V[5];
V[6] = G ^ V[6];
V[7] = H ^ V[7];
}
void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[]) {
unsigned char tmp = 0;
unsigned long i = 0;
for (i = 0; i < bytelen / 4; i++) {
tmp = des[4 * i];
des[4 * i] = src[4 * i + 3];
src[4 * i + 3] = tmp;
tmp = des[4 * i + 1];
des[4 * i + 1] = src[4 * i + 2];
des[4 * i + 2] = tmp;
}
}
void SM3_init(SM3_STATE* md) { //初始化SM3上下文状态
md->curlen = md->length = 0;
md->state[0] = SM3_IVA;
md->state[1] = SM3_IVB;
md->state[2] = SM3_IVC;
md->state[3] = SM3_IVD;
md->state[4] = SM3_IVE;
md->state[5] = SM3_IVF;
md->state[6] = SM3_IVG;
md->state[7] = SM3_IVH;
}
void SM3_compress(SM3_STATE* md) { //压缩单个消息块
unsigned long W[68];
unsigned long W1[64];
//if CPU uses little-endian, BigEndian function is a necessary call
BigEndian(md->buf, 64, md->buf);
BiToW((unsigned long*)md->buf, W);
WToW1(W, W1);
CF(W, W1, md->state);
}
void SM3_process(SM3_STATE* md, unsigned char* buf, int len) { //处理消息中前len/64个块
while (len--) {
/* copy byte */
md->buf[md->curlen] = *buf++;
md->curlen++;
/* is 64 bytes full? */
if (md->curlen == 64) {
SM3_compress(md);
md->length += 512;
md->curlen = 0;
}
}
}
void SM3_done(SM3_STATE* md, unsigned char hash[]) { //处理剩下的消息内容并输出结果
int i;
unsigned char tmp = 0;
/* increase the bit length of the message */
md->length += md->curlen << 3;
/* append the '1' bit */
md->buf[md->curlen] = 0x80;
md->curlen++;
//if the length is currently above 56 bytes, appends zeros till it reaches 64 bytes, compress the current block, creat a new block by appending zeros and length,and then compress it
if (md->curlen > 56) {
for (; md->curlen < 64;) {
md->buf[md->curlen] = 0;
md->curlen++;
}
SM3_compress(md);
md->curlen = 0;
}
/* if the length is less than 56 bytes, pad upto 56 bytes of zeroes */
for (; md->curlen < 56;) {
md->buf[md->curlen] = 0;
md->curlen++;
}
/* since all messages are under 2^32 bits we mark the top bits zero */
for (i = 56; i < 60; i++)
md->buf[i] = 0;
/* append length */
md->buf[63] = md->length & 0xff;
md->buf[62] = (md->length >> 8) & 0xff;
md->buf[61] = (md->length >> 16) & 0xff;
md->buf[60] = (md->length >> 24) & 0xff;
SM3_compress(md);
/* copy output */
memcpy(hash, md->state, SM3_len / 8);
BigEndian(hash, SM3_len / 8, hash);//if CPU uses little-endian, BigEndian function is a necessary call
}
void SM3_256(unsigned char buf[], int len, unsigned char hash[]) {
SM3_STATE md;
SM3_init(&md);
SM3_process(&md, buf, len);
SM3_done(&md, hash);
}
void SM3_KDF(unsigned char Z[], unsigned short zlen, unsigned short klen, unsigned char K[]) { //密钥派生
unsigned short i, j, t;
unsigned int bitklen;
SM3_STATE md;
unsigned char Ha[SM2_NUMWORD];
unsigned char ct[4] = { 0,0,0,1 };
bitklen = klen * 8;
if (bitklen % SM2_NUMBITS)
t = bitklen / SM2_NUMBITS + 1;
else
t = bitklen / SM2_NUMBITS;
//s4: K=Ha1||Ha2||...
for (i = 1; i < t; i++) {
//s2: Hai=Hv(Z||ct)
SM3_init(&md);
SM3_process(&md, Z, zlen);
SM3_process(&md, ct, 4);
SM3_done(&md, Ha);
memcpy((K + SM2_NUMWORD * (i - 1)), Ha, SM2_NUMWORD);
if (ct[3] == 0xff) {
ct[3] = 0;
if (ct[2] == 0xff) {
ct[2] = 0;
if (ct[1] == 0xff) {
ct[1] = 0;
ct[0]++;
}
else
ct[1]++;
}
else
ct[2]++;
}
else
ct[3]++;
}
//s3: klen/v非整数的处理
SM3_init(&md);
SM3_process(&md, Z, zlen);
SM3_process(&md, ct, 4);
SM3_done(&md, Ha);
if (bitklen % SM2_NUMBITS) {
i = (SM2_NUMBITS - bitklen + SM2_NUMBITS * (bitklen / SM2_NUMBITS)) / 8;
j = (bitklen - SM2_NUMBITS * (bitklen / SM2_NUMBITS)) / 8;
memcpy((K + SM2_NUMWORD * (t - 1)), Ha, j);
}
else
memcpy((K + SM2_NUMWORD * (t - 1)), Ha, SM2_NUMWORD);
}

SM2_ENC.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#pragma once
#include "miracl.h"
#define ECC_WORDSIZE 8
#define SM2_NUMBITS 256
#define SM2_NUMWORD (SM2_NUMBITS/ECC_WORDSIZE) //32
#define ERR_INFINITY_POINT 0x00000001
#define ERR_NOT_VALID_ELEMENT 0x00000002
#define ERR_NOT_VALID_POINT 0x00000003
#define ERR_ORDER 0x00000004
#define ERR_ARRAY_NULL 0x00000005
#define ERR_C3_MATCH 0x00000006
#define ERR_ECURVE_INIT 0x00000007
#define ERR_SELFTEST_KG 0x00000008
#define ERR_SELFTEST_ENC 0x00000009
#define ERR_SELFTEST_DEC 0x0000000A
extern unsigned char SM2_p[32];
extern unsigned char SM2_a[32];
extern unsigned char SM2_b[32];
extern unsigned char SM2_n[32];
extern unsigned char SM2_Gx[32];
extern unsigned char SM2_Gy[32];
extern unsigned char SM2_h[32];
big para_p, para_a, para_b, para_n, para_Gx, para_Gy, para_h;
epoint* G;
miracl* mip;
int Test_Point(epoint* point);
int Test_PubKey(epoint* pubKey);
int Test_Null(unsigned char array[], int len);
int SM2_Init();
int SM2_KeyGeneration(big priKey, epoint* pubKey);
int SM2_Encrypt(unsigned char* randK, epoint* pubKey, unsigned char M[], int klen, unsigned char C[]);
int SM2_Decrypt(big dB, unsigned char C[], int Clen, unsigned char M[]);
int SM2_ENC_SelfTest();

kdf.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "SM2_ENC.h"
#include <string.h>
#define SM3_len 256
#define SM3_T1 0x79CC4519
#define SM3_T2 0x7A879D8A
#define SM3_IVA 0x7380166f
#define SM3_IVB 0x4914b2b9
#define SM3_IVC 0x172442d7
#define SM3_IVD 0xda8a0600
#define SM3_IVE 0xa96f30bc
#define SM3_IVF 0x163138aa
#define SM3_IVG 0xe38dee4d
#define SM3_IVH 0xb0fb0e4e
/* Various logical functions */
#define SM3_p1(x) (x^SM3_rotl32(x,15)^SM3_rotl32(x,23))
#define SM3_p0(x) (x^SM3_rotl32(x,9)^SM3_rotl32(x,17))
#define SM3_ff0(a,b,c) (a^b^c)
#define SM3_ff1(a,b,c) ((a&b)|(a&c)|(b&c))
#define SM3_gg0(e,f,g) (e^f^g)
#define SM3_gg1(e,f,g) ((e&f)|((~e)&g))
#define SM3_rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
#define SM3_rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
typedef struct {
unsigned long state[8];
unsigned long length;
unsigned long curlen;
unsigned char buf[64];
} SM3_STATE;
void BiToWj(unsigned long Bi[], unsigned long Wj[]);
void WjToWj1(unsigned long Wj[], unsigned long Wj1[]);
void CF(unsigned long Wj[], unsigned long Wj1[], unsigned long V[]);
void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[]);
void SM3_init(SM3_STATE *md);
void SM3_process(SM3_STATE * md, unsigned char buf[], int len);
void SM3_done(SM3_STATE *md, unsigned char *hash);
void SM3_compress(SM3_STATE * md);
void SM3_256(unsigned char buf[], int len, unsigned char hash[]);
void SM3_KDF(unsigned char *Z, unsigned short zlen, unsigned short klen, unsigned char *K);

SM2验签

kdf.h和kdf.c同上,test.c:

1
2
3
4
5
6
7
8
#include "SM2_sv.h"
void main() {
if (SM2_SelfCheck()) {
puts("SM2签名验签出错");
return;
}
puts("SM2签名验签成功");
}

SM2_sv.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#include "SM2_sv.h"
#include "KDF.h"
unsigned char SM2_p[32] = { 0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff };
unsigned char SM2_a[32] = { 0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xfc };
unsigned char SM2_b[32] = { 0x28,0xe9,0xfa,0x9e, 0x9d,0x9f,0x5e,0x34, 0x4d,0x5a,0x9e,0x4b,0xcf,0x65,0x09,0xa7,0xf3,0x97,0x89,0xf5, 0x15,0xab,0x8f,0x92, 0xdd,0xbc,0xbd,0x41,0x4d,0x94,0x0e,0x93 };
unsigned char SM2_Gx[32] = { 0x32,0xc4,0xae,0x2c, 0x1f,0x19,0x81,0x19,0x5f,0x99,0x04,0x46,0x6a,0x39,0xc9,0x94,0x8f,0xe3,0x0b,0xbf,0xf2,0x66,0x0b,0xe1,0x71,0x5a,0x45,0x89,0x33,0x4c,0x74,0xc7 };
unsigned char SM2_Gy[32] = { 0xbc,0x37,0x36,0xa2,0xf4,0xf6,0x77,0x9c,0x59,0xbd,0xce,0xe3,0x6b,0x69,0x21,0x53,0xd0,0xa9,0x87,0x7c,0xc6,0x2a,0x47,0x40,0x02,0xdf,0x32,0xe5,0x21,0x39,0xf0,0xa0 };
unsigned char SM2_n[32] = { 0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x72,0x03,0xdf,0x6b,0x21,0xc6,0x05,0x2b,0x53,0xbb,0xf4,0x09,0x39,0xd5,0x41,0x23 };
int SM2_Init() {
Gx = mirvar(0);
Gy = mirvar(0);
p = mirvar(0);
a = mirvar(0);
b = mirvar(0);
n = mirvar(0);
bytes_to_big(SM2_NUMWORD, SM2_Gx, Gx);
bytes_to_big(SM2_NUMWORD, SM2_Gy, Gy);
bytes_to_big(SM2_NUMWORD, SM2_p, p);
bytes_to_big(SM2_NUMWORD, SM2_a, a);
bytes_to_big(SM2_NUMWORD, SM2_b, b);
bytes_to_big(SM2_NUMWORD, SM2_n, n);
ecurve_init(a, b, p, MR_PROJECTIVE);
G = epoint_init();
nG = epoint_init();
if (!epoint_set(Gx, Gy, 0, G))//initialise point G
return ERR_ECURVE_INIT;
ecurve_mult(n, G, nG);
if (!point_at_infinity(nG)) //test if the order of the point is n
return ERR_ORDER;
return 0;
}
int Test_Point(epoint* point) {
big x, y, x_3, tmp;
x = mirvar(0);
y = mirvar(0);
x_3 = mirvar(0);
tmp = mirvar(0);
//test if y^2=x^3+ax+b
epoint_get(point, x, y);
power(x, 3, p, x_3); //x_3=x^3 mod p
multiply(x, a, x); //x=a*x
divide(x, p, tmp); //x=a*x mod p , tmp=a*x/p
add(x_3, x, x); //x=x^3+ax
add(x, b, x); //x=x^3+ax+b
divide(x, p, tmp); //x=x^3+ax+b mod p
power(y, 2, p, y); //y=y^2 mod p
if (mr_compare(x, y) != 0)
return ERR_NOT_VALID_POINT;
else
return 0;
}
int Test_PubKey(epoint* pubKey) {
big x, y, x_3, tmp;
epoint* nP;
x = mirvar(0);
y = mirvar(0);
x_3 = mirvar(0);
tmp = mirvar(0);
nP = epoint_init();
//test if the pubKey is the point at infinity
if (point_at_infinity(pubKey))// if pubKey is point at infinity, return error;
return ERR_INFINITY_POINT;
//test if x<p and y<p both hold
epoint_get(pubKey, x, y);
if ((mr_compare(x, p) != -1) || (mr_compare(y, p) != -1))
return ERR_NOT_VALID_ELEMENT;
if (Test_Point(pubKey) != 0)
return ERR_NOT_VALID_POINT;
//test if the order of pubKey is equal to n
ecurve_mult(n, pubKey, nP); // nP=[n]P
if (!point_at_infinity(nP)) // if np is point NOT at infinity, return error;
return ERR_ORDER;
return 0;
}
int Test_Zero(big x) {
big zero;
zero = mirvar(0);
if (mr_compare(x, zero) == 0)
return 1;
else
return 0;
}
int Test_n(big x) {
// bytes_to_big(32,SM2_n,n);
if (mr_compare(x, n) == 0)
return 1;
else
return 0;
}
int Test_Range(big x) {
big one, decr_n;
one = mirvar(0);
decr_n = mirvar(0);
convert(1, one);
decr(n, 1, decr_n);
if ((mr_compare(x, one) < 0) | (mr_compare(x, decr_n) > 0))
return 1;
return 0;
}
int SM2_KeyGeneration(unsigned char PriKey[], unsigned char Px[], unsigned char Py[]) {
int i = 0;
big d, PAx, PAy;
epoint* PA;
SM2_Init();
PA = epoint_init();
d = mirvar(0);
PAx = mirvar(0);
PAy = mirvar(0);
bytes_to_big(SM2_NUMWORD, PriKey, d);
ecurve_mult(d, G, PA);
epoint_get(PA, PAx, PAy);
big_to_bytes(SM2_NUMWORD, PAx, Px, TRUE);
big_to_bytes(SM2_NUMWORD, PAy, Py, TRUE);
i = Test_PubKey(PA);
if (i)
return i;
else
return 0;
}
int SM2_Sign(unsigned char* message, int len, unsigned char ZA[], unsigned char rand[], unsigned char d[], unsigned char R[], unsigned char S[]) {
unsigned char hash[SM3_len / 8];
int M_len = len + SM3_len / 8;
unsigned char* M = NULL;
int i;
big dA, r, s, e, k, KGx, KGy;
big rem, rk, z1, z2;
epoint* KG;
i = SM2_Init();
if (i) return i;
//initiate
dA = mirvar(0);
e = mirvar(0);
k = mirvar(0);
KGx = mirvar(0);
KGy = mirvar(0);
r = mirvar(0);
s = mirvar(0);
rem = mirvar(0);
rk = mirvar(0);
z1 = mirvar(0);
z2 = mirvar(0);
bytes_to_big(SM2_NUMWORD, d, dA);//cinstr(dA,d);
KG = epoint_init();
//step1,set M=ZA||M
M = (char*)malloc(sizeof(char) * (M_len + 1));
memcpy(M, ZA, SM3_len / 8);
memcpy(M + SM3_len / 8, message, len);
//step2,generate e=H(M)
SM3_256(M, M_len, hash);
bytes_to_big(SM3_len / 8, hash, e);
//step3:generate k
bytes_to_big(SM3_len / 8, rand, k);
//step4:calculate kG
ecurve_mult(k, G, KG);
//step5:calculate r
epoint_get(KG, KGx, KGy);
add(e, KGx, r);
divide(r, n, rem);
//judge r=0 or n+k=n?
add(r, k, rk);
if (Test_Zero(r) | Test_n(rk))
return ERR_GENERATE_R;
//step6:generate s
incr(dA, 1, z1);
xgcd(z1, n, z1, z1, z1);
multiply(r, dA, z2);
divide(z2, n, rem);
subtract(k, z2, z2);
add(z2, n, z2);
multiply(z1, z2, s);
divide(s, n, rem);
//judge s=0?
if (Test_Zero(s))
return ERR_GENERATE_S;
big_to_bytes(SM2_NUMWORD, r, R, TRUE);
big_to_bytes(SM2_NUMWORD, s, S, TRUE);
free(M);
return 0;
}
int SM2_Verify(unsigned char* message, int len, unsigned char ZA[], unsigned char Px[], unsigned char Py[], unsigned char R[], unsigned char S[]) {
unsigned char hash[SM3_len / 8];
int M_len = len + SM3_len / 8;
unsigned char* M = NULL;
int i;
big PAx, PAy, r, s, e, t, rem, x1, y1;
big RR;
epoint* PA, * sG, * tPA;
i = SM2_Init();
if (i) return i;
PAx = mirvar(0);
PAy = mirvar(0);
r = mirvar(0);
s = mirvar(0);
e = mirvar(0);
t = mirvar(0);
x1 = mirvar(0);
y1 = mirvar(0);
rem = mirvar(0);
RR = mirvar(0);
PA = epoint_init();
sG = epoint_init();
tPA = epoint_init();
bytes_to_big(SM2_NUMWORD, Px, PAx);
bytes_to_big(SM2_NUMWORD, Py, PAy);
bytes_to_big(SM2_NUMWORD, R, r);
bytes_to_big(SM2_NUMWORD, S, s);
if (!epoint_set(PAx, PAy, 0, PA))//initialise public key
return ERR_PUBKEY_INIT;
//step1: test if r belong to [1,n-1]
if (Test_Range(r))
return ERR_OUTRANGE_R;
//step2: test if s belong to [1,n-1]
if (Test_Range(s))
return ERR_OUTRANGE_S;
//step3,generate M
M = (char*)malloc(sizeof(char) * (M_len + 1));
memcpy(M, ZA, SM3_len / 8);
memcpy(M + SM3_len / 8, message, len);
//step4,generate e=H(M)
SM3_256(M, M_len, hash);
bytes_to_big(SM3_len / 8, hash, e);
//step5:generate t
add(r, s, t);
divide(t, n, rem);
if (Test_Zero(t))
return ERR_GENERATE_T;
//step 6: generate(x1,y1)
ecurve_mult(s, G, sG);
ecurve_mult(t, PA, tPA);
ecurve_add(sG, tPA);
epoint_get(tPA, x1, y1);
//step7:generate RR
add(e, x1, RR);
divide(RR, n, rem);
free(M);
if (mr_compare(RR, r) == 0)
return 0;
else
return ERR_DATA_MEMCMP;
}
int SM2_SelfCheck() {
//the private key
unsigned char dA[32] = { 0x39,0x45,0x20,0x8f,0x7b,0x21,0x44,0xb1,0x3f,0x36,0xe3,0x8a,0xc6,0xd3,0x9f,0x95,0x88,0x93,0x93,0x69,0x28,0x60,0xb5,0x1a,0x42,0xfb,0x81,0xef,0x4d,0xf7,0xc5,0xb8 };
unsigned char rand[32] = { 0x59,0x27,0x6E,0x27,0xD5,0x06,0x86,0x1A,0x16,0x68,0x0F,0x3A,0xD9,0xC0,0x2D,0xCC,0xEF,0x3C,0xC1,0xFA,0x3C,0xDB,0xE4,0xCE,0x6D,0x54,0xB8,0x0D,0xEA,0xC1,0xBC,0x21 };
//the public key
/* unsigned char xA[32]={0x09,0xf9,0xdf,0x31,0x1e,0x54,0x21,0xa1,0x50,0xdd,0x7d,0x16,0x1e,0x4b,0xc5,
0xc6,0x72,0x17,0x9f,0xad,0x18,0x33,0xfc,0x07,0x6b,0xb0,0x8f,0xf3,0x56,0xf3,0x50,0x20};
unsigned char yA[32]={0xcc,0xea,0x49,0x0c,0xe2,0x67,0x75,0xa5,0x2d,0xc6,0xea,0x71,0x8c,0xc1,0xaa,
0x60,0x0a,0xed,0x05,0xfb,0xf3,0x5e,0x08,0x4a,0x66,0x32,0xf6,0x07,0x2d,0xa9,0xad,0x13};*/
unsigned char xA[32], yA[32];
unsigned char r[32], s[32];// Signature
unsigned char IDA[16] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38 };//ASCII code of userA's identification
int IDA_len = 16;
unsigned char ENTLA[2] = { 0x00,0x80 };//the length of userA's identification,presentation in ASCII code
unsigned char* message = "message digest";//the message to be signed
int len = strlen(message);//the length of message
unsigned char ZA[SM3_len / 8];//ZA=Hash(ENTLA|| IDA|| a|| b|| Gx || Gy || xA|| yA)
unsigned char Msg[210]; //210=IDA_len+2+SM2_NUMWORD*6
int temp;
miracl* mip = mirsys(10000, 16);
mip->IOBASE = 16;
temp = SM2_KeyGeneration(dA, xA, yA);
if (temp)
return temp;
// ENTLA|| IDA|| a|| b|| Gx || Gy || xA|| yA
memcpy(Msg, ENTLA, 2);
memcpy(Msg + 2, IDA, IDA_len);
memcpy(Msg + 2 + IDA_len, SM2_a, SM2_NUMWORD);
memcpy(Msg + 2 + IDA_len + SM2_NUMWORD, SM2_b, SM2_NUMWORD);
memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 2, SM2_Gx, SM2_NUMWORD);
memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 3, SM2_Gy, SM2_NUMWORD);
memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 4, xA, SM2_NUMWORD);
memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 5, yA, SM2_NUMWORD);
SM3_256(Msg, 210, ZA);
temp = SM2_Sign(message, len, ZA, rand, dA, r, s);
if (temp)
return temp;
temp = SM2_Verify(message, len, ZA, xA, yA, r, s);
if (temp)
return temp;
return 0;
}

SM2_sv.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#pragma once
#include<string.h>
#include<malloc.h>
#include "miracl.h"
#define SM2_WORDSIZE 8
#define SM2_NUMBITS 256
#define SM2_NUMWORD (SM2_NUMBITS/SM2_WORDSIZE) //32
#define ERR_ECURVE_INIT 0x00000001
#define ERR_INFINITY_POINT 0x00000002
#define ERR_NOT_VALID_POINT 0x00000003
#define ERR_ORDER 0x00000004
#define ERR_NOT_VALID_ELEMENT 0x00000005
#define ERR_GENERATE_R 0x00000006
#define ERR_GENERATE_S 0x00000007
#define ERR_OUTRANGE_R 0x00000008
#define ERR_OUTRANGE_S 0x00000009
#define ERR_GENERATE_T 0x0000000A
#define ERR_PUBKEY_INIT 0x0000000B
#define ERR_DATA_MEMCMP 0x0000000C
extern unsigned char SM2_p[32];
extern unsigned char SM2_a[32];
extern unsigned char SM2_b[32];
extern unsigned char SM2_n[32];
extern unsigned char SM2_Gx[32];
extern unsigned char SM2_Gy[32];
extern unsigned char SM2_h[32];
big Gx, Gy, p, a, b, n;
epoint* G, * nG;
int SM2_Init();
int Test_Point(epoint* point);
int Test_PubKey(epoint* pubKey);
int Test_Zero(big x);
int Test_n(big x);
int Test_Range(big x);
int SM2_KeyGeneration(unsigned char PriKey[], unsigned char Px[], unsigned char Py[]);
int SM2_Sign(unsigned char* message, int len, unsigned char ZA[], unsigned char rand[], unsigned char d[], unsigned char R[], unsigned char S[]);
int SM2_Verify(unsigned char* message, int len, unsigned char ZA[], unsigned char Px[], unsigned char Py[], unsigned char R[], unsigned char S[]);
int SM2_SelfCheck();