# 加密步骤
运算步骤:
- 用随机数发生器产生随机数k ∈ [1, n-1];
- 计算椭圆曲线点C1 = [k]G = (x1, y1),C1的存储方式为PC || x1 || y1,其中PC为固定值0x04;
- 计算椭圆曲线点[k]P = (x2, y2);
- 计算t = KDF(x2 || y2, klen),若t为全0比特串,则返回步骤1;
- 计算C2 = M ⊕ t;
- 计算C3 = Hash(x2 || M || y2);
- 输出密文C = C1 || C2 || C3。
# 解密步骤
运算步骤:
- 从C中取出比特串C1,将C1的数据类型转换为椭圆曲线上的点,验证C1是否满足椭圆曲线方程,若不满足则报错并退出;
- 计算[d]C1 = (x2, y2);
- 计算t = KDF(x2 || y2, klen),若t为全0比特串,则报错并退出;
- 从C中取出比特串C2,计算M′ = C2 ⊕ t;
- 计算u = Hash(x2 || M′ || y2),从C中取出比特串C3,若u ̸= C3,则报错并退出;
- 输出明文M′
# 定义
根据规范文档,我们也参考SM4的实现方式,分三步来实现加解密,即init、update、done。
定义如下:
typedef struct {
gm_bn_t private_key; // SM2私钥
gm_point_t public_key; // SM2公钥
unsigned char x2y2[64]; // SM2 crypt x2y2
gm_sm3_context sm3_ctx; // SM3上下文,用于计算加解密C3
unsigned char buf[32]; // 缓冲区,32字节为一个数据块
unsigned int cur_buf_len; // 当前缓冲区长度
unsigned int ct; // SM2 crypt ct,计算KDF
unsigned int state; // 标识是否为加密或是否为签名
} gm_sm2_context;
/**
* 加解密初始化
* @param ctx SM2上下文
* @param key 公钥PC||x||y或者yTile||x用于加密,私钥用于解密
* @param kLen 公钥长度必须为33或65,私钥为32字节
* @param forEncryption 1为加密,否则为解密
* @param c1 解密传入C1的值PC||x||y,加密时作为C1输出缓冲区
* @return 1返回成功,否则为密钥非法
*/
int gm_sm2_crypt_init(gm_sm2_context * ctx, const unsigned char * key, unsigned int kLen, int forEncryption, unsigned char * c1);
/**
* 加解密初始化,单元测试专用
* @param ctx SM2上下文
* @param key 公钥PC||x||y或者yTile||x用于加密,私钥用于解密
* @param kLen 公钥长度必须为33或65,私钥为32字节
* @param forEncryption 1为加密,否则为解密
* @param c1 解密传入C1的值PC||x||y,加密时作为C1输出缓冲区
* @param test_key 测试用密钥
* @return 1返回成功,否则为密钥非法
*/
int gm_sm2_crypt_init_for_test(gm_sm2_context * ctx, const unsigned char * key, unsigned int kLen,
int forEncryption, unsigned char * c1, const gm_bn_t test_key);
/**
* 加解密添加数据
* @param ctx SM2上下文
* @param input 待处理数据
* @param iLen 待处理数据长度
* @param output 输出缓冲区,必须是32字节的倍数,要比iLen大
* @return 返回已处理的数据长度
*/
int gm_sm2_crypt_update(gm_sm2_context * ctx, const unsigned char * input, unsigned int iLen, unsigned char * output);
/**
* 结束加解密
* @param ctx SM2上下文
* @param output 输出缓冲区,必须是32字节的倍数,至少为32字节
* @param c3 加解密都会输出C3,解密时,需要业务层再比较是否一致
* @return 返回已处理的数据长度
*/
int gm_sm2_crypt_done(gm_sm2_context * ctx, unsigned char * output, unsigned char * c3);
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
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
init时,如果是加密,则会输出加密C1部分,如果是解密的话,则要将C1当参数传入,用于计算过程数据。
update,添加待处理数据,满一轮(32字节)时,会立刻处理,并将结果输出至output中。
done,结束加解密,会将还未处理的数据进行处理,并将结果输出至output,并且计算hash值,输出至c3。
下面分别看一下三个函数的实现代码。
# gm_sm2_crypt_init
/**
* 检查公钥是否合法
* @param pub_key 公钥
* @return 1合法,否则非法
*/
static int gm_sm2_check_public_key(const gm_point_t * pub_key) {
if(gm_is_at_infinity(pub_key)) {
return 0;
}
gm_bn_t x, y, r;
gm_point_get_xy(pub_key, x, y);
if(gm_bn_is_zero(x) || gm_bn_cmp(x, GM_BN_P) >= 0) {
return 0;
}
if(gm_bn_is_zero(y) || gm_bn_cmp(y, GM_BN_P) >= 0) {
return 0;
}
//y^2 = x^3 + ax + b
gm_bn_to_mont(x, x, GM_BN_P);
gm_bn_to_mont(y, y, GM_BN_P);
// r = x ^ 2
gm_bn_sqr(r, x, GM_BN_P);
// r = x^2 + a
gm_bn_add(r, r, GM_BN_MONT_A, GM_BN_P);
// r = x^3 + ax
gm_bn_mont_mul(r, r, x, GM_BN_P);
// r = x^3 + ax + b
gm_bn_add(r, r, GM_BN_MONT_B, GM_BN_P);
gm_bn_sqr(y, y, GM_BN_P);
if(gm_bn_cmp(r, y) != 0) {
return 0;
}
return 1;
}
/**
* 加解密初始化
* @param ctx SM2上下文
* @param key 公钥PC||x||y或者yTile||x用于加密,私钥用于解密
* @param kLen 公钥长度必须为33或65,私钥为32字节
* @param forEncryption 1为加密,否则为解密
* @return 1返回成功,否则为密钥非法
*/
int gm_sm2_crypt_init(gm_sm2_context * ctx, const unsigned char * key, unsigned int kLen, int forEncryption, unsigned char * c1) {
gm_bn_t k;
uint8_t buf[256] = {0};
if(forEncryption) {
// rand k in [1, n - 1]
do {
do {
randombytes(buf, 256);
#ifdef GM_RAND_SM3
gm_sm3(buf, 256, buf);
#endif
gm_bn_from_bytes(k, buf);
} while (gm_bn_cmp(k, GM_BN_N) >= 0);
} while (gm_bn_is_zero(k));
}
return gm_sm2_crypt_init_for_test(ctx, key, kLen, forEncryption, c1, k);
}
int gm_sm2_crypt_init_for_test(gm_sm2_context * ctx, const unsigned char * key, unsigned int kLen,
int forEncryption, unsigned char * c1, const gm_bn_t test_key) {
gm_point_t p;
if(forEncryption) {
if((kLen != 33 && kLen != 65) || (key[0] != 0x04 && key[0] != 0x02 && key[0] != 0x03)) {
return 0;
}
// check public key
gm_point_decode(&ctx->public_key, key);
if(gm_sm2_check_public_key(&ctx->public_key) != 1) {
return 0;
}
gm_point_mul(&p, test_key, GM_MONT_G);
gm_point_to_bytes(&p, c1 + 1);
c1[0] = 0x04;
gm_point_mul(&p, test_key, &ctx->public_key);
gm_point_to_bytes(&p, ctx->x2y2);
}else {
if(kLen != 32) {
return 0;
}
gm_bn_from_bytes(ctx->private_key, key);
// check k ∈ [1, n-2]
if(gm_bn_is_zero(ctx->private_key) || gm_bn_cmp(ctx->private_key, GM_BN_N_SUB_ONE) >= 0) {
return 0;
}
// check public key
gm_point_mul(&ctx->public_key, ctx->private_key, GM_MONT_G);
if(gm_sm2_check_public_key(&ctx->public_key) != 1) {
return 0;
}
if(c1[0] == 0x04) {
gm_point_from_bytes(&p, c1 + 1);
}else {
gm_point_from_bytes(&p, c1);
}
gm_point_mul(&p, ctx->private_key, &p);
gm_point_to_bytes(&p, ctx->x2y2);
}
ctx->state = forEncryption;
ctx->cur_buf_len = 0;
ctx->ct = 1;
gm_sm3_init(&ctx->sm3_ctx);
gm_sm3_update(&ctx->sm3_ctx, ctx->x2y2, 32);
return 1;
}
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
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
# gm_sm2_crypt_update
/**
* 加解密一轮
* @param ctx SM2上下文
* @param output 输出缓冲区
* @param len 本轮待处理数据长度
*/
static void crypt_update_one_round(gm_sm2_context * ctx, unsigned char * output, int len) {
int i;
// KDF
gm_sm3_context sm3_ctx;
gm_sm3_init(&sm3_ctx);
gm_sm3_update(&sm3_ctx, ctx->x2y2, 64);
GM_PUT_UINT32_BE(ctx->ct, output, 0);
gm_sm3_update(&sm3_ctx, output, 4);
gm_sm3_done(&sm3_ctx, output);
for(i = 0; i < len; i++) {
output[i] ^= ctx->buf[i];
}
if(ctx->state) {
// 加密
gm_sm3_update(&ctx->sm3_ctx, ctx->buf, len);
}else {
// 解密
gm_sm3_update(&ctx->sm3_ctx, output, len);
}
ctx->cur_buf_len = 0;
ctx->ct++;
}
/**
* 加解密添加数据
* @param ctx SM2上下文
* @param input 待处理数据
* @param iLen 待处理数据长度
* @param output 输出缓冲区,必须是32字节的倍数,要比iLen大
* @return 返回已处理的数据长度
*/
int gm_sm2_crypt_update(gm_sm2_context * ctx, const unsigned char * input, unsigned int iLen, unsigned char * output) {
int rLen = 0;
while(iLen--) {
ctx->buf[ctx->cur_buf_len++] = *input++;
// 是否满一轮
if(ctx->cur_buf_len == 32) {
crypt_update_one_round(ctx, output + rLen, 32);
rLen += 32;
}
}
return rLen;
}
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
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
# gm_sm2_crypt_done
/**
* 结束加解密
* @param ctx SM2上下文
* @param output 输出缓冲区,必须是32字节的倍数,至少为32字节
* @param c3 加解密都会输出C3,解密时,需要业务层再比较是否一致
* @return 返回已处理的数据长度
*/
int gm_sm2_crypt_done(gm_sm2_context * ctx, unsigned char * output, unsigned char * c3) {
int rLen = ctx->cur_buf_len;
crypt_update_one_round(ctx, output, rLen);
gm_sm3_update(&ctx->sm3_ctx, ctx->x2y2 + 32, 32);
gm_sm3_done(&ctx->sm3_ctx, c3);
return rLen;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 单元测试
单元测试代码:
void test_sm2_crypt() {
gm_sm2_context ctx;
int i, j;
gm_bn_t k;
unsigned char testPrivK[32] = {0};
unsigned char testPubK[65] = {0};
unsigned char c3[32] = {0};
unsigned char buf[6536] = {0};
unsigned char output[6536] = {0};
gm_hex2bin("3D325BAA32B2A2437FFB471901FD7C0D218FEF5B9BCF5187431DC4B23330FB16", 64, testPrivK);
gm_hex2bin("04328B2B5CEB896FB409FAD358F8228F8FD17A9AED7F9C78B1D78AAD45D2514EA1CC615C5184B1CA6C8462DC3ED541E2D7666FEB6C5293FB1B7E60CBE8DF203D2F", 130, testPubK);
gm_bn_from_bytes(k, testPrivK);
buf[65] = 0x61;
buf[66] = 0x62;
buf[67] = 0x63;
for(i = 0; i < 100; i++) {
gm_sm2_crypt_init_for_test(&ctx, testPubK, 65, 1, output, k);
int rLen = gm_sm2_crypt_update(&ctx, buf + 65, 3 + i * 32, output + 65);
rLen += gm_sm2_crypt_done(&ctx, output + 65 + rLen, c3);
memcpy(buf, output, rLen + 65);
memcpy(buf + rLen + 65, c3, 32);
}
gm_hex2bin("04328B2B5CEB896FB409FAD358F8228F8FD17A9AED7F9C78B1D78AAD45D2514EA1CC615C5184B1CA6C8462DC3ED541E2D7666FEB6C5293FB1B7E60CBE8DF203D2F6162634E2DE036AE3AC2C07F99C9108427536B515CBC481E12450658E729992729F88A187A26E9D7CC99F63094948800C7E0A54162B66C0A29A44899A86180BBC41B9DC0924AF86EDD4ADB6B5382CC43FE39F7476609400D554ACD7843EFBC0E8ED25AD6F8AF0266578F9B5D3AA4E47888774BE4ECB0EB989F918A80550AE2AE99DE1FD88897653411DA756F249D11229D7220F2D57CD948CE508F45087A2B78D0D78F9A0A581EBDC5E7F8570E1E90000FCFA5D4DD53448535A46108ACF26D7517F2FE6AF4A85B7F8949CA41DECD7BA6C34AB8B4B3D3C485876C64B5A89AE71BF1732861F41F533A586F4B5043C41E54DFC007F2AF0B33939421E20972753F6893419512FB9D67DC95620BEB2EB5AD86A7493B67ECA5256770112C7FD7A165CD836ED70EDE3B3A8ECDDAFF2C3C65C00FF695E8309CCCCCCE61FDA5A68D29CFCB81A7391C5453F1657F42FEA3B3352A652264CEB8637A807A4D93862AF6FD7D49E33CBBBB96D4165A74F1B5CE28F83EF58A7639DFB2E9748469AE064ABA467091329DB56709873D90B257077EFA990CDFD33354E29280A9D6891027022031C607DD43A495925BC45E6E43422B19F68347EBF904FE318E6378A6A4E9BF1E6A4A0B35C388349975C2C2551F532F8FA78ED7C694768D1B1BAB445C906D9389CD0EF124CFC7D4719301D5D4A1A7B05550D1421AE1499458E5DF55520316B56A872212562CEC9E4CACB542D48C89F82B4702E0264DC0FCEAA1D1C93838AA62AD154F143D09E6A4DF3385AD186FC8AF846EEB40EB5D1CFE555AE726980F42BCAA5059138C48385A137CE3A59B5B8EFEAD18814F2D9820A732A338A85F6A47593628A6C4E55D3878D9AC243BDF016FACEB4275B1050A69B2469103EDD3BDE24B1FF74FE711076BCE4B0585474CD71A42580967306DA0B81E4B5F94B8B82E15029788CFB812D0B1C3F2A216EC18BDCEE1C8B5E6E2C533AABE001BA4AF3251C50D9BD71C8F912B0C0D52710E605B99634C7AFF6B7B27CF889A446F4FC61C0DE3B571AFE44A0BF6B83E7FCF3F077C5EA64A53EAC5525CFEF07BE67DE29E161E4C0B02CE303AEDDC4DAEE64B4CDCC19FB6772BAF2300A2B3B1A986D16EC0D0CC2CD2B19CCF39DA6300A4E99E873D07A7239FA8CC249BE98F5C54EFE607C2DA2B1C1D5E40540D92ABE1DF9A00CAB1BF3E64A63732F2458C3A1254A723F129017C3C0B2E6A4A8F6E9DCF079B3E0740210DE69E5B888FF388C7D9798316B8786169A69F70A61F26C9E8BE5F432245935409EC9E37BEACE9DBE8DD429EB1AF655EC269D70CCDBBCD81C2C8540E46D3DC9FC183A78EE4E875A68FD9DF84351D50F39608E706DA7DB38B14DE6C190C00D0A087AC4DBE0FB01B83A674266DD5EF770F22C06FF480F940877AE086DDD91207598B7DA1523906376F916493868559CC08BA84B5B2DBAE5645410B8AAA28D113FB2ECD4319B396473842C04330E0ECEC087AC8E41FC00F262767BD0C3C966E12D714661D703AECCFDBFAD068EF402FC32CC2956128DFE2CCD883445B0484545F0E53AC4D150F9F3F53AF7B7DFC85E8854C261979637D7C3B55AFEFE94F2ABA94F91EE07BF6AF4396A1E89F35E03B2D305ED36D1FA9ECAD6D4B8F7EBC724466F86B1502137683282EC188981213F93752663A05E6DB04090BF9CCE1B5F0F9D7522A6C4AC71DFFC0E50E73B03FB7C51BF2E536731281AC48FF20B871F930FEDBD5EE225BA345513815F58209F55083C9B6E2AB42D7A1DEC9E43CB121F69CAF28D6DABFFB5DA1A1A3AB4CFD38CF5B7F677E88E174B6AA3A1926BE55DA038A351452C471B496F457B9B6A054D33A513A91283365069128FF45E852654701C65ACD2DF98D2395C82E2818F7D1DD6729703A59E9CBEB8833D0463137B1D6E6A35BBB8D399C0994D13B5B37F3455C9225C8A421EED8005EE71E9FC794E627FE1672212961133354E2D2931A290E0A80DEAD21F15F1BDED014455D4B237AB814A4D138741AE4D59D32FBE88E20F5D21D78A45FBE86DF603D3FEACD7BDA51456E925741DEBC9A7362F0B84C4E00E9BA3B9336F9EB709204AB83400672D489C6F52A68E74ED7CA3BEE77D99210AA4A2A3A71ABA631CCC0E89A0727B84509924E9E8DB47EFB6DCBE2B362D0F1695BBD5C2FFD191098A8A330327040340DC1D72473EB6A0886D046D83FEC99B85AC2740A19E6195683A18E7DADBD97DB8D39F9E00F0B7FD68B26D494AA4090B23F7C7AB0B78117973EC217BA376317BB27A8A36FC52C533A911A24DB0865F42B3E87801FD305FFFDBA937C486B90F9EC9E245B9879E58D42B36EDD8787A21B386E65B0C47695EBCE27A95D70AF2311248E876DD7E36B41C6E6826C4FD22C50ACAF6E8C7E420E934F064D8C792F26212FB58C9AD32705CF859FFD18F5C67EF4DCBA50A37AD7FB01D839423554587CC67BA5955CA8EDBFE3B1242E4F6AA9E46DF41768C3A89BC9AEE371EC2E690A29AA057155B0066CEB08ED725FDA2E24DA37490DA54F36DB66FCB7C77CCB8CF19298C6A5089228B760A805EAE814927FCED1316E7EDB3F761937014B60C95364DF6E19571BD5A34527084FF3338080BD75F6D0E100ED3ADF5524F422CCBEDC5D40DAEE981573EC3B33F8CE76B3F368D02C413DEF85D80C247737FA5BC71835E056AFC87452A6EAB74F5A61D8A6B074304A5C49F4E178B480A43D2B4E7276E48D28FB05B35902399889E7FDFB2B11FBE1F2117A5B5A21CD07D586FFD0D564515C9E1895E75A12778FE493DBBEFACCFE104D97D5C4871D8A3940ECECFDB11427B94DDB05E8550F6E8C424D2FE5AF7C60B3CB2F01F8EA4128185F68FCDB7D744D3C5F2588F02DE5A14BBD5FD82AFA9D16117F5D59E985C4A44D73C53FFDD3B0660EF4BC5105519185D8A8D418426CEA651CFE6F6C7CEAA28940F3878D033DA544D3E9CCED970DDDAA46D4309BBFFB18DF814C9898DD4A38E07768C2D6F2688AB90665AF7F1E9666C04A770341A35421BC456F847B6A0437269CF05296BA014F3B957C4EE8148F63BE231F919BA11A890126BD7C50766EA2F90BE83A174657652A05C1F4D0FEE41CDBD35C2CAD83D922182C9035AA55F07EDA4A02F7782B341B676A310E4543932FF4C0A900FC36EA95D36642052A43AB9104729AFADEECD6C1324FA73F5C45173447706D3DD1654416D15406C81FF3F2880A4C9D1BF4CD81A156366802F6291B03E37B904A20C64FA2B3E1B5003671BA546E5D3FC05581F2A9F8CE76D527B6484F8AF48DD121A715647C1BF92AF77CD2362DDEBD0E597A8EFA425EDDC346B91D455F79802F8EAAFA563398DC8F7E55085C63F9E8F5A454CBFE52D612A9AFE00D4D06A35E72EA9F41D5A37C5C6994DA5F137FE2EE4EDAC77A74F7467CE176F8C901D2B90810CCF1BFFADD4DF04160FC2B2A5CA32E1E075D00B8E5C21F793AC7D244EAE46062DA59E0A291AAC16AD75F54CD15FD229E5FEA2C9FFDEB5C5A010C56E3CF03C2D60ECBA3158DA79BA0B1D46A40704421F772A894AF328A83122B73B7B8E760BB5DD5F148F5ABAC30DA980AB6958E7586CFB42811DDCC7F0A9E7ECE9C81DD1A63F9E433273282A0C2ED8C229F6D0732D5859662098B1F8CD22A5291654AEFC81F81607C99E4F8545C37C880335DFB065272396D408EB78B4A6EB64C5F7F51B79152283F540961E34B3AD0F648EC0CC982373FA9863F4BFD998F0E05770DB2CC411B30C4E498AC9C1CBFE3FE00B60C57E166E3192482BF31BD14192D18342F741DFFDDB60053B4EA0CD4F1AB5177BC6BF0F0F9D1186D7958BFF9A5EF1092F02980BE9D6A04E123633C8BC2BBDA800F38835642E9EEC9B4F1771F25BC6090FA1FF0F25AB58DD491ED7147703DFAC1668646659DE9D577868B269930EDD2A41B07B04F9E16D4C0FECCAFC9CDAB27472E276D975B4345043AB7843CA683DE2DDCECD773114AC75912FEA3D719C08959249A8DF46CA3B497A821A2EC3CA913FC5C777876800956FC1B8BFE27ADFF00673A5269972B4FA721A55548F9E9BDA5382D0F3C6AB0129D977AE86009A1A68C789B042F015C6097B6BE3613317B1BE8491077D24443B24A95B91DDD300564020FFB3D2B7537E82B6748766C87AD92FE7700899FB5909CBF749AE369DFA22F052ABD688AEBD6685F6EDFB4BC2E8F037AEDBCE2D824EEDDF96D1B7A2A3AECC102A3500BF108E00B6121287377482F2AEA4860F42F6B6D8FB3461738ED8860762D7714F9F6F46A18C47A970A40867411180849E37EF758C586E9E5C7373C2742AA9B7BB3CB88A698D2D73C1AC2BEBA9BC7FB51931E8BD0D33925005791C1763F3B81E9FDE3E55D6A0DC54ECDF15334A2BA28958248808F1A294BF1AAA16DDCE2649077D8CE244D6E84ACEDE2DA5B951294B318917568A04D785C827E09E2CCA28C5503C4156E81726C4263E06D932B337F78D65D2CE7DE25EEC60DBFA1B4259807DE14E11C23B3BC2475D20E84EDA715EDD636528404EBF9EFAC9BDCE1094735ED8AD588D886A6111155C3A7364E21649DC7B6",
6536, output);
if(memcmp(buf, output, 3268) != 0) {
printf("test result: fail1\n");
return;
}
for(i = 0; i < 100; i++) {
gm_sm2_crypt_init_for_test(&ctx, testPrivK, 32, 0, buf, NULL);
int rLen = gm_sm2_crypt_update(&ctx, buf + 65, 3268 - 97 - i * 32, output);
rLen += gm_sm2_crypt_done(&ctx, output + rLen, c3);
if(memcmp(buf + (3268 - 32 - i *32), c3, 32) != 0) {
printf("test result: fail2\n");
return;
}
memcpy(buf, testPubK, 65);
memcpy(buf + 65, output, rLen);
}
if(buf[65] != 0x61 || buf[66] != 0x62 || buf[67] != 0x63) {
printf("test result: fail3\n");
return;
}
for(i = 0; i < 100; i++) {
gm_sm2_crypt_init(&ctx, testPubK, 65, 1, output);
int rLen = gm_sm2_crypt_update(&ctx, buf + 65, 3, output + 65);
rLen += gm_sm2_crypt_done(&ctx, output + 65 + rLen, output + 68);
gm_sm2_crypt_init(&ctx, testPrivK, 32, 0, output);
rLen = gm_sm2_crypt_update(&ctx, output + 65, 3, buf + 65);
rLen += gm_sm2_crypt_done(&ctx, buf + 65 + rLen, buf + 68);
// check plain bytes
if(buf[65] != 0x61 || buf[66] != 0x62 || buf[67] != 0x63) {
printf("test result: fail4\n");
return;
}
// check c3
if(memcmp(buf + 68, output + 68, 32) != 0) {
printf("test result: fail5\n");
return;
}
}
printf("test result: ok\n");
}
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
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
main函数增加:
if(strcmp(argv[1], "sm2_crypt") == 0) {
test_sm2_crypt();
}
1
2
3
2
3
执行测试:
192:c saint$ time ./gm_test sm2_crypt
test result: ok
real 0m5.066s
user 0m5.027s
sys 0m0.023s
1
2
3
4
5
6
2
3
4
5
6
未经本人同意,禁止转载!