xref: /freebsd/crypto/libecc/src/hash/sm3.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1 /*
2  *  Copyright (C) 2021 - This file is part of libecc project
3  *
4  *  Authors:
5  *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
6  *      Ryad BENADJILA <ryadbenadjila@gmail.com>
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  */
sm3_process(sm3_context * ctx,const u8 data[SM3_BLOCK_SIZE])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. */
sm3_init(sm3_context * ctx)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 */
sm3_update(sm3_context * ctx,const u8 * input,u32 ilen)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 */
sm3_final(sm3_context * ctx,u8 output[SM3_DIGEST_SIZE])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 
sm3_scattered(const u8 ** inputs,const u32 * ilens,u8 output[SM3_DIGEST_SIZE])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 
sm3(const u8 * input,u32 ilen,u8 output[SM3_DIGEST_SIZE])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