# 头文件定义
typedef struct {
unsigned int state[8]; // 寄存器中间状态
unsigned char buf[64]; // 待压缩消息
unsigned int cur_buf_len; // 当前待压缩消息长度(字节)
uint64_t compressed_len; // 已压缩消息长度(比特)
}gm_sm3_context;
/**
* 摘要算法初始化
* @param ctx 上下文
*/
void gm_sm3_init(gm_sm3_context * ctx);
/**
* 添加消息
* @param ctx 上下文
* @param input 消息
* @param iLen 消息长度(字节)
*/
void gm_sm3_update(gm_sm3_context * ctx, const unsigned char * input, unsigned int iLen);
/**
* 计算摘要
* @param ctx 上下文
* @param output 输出摘要结果
*/
void gm_sm3_done(gm_sm3_context * ctx, unsigned char * output);
/**
* 直接计算消息的摘要
* @param input 消息
* @param iLen 消息长度(字节)
* @param output 输出摘要结果
*/
void gm_sm3(const unsigned char * input, unsigned int iLen, unsigned char * output);
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
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
# gm_sm3_init
初始化函数,就是将寄存器的值初始化一下,长度这些初始化一下
void gm_sm3_init(gm_sm3_context * ctx) {
ctx->state[0] = GM_SM3_IV_A;
ctx->state[1] = GM_SM3_IV_B;
ctx->state[2] = GM_SM3_IV_C;
ctx->state[3] = GM_SM3_IV_D;
ctx->state[4] = GM_SM3_IV_E;
ctx->state[5] = GM_SM3_IV_F;
ctx->state[6] = GM_SM3_IV_G;
ctx->state[7] = GM_SM3_IV_H;
ctx->cur_buf_len = 0;
ctx->compressed_len = 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# gm_sm3_update
往摘要算法上下文中添加待计算的消息,每当消息长度满64字节(一个BlockSize)时,调用一次压缩算法进行压缩
void gm_sm3_update(gm_sm3_context * ctx, const unsigned char * input, unsigned int iLen) {
while (iLen--)
{
ctx->buf[ctx->cur_buf_len] = *input++;
ctx->cur_buf_len++;
/* 是否满64个字节 */
if (ctx->cur_buf_len == 64)
{
// 满了,则立即调用压缩函数进行压缩
gm_sm3_compress(ctx);
ctx->compressed_len += 512;
ctx->cur_buf_len = 0;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# gm_sm3_done
计算最终摘要值,计算前要把消息最终的长度及填充计算出来,然后再调用压缩算法计算最终结果
#ifndef GM_PUT_UINT32_BE
#define GM_PUT_UINT32_BE(n, b ,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
static const unsigned char gm_sm3_padding[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
void gm_sm3_done(gm_sm3_context * ctx, unsigned char * output) {
uint32_t padn;
unsigned char msglen[8];
uint64_t total_len, high, low;
// 消息的总长度(比特) = 剩余未压缩数据的长度(字节) * 8
total_len = ctx->compressed_len + (ctx->cur_buf_len << 3);
high = (total_len >> 32) & 0x0FFFFFFFF;
low = total_len & 0x0FFFFFFFF;
GM_PUT_UINT32_BE(high, msglen, 0);
GM_PUT_UINT32_BE(low, msglen, 4);
// 计算填充长度,因为事先要添加一比特,故应计算cur_buf_len + 1是否超过56
padn = ((ctx->cur_buf_len + 1) < 56) ? (56 - ctx->cur_buf_len) : (120 - ctx->cur_buf_len);
// 添加填充
gm_sm3_update(ctx, (unsigned char *) gm_sm3_padding, padn);
gm_sm3_update(ctx, msglen, 8);
GM_PUT_UINT32_BE(ctx->state[0], output, 0);
GM_PUT_UINT32_BE(ctx->state[1], output, 4);
GM_PUT_UINT32_BE(ctx->state[2], output, 8);
GM_PUT_UINT32_BE(ctx->state[3], output, 12);
GM_PUT_UINT32_BE(ctx->state[4], output, 16);
GM_PUT_UINT32_BE(ctx->state[5], output, 20);
GM_PUT_UINT32_BE(ctx->state[6], output, 24);
GM_PUT_UINT32_BE(ctx->state[7], output, 28);
}
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
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
# gm_sm3
void gm_sm3(const unsigned char * input, unsigned int iLen, unsigned char * output) {
gm_sm3_context ctx;
gm_sm3_init(&ctx);
gm_sm3_update(&ctx, input, iLen);
gm_sm3_done(&ctx, output);
}
1
2
3
4
5
6
2
3
4
5
6
# 单元测试
void test_gm_sm3(const unsigned char * input, unsigned int iLen, const unsigned char * output_hex) {
gm_sm3_context ctx;
int i = 0;
unsigned char buf[32] = {0};
char res[65] = {0};
gm_sm3(input, iLen, buf);
gm_sm3_init(&ctx);
gm_sm3_update(&ctx, input, iLen);
for(i = 0; i < 100000; i++) { // 10万次
gm_sm3(buf, 31, buf);
gm_sm3_update(&ctx, buf, i % 32);
}
gm_sm3_done(&ctx, buf);
for (i = 0; i < 32; i++) {
sprintf(res + i * 2, "%02X", (buf[i] & 0x0FF));
}
printf("r = %s\n", res);
printf("test result: %s\n", (strcmp(output_hex, res) == 0 ? "ok" : "fail"));
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
main函数增加:
if(strcmp(argv[1], "gm_sm3") == 0) {
test_gm_sm3("abc", 3, "DC7E07FF06247D00B4A8D1837C8F8B2A26C3C67C2EEE81B1E7CF9400B51891CB");
}
1
2
3
2
3
算法效率:
saintdeMacBook-Pro:bn saint$ time ./a.out gm_sm3
r = DC7E07FF06247D00B4A8D1837C8F8B2A26C3C67C2EEE81B1E7CF9400B51891CB
test result: ok
real 0m0.320s
user 0m0.312s
sys 0m0.005s
1
2
3
4
5
6
7
2
3
4
5
6
7
未经本人同意,禁止转载!