Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/libecc/src/hash/sm3.c
34879 views
1
/*
2
* Copyright (C) 2021 - This file is part of libecc project
3
*
4
* Authors:
5
* Arnaud EBALARD <[email protected]>
6
* Ryad BENADJILA <[email protected]>
7
*
8
* This software is licensed under a dual BSD and GPL v2 license.
9
* See LICENSE file at the root folder of the project.
10
*/
11
#include <libecc/lib_ecc_config.h>
12
#ifdef WITH_HASH_SM3
13
14
#include <libecc/hash/sm3.h>
15
16
/*
17
* 32-bit integer manipulation macros (big endian)
18
*/
19
#ifndef GET_UINT32_BE
20
#define GET_UINT32_BE(n, b, i) \
21
do { \
22
(n) = ( ((u32) (b)[(i) ]) << 24 ) \
23
| ( ((u32) (b)[(i) + 1]) << 16 ) \
24
| ( ((u32) (b)[(i) + 2]) << 8 ) \
25
| ( ((u32) (b)[(i) + 3]) ); \
26
} while( 0 )
27
#endif
28
29
#ifndef PUT_UINT32_BE
30
#define PUT_UINT32_BE(n, b, i) \
31
do { \
32
(b)[(i) ] = (u8) ( (n) >> 24 ); \
33
(b)[(i) + 1] = (u8) ( (n) >> 16 ); \
34
(b)[(i) + 2] = (u8) ( (n) >> 8 ); \
35
(b)[(i) + 3] = (u8) ( (n) ); \
36
} while( 0 )
37
#endif
38
39
/*
40
* 64-bit integer manipulation macros (big endian)
41
*/
42
#ifndef PUT_UINT64_BE
43
#define PUT_UINT64_BE(n,b,i) \
44
do { \
45
(b)[(i) ] = (u8) ( (n) >> 56 ); \
46
(b)[(i) + 1] = (u8) ( (n) >> 48 ); \
47
(b)[(i) + 2] = (u8) ( (n) >> 40 ); \
48
(b)[(i) + 3] = (u8) ( (n) >> 32 ); \
49
(b)[(i) + 4] = (u8) ( (n) >> 24 ); \
50
(b)[(i) + 5] = (u8) ( (n) >> 16 ); \
51
(b)[(i) + 6] = (u8) ( (n) >> 8 ); \
52
(b)[(i) + 7] = (u8) ( (n) ); \
53
} while( 0 )
54
#endif /* PUT_UINT64_BE */
55
56
57
58
static const u32 SM3_Tj_low = 0x79cc4519;
59
static const u32 SM3_Tj_high = 0x7a879d8a;
60
61
/* Boolean functions FF_j and GG_j for 0 <= j <= 15 */
62
#define FF_j_low(X, Y, Z) (((u32)(X)) ^ ((u32)(Y)) ^ ((u32)(Z)))
63
#define GG_j_low(X, Y, Z) (((u32)(X)) ^ ((u32)(Y)) ^ ((u32)(Z)))
64
65
/* Boolean functions FF_j and GG_j for 16 <= j <= 63 */
66
#define FF_j_high(X, Y, Z) ((((u32)(X)) & ((u32)(Y))) | \
67
(((u32)(X)) & ((u32)(Z))) | \
68
(((u32)(Y)) & ((u32)(Z))))
69
#define GG_j_high(X, Y, Z) ((((u32)(X)) & ((u32)(Y))) | \
70
((~((u32)(X))) & ((u32)(Z))))
71
72
/* 32-bit bitwise cyclic shift. Only support shifts value y < 32 */
73
#define _SM3_ROTL_(x, y) ((((u32)(x)) << (y)) | \
74
(((u32)(x)) >> ((sizeof(u32) * 8) - (y))))
75
76
#define SM3_ROTL(x, y) ((((y) < (sizeof(u32) * 8)) && ((y) > 0)) ? (_SM3_ROTL_(x, y)) : (x))
77
78
/* Permutation Functions P_0 and P_1 */
79
#define SM3_P_0(X) (((u32)X) ^ SM3_ROTL((X), 9) ^ SM3_ROTL((X), 17))
80
#define SM3_P_1(X) (((u32)X) ^ SM3_ROTL((X), 15) ^ SM3_ROTL((X), 23))
81
82
/* SM3 Iterative Compression Process
83
* NOTE: ctx and data sanity checks are performed by the caller (this is an internal function)
84
*/
85
ATTRIBUTE_WARN_UNUSED_RET static int sm3_process(sm3_context *ctx, const u8 data[SM3_BLOCK_SIZE])
86
{
87
u32 A, B, C, D, E, F, G, H;
88
u32 SS1, SS2, TT1, TT2;
89
u32 W[68 + 64];
90
unsigned int j;
91
int ret;
92
93
/* Message Expansion Function ME */
94
95
for (j = 0; j < 16; j++) {
96
GET_UINT32_BE(W[j], data, 4 * j);
97
}
98
99
for (j = 16; j < 68; j++) {
100
W[j] = SM3_P_1(W[j - 16] ^ W[j - 9] ^ (SM3_ROTL(W[j - 3], 15))) ^
101
(SM3_ROTL(W[j - 13], 7)) ^ W[j - 6];
102
}
103
104
for (j = 0; j < 64; j++) {
105
W[j + 68] = W[j] ^ W[j + 4];
106
}
107
108
/* Compression Function CF */
109
110
A = ctx->sm3_state[0];
111
B = ctx->sm3_state[1];
112
C = ctx->sm3_state[2];
113
D = ctx->sm3_state[3];
114
E = ctx->sm3_state[4];
115
F = ctx->sm3_state[5];
116
G = ctx->sm3_state[6];
117
H = ctx->sm3_state[7];
118
119
/*
120
* Note: in a previous version of the code, we had two loops for j from
121
* 0 to 15 and then from 16 to 63 with SM3_ROTL(SM3_Tj_low, (j & 0x1F))
122
* inside but clang-12 was smart enough to detect cases where SM3_ROTL
123
* macro is useless. On the other side, clang address sanitizer does not
124
* allow to remove the check for too high shift values in the macro
125
* itself. Creating 3 distinct loops instead of 2 to remove the & 0x1F
126
* is sufficient to satisfy everyone.
127
*/
128
129
for (j = 0; j < 16; j++) {
130
SS1 = SM3_ROTL(SM3_ROTL(A, 12) + E + SM3_ROTL(SM3_Tj_low, j),7);
131
SS2 = SS1 ^ SM3_ROTL(A, 12);
132
TT1 = FF_j_low(A, B, C) + D + SS2 + W[j + 68];
133
TT2 = GG_j_low(E, F, G) + H + SS1 + W[j];
134
D = C;
135
C = SM3_ROTL(B, 9);
136
B = A;
137
A = TT1;
138
H = G;
139
G = SM3_ROTL(F, 19);
140
F = E;
141
E = SM3_P_0(TT2);
142
}
143
144
for (j = 16; j < 32; j++) {
145
SS1 = SM3_ROTL(SM3_ROTL(A, 12) + E + SM3_ROTL(SM3_Tj_high, j), 7);
146
SS2 = SS1 ^ SM3_ROTL(A, 12);
147
TT1 = FF_j_high(A, B, C) + D + SS2 + W[j + 68];
148
TT2 = GG_j_high(E, F, G) + H + SS1 + W[j];
149
D = C;
150
C = SM3_ROTL(B, 9);
151
B = A;
152
A = TT1;
153
H = G;
154
G = SM3_ROTL(F, 19);
155
F = E;
156
E = SM3_P_0(TT2);
157
}
158
159
for (j = 32; j < 64; j++) {
160
SS1 = SM3_ROTL(SM3_ROTL(A, 12) + E + SM3_ROTL(SM3_Tj_high, (j - 32)), 7);
161
SS2 = SS1 ^ SM3_ROTL(A, 12);
162
TT1 = FF_j_high(A, B, C) + D + SS2 + W[j + 68];
163
TT2 = GG_j_high(E, F, G) + H + SS1 + W[j];
164
D = C;
165
C = SM3_ROTL(B, 9);
166
B = A;
167
A = TT1;
168
H = G;
169
G = SM3_ROTL(F, 19);
170
F = E;
171
E = SM3_P_0(TT2);
172
}
173
174
ctx->sm3_state[0] ^= A;
175
ctx->sm3_state[1] ^= B;
176
ctx->sm3_state[2] ^= C;
177
ctx->sm3_state[3] ^= D;
178
ctx->sm3_state[4] ^= E;
179
ctx->sm3_state[5] ^= F;
180
ctx->sm3_state[6] ^= G;
181
ctx->sm3_state[7] ^= H;
182
183
ret = 0;
184
185
return ret;
186
}
187
188
/* Init hash function. Initialize state to SM3 defined IV. */
189
int sm3_init(sm3_context *ctx)
190
{
191
int ret;
192
193
MUST_HAVE(ctx != NULL, ret, err);
194
195
ctx->sm3_total = 0;
196
ctx->sm3_state[0] = 0x7380166F;
197
ctx->sm3_state[1] = 0x4914B2B9;
198
ctx->sm3_state[2] = 0x172442D7;
199
ctx->sm3_state[3] = 0xDA8A0600;
200
ctx->sm3_state[4] = 0xA96F30BC;
201
ctx->sm3_state[5] = 0x163138AA;
202
ctx->sm3_state[6] = 0xE38DEE4D;
203
ctx->sm3_state[7] = 0xB0FB0E4E;
204
205
/* Tell that we are initialized */
206
ctx->magic = SM3_HASH_MAGIC;
207
208
ret = 0;
209
210
err:
211
return ret;
212
}
213
214
/* Update hash function */
215
int sm3_update(sm3_context *ctx, const u8 *input, u32 ilen)
216
{
217
const u8 *data_ptr = input;
218
u32 remain_ilen = ilen;
219
u16 fill;
220
u8 left;
221
int ret;
222
223
MUST_HAVE((input != NULL) || (ilen == 0), ret, err);
224
SM3_HASH_CHECK_INITIALIZED(ctx, ret, err);
225
226
/* Nothing to process, return */
227
if (ilen == 0) {
228
ret = 0;
229
goto err;
230
}
231
232
/* Get what's left in our local buffer */
233
left = (ctx->sm3_total & 0x3F);
234
fill = (u16)(SM3_BLOCK_SIZE - left);
235
236
ctx->sm3_total += ilen;
237
238
if ((left > 0) && (remain_ilen >= fill)) {
239
/* Copy data at the end of the buffer */
240
ret = local_memcpy(ctx->sm3_buffer + left, data_ptr, fill); EG(ret, err);
241
ret = sm3_process(ctx, ctx->sm3_buffer); EG(ret, err);
242
data_ptr += fill;
243
remain_ilen -= fill;
244
left = 0;
245
}
246
247
while (remain_ilen >= SM3_BLOCK_SIZE) {
248
ret = sm3_process(ctx, data_ptr); EG(ret, err);
249
data_ptr += SM3_BLOCK_SIZE;
250
remain_ilen -= SM3_BLOCK_SIZE;
251
}
252
253
if (remain_ilen > 0) {
254
ret = local_memcpy(ctx->sm3_buffer + left, data_ptr, remain_ilen); EG(ret, err);
255
}
256
257
ret = 0;
258
259
err:
260
return ret;
261
}
262
263
/* Finalize */
264
int sm3_final(sm3_context *ctx, u8 output[SM3_DIGEST_SIZE])
265
{
266
unsigned int block_present = 0;
267
u8 last_padded_block[2 * SM3_BLOCK_SIZE];
268
int ret;
269
270
MUST_HAVE((output != NULL), ret, err);
271
SM3_HASH_CHECK_INITIALIZED(ctx, ret, err);
272
273
/* Fill in our last block with zeroes */
274
ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);
275
276
/* This is our final step, so we proceed with the padding */
277
block_present = (ctx->sm3_total % SM3_BLOCK_SIZE);
278
if (block_present != 0) {
279
/* Copy what's left in our temporary context buffer */
280
ret = local_memcpy(last_padded_block, ctx->sm3_buffer,
281
block_present); EG(ret, err);
282
}
283
284
/* Put the 0x80 byte, beginning of padding */
285
last_padded_block[block_present] = 0x80;
286
287
/* Handle possible additional block */
288
if (block_present > (SM3_BLOCK_SIZE - 1 - sizeof(u64))) {
289
/* We need an additional block */
290
PUT_UINT64_BE(8 * ctx->sm3_total, last_padded_block,
291
(2 * SM3_BLOCK_SIZE) - sizeof(u64));
292
ret = sm3_process(ctx, last_padded_block); EG(ret, err);
293
ret = sm3_process(ctx, last_padded_block + SM3_BLOCK_SIZE); EG(ret, err);
294
} else {
295
/* We do not need an additional block */
296
PUT_UINT64_BE(8 * ctx->sm3_total, last_padded_block,
297
SM3_BLOCK_SIZE - sizeof(u64));
298
ret = sm3_process(ctx, last_padded_block); EG(ret, err);
299
}
300
301
/* Output the hash result */
302
PUT_UINT32_BE(ctx->sm3_state[0], output, 0);
303
PUT_UINT32_BE(ctx->sm3_state[1], output, 4);
304
PUT_UINT32_BE(ctx->sm3_state[2], output, 8);
305
PUT_UINT32_BE(ctx->sm3_state[3], output, 12);
306
PUT_UINT32_BE(ctx->sm3_state[4], output, 16);
307
PUT_UINT32_BE(ctx->sm3_state[5], output, 20);
308
PUT_UINT32_BE(ctx->sm3_state[6], output, 24);
309
PUT_UINT32_BE(ctx->sm3_state[7], output, 28);
310
311
/* Tell that we are uninitialized */
312
ctx->magic = WORD(0);
313
314
ret = 0;
315
316
err:
317
return ret;
318
}
319
320
int sm3_scattered(const u8 **inputs, const u32 *ilens,
321
u8 output[SM3_DIGEST_SIZE])
322
{
323
sm3_context ctx;
324
int pos = 0, ret;
325
326
MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
327
328
ret = sm3_init(&ctx); EG(ret, err);
329
330
while (inputs[pos] != NULL) {
331
ret = sm3_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
332
pos += 1;
333
}
334
335
ret = sm3_final(&ctx, output);
336
337
err:
338
return ret;
339
}
340
341
int sm3(const u8 *input, u32 ilen, u8 output[SM3_DIGEST_SIZE])
342
{
343
sm3_context ctx;
344
int ret;
345
346
ret = sm3_init(&ctx); EG(ret, err);
347
ret = sm3_update(&ctx, input, ilen); EG(ret, err);
348
ret = sm3_final(&ctx, output);
349
350
err:
351
return ret;
352
}
353
354
#else /* WITH_HASH_SM3 */
355
356
/*
357
* Dummy definition to avoid the empty translation unit ISO C warning
358
*/
359
typedef int dummy;
360
#endif /* WITH_HASH_SM3 */
361
362