xref: /freebsd/crypto/libecc/src/hash/streebog.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1 /*
2  *  Copyright (C) 2021 - This file is part of libecc project
3  *
4  *  Authors:
5  *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6  *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
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 #if defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512)
13 
14 /*
15  * NOTE: we put STREEBOG256 and STREEBOG512 in the same compilation unit on
16  * purpose, so that we avoid duplicating the rather big tables that are shared
17  * between the two digest versions.
18  */
19 
20 #include <libecc/utils/utils.h>
21 #if defined(WITH_HASH_STREEBOG256)
22 #include <libecc/hash/streebog256.h>
23 #endif
24 #if defined(WITH_HASH_STREEBOG512)
25 #include <libecc/hash/streebog512.h>
26 #endif
27 
28 /*** Generic functions for both STREEBOG256 and STREEBOG512 ***/
29 /* Init */
streebog_init(streebog_context * ctx,u8 digest_size,u8 block_size)30 ATTRIBUTE_WARN_UNUSED_RET static int streebog_init(streebog_context *ctx, u8 digest_size, u8 block_size)
31 {
32 	int ret;
33 
34 	/* Sanity check */
35 	MUST_HAVE((digest_size == STREEBOG256_DIGEST_SIZE) || (digest_size == STREEBOG512_DIGEST_SIZE), ret, err);
36 
37 	MUST_HAVE((ctx != NULL), ret, err);
38 
39 	/* Zeroize the internal state */
40 	ret = local_memset(ctx, 0, sizeof(streebog_context)); EG(ret, err);
41 
42 	if(digest_size == 32){
43 		ret = local_memset(ctx->h, 1, sizeof(ctx->h)); EG(ret, err);
44 	}
45 
46 	/* Initialize our digest size and block size */
47 	ctx->streebog_digest_size = digest_size;
48 	ctx->streebog_block_size = block_size;
49 	/* Detect endianness */
50 	ctx->streebog_endian = arch_is_big_endian() ? STREEBOG_BIG : STREEBOG_LITTLE;
51 
52 err:
53 	return ret;
54 }
55 
streebog_update(streebog_context * ctx,const u8 * input,u32 ilen)56 ATTRIBUTE_WARN_UNUSED_RET static int streebog_update(streebog_context *ctx, const u8 *input, u32 ilen)
57 {
58 	const u8 *data_ptr = input;
59 	u32 remain_ilen = ilen;
60 	u16 fill;
61 	u8 left;
62 	int ret;
63 
64 	MUST_HAVE((ctx != NULL) && ((input != NULL) || (ilen == 0)), ret, err);
65 
66 	/* Nothing to process, return */
67 	if (ilen == 0) {
68 		ret = 0;
69 		goto err;
70 	}
71 
72 	/* Get what's left in our local buffer */
73 	left = (ctx->streebog_total & 0x3F);
74 	fill = (u16)(STREEBOG_BLOCK_SIZE - left);
75 
76 	ctx->streebog_total += ilen;
77 
78 	if ((left > 0) && (remain_ilen >= fill)) {
79 		/* Copy data at the end of the buffer */
80 		ret = local_memcpy(ctx->streebog_buffer + left, data_ptr, fill); EG(ret, err);
81 		streebog_process(ctx, ctx->streebog_buffer, (8 * STREEBOG_BLOCK_SIZE));
82 		data_ptr += fill;
83 		remain_ilen -= fill;
84 		left = 0;
85 	}
86 
87 	while (remain_ilen >= STREEBOG_BLOCK_SIZE) {
88 		streebog_process(ctx, data_ptr, (8 * STREEBOG_BLOCK_SIZE));
89 		data_ptr += STREEBOG_BLOCK_SIZE;
90 		remain_ilen -= STREEBOG_BLOCK_SIZE;
91 	}
92 
93 	if (remain_ilen > 0) {
94 		ret = local_memcpy(ctx->streebog_buffer + left, data_ptr, remain_ilen); EG(ret, err);
95 	}
96 
97 	ret = 0;
98 
99 err:
100 	return ret;
101 }
102 
streebog_final(streebog_context * ctx,u8 * output)103 ATTRIBUTE_WARN_UNUSED_RET static int streebog_final(streebog_context *ctx, u8 *output)
104 {
105 	unsigned int block_present = 0;
106 	u8 last_padded_block[STREEBOG_BLOCK_SIZE];
107 	u64 Z[STREEBOG_BLOCK_U64_SIZE];
108 	unsigned int j;
109 	u8 digest_size;
110 	u8 idx;
111 	int ret;
112 
113 	MUST_HAVE((ctx != NULL) && (output != NULL), ret, err);
114 
115 	digest_size = ctx->streebog_digest_size;
116 	/* Sanity check */
117 	MUST_HAVE((digest_size == 32) || (digest_size == 64), ret, err);
118 
119 	/* Zero init our Z */
120 	ret = local_memset(Z, 0, sizeof(Z)); EG(ret, err);
121 
122 	/* Fill in our last block with zeroes */
123 	ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);
124 
125 	/* This is our final step, so we proceed with the padding */
126 	block_present = (ctx->streebog_total % STREEBOG_BLOCK_SIZE);
127 	if (block_present != 0) {
128 		/* Copy what's left in our temporary context buffer */
129 		ret = local_memcpy(last_padded_block, ctx->streebog_buffer,
130 			     block_present); EG(ret, err);
131 	}
132 
133 	/* Put the 0x01 byte, beginning of padding  */
134 	last_padded_block[block_present] = 0x01;
135 
136 	streebog_process(ctx, last_padded_block, (8 * (ctx->streebog_total % STREEBOG_BLOCK_SIZE)));
137 
138 	gN(ctx->h, ctx->N, Z);
139 	gN(ctx->h, ctx->Sigma, Z);
140 
141 	for(j = 0; j < STREEBOG_BLOCK_U64_SIZE; j++){
142 		ctx->h[j] = S64(ctx->h[j]);
143 	}
144 
145 	idx = 0;
146 
147 	if(digest_size == 64){
148 		/* 512-bit hash case */
149 		STREEBOG_PUT_UINT64(ctx->h[0], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
150 		STREEBOG_PUT_UINT64(ctx->h[1], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
151 		STREEBOG_PUT_UINT64(ctx->h[2], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
152 		STREEBOG_PUT_UINT64(ctx->h[3], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
153 	}
154 	/* 256 and 512-bit hash case */
155 	STREEBOG_PUT_UINT64(ctx->h[4], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
156 	STREEBOG_PUT_UINT64(ctx->h[5], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
157 	STREEBOG_PUT_UINT64(ctx->h[6], output, idx, ctx->streebog_endian); idx = (u8)(idx + 8);
158 	STREEBOG_PUT_UINT64(ctx->h[7], output, idx, ctx->streebog_endian);
159 
160 	ret = 0;
161 
162 err:
163 	return ret;
164 }
165 
166 #if defined(WITH_HASH_STREEBOG256)
167 
168 /* Init */
streebog256_init(streebog256_context * ctx)169 int streebog256_init(streebog256_context *ctx)
170 {
171 	int ret;
172 
173 	ret = streebog_init(ctx, STREEBOG256_DIGEST_SIZE, STREEBOG256_BLOCK_SIZE); EG(ret, err);
174 
175 	ctx->magic = STREEBOG256_HASH_MAGIC;
176 
177 err:
178 	return ret;
179 }
180 
181 /* Update */
streebog256_update(streebog256_context * ctx,const u8 * input,u32 ilen)182 int streebog256_update(streebog256_context *ctx, const u8 *input, u32 ilen)
183 {
184 	int ret;
185 
186 	STREEBOG256_HASH_CHECK_INITIALIZED(ctx, ret, err);
187 
188 	ret = streebog_update(ctx, input, ilen);
189 
190 err:
191 	return ret;
192 }
193 
194 /* Finalize */
streebog256_final(streebog256_context * ctx,u8 output[STREEBOG256_DIGEST_SIZE])195 int streebog256_final(streebog256_context *ctx,
196 		       u8 output[STREEBOG256_DIGEST_SIZE])
197 {
198 	int ret;
199 
200 	STREEBOG256_HASH_CHECK_INITIALIZED(ctx, ret, err);
201 
202 	ret = streebog_final(ctx, output); EG(ret, err);
203 
204 	/* Uninit our context magic */
205 	ctx->magic = WORD(0);
206 
207 	ret = 0;
208 
209 err:
210 	return ret;
211 }
212 
streebog256_scattered(const u8 ** inputs,const u32 * ilens,u8 output[STREEBOG256_DIGEST_SIZE])213 int streebog256_scattered(const u8 **inputs, const u32 *ilens,
214 			   u8 output[STREEBOG256_DIGEST_SIZE])
215 {
216 	streebog256_context ctx;
217 	int pos = 0;
218 	int ret;
219 
220 	MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
221 
222 	ret = streebog256_init(&ctx); EG(ret, err);
223 
224 	while (inputs[pos] != NULL) {
225 		ret = streebog256_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
226 		pos += 1;
227 	}
228 
229 	ret = streebog256_final(&ctx, output);
230 
231 err:
232 	return ret;
233 }
234 
streebog256(const u8 * input,u32 ilen,u8 output[STREEBOG256_DIGEST_SIZE])235 int streebog256(const u8 *input, u32 ilen, u8 output[STREEBOG256_DIGEST_SIZE])
236 {
237 	int ret;
238 	streebog256_context ctx;
239 
240 	ret = streebog256_init(&ctx); EG(ret, err);
241 	ret = streebog256_update(&ctx, input, ilen); EG(ret, err);
242 	ret = streebog256_final(&ctx, output);
243 
244 err:
245 	return ret;
246 }
247 
248 #endif /* defined(WITH_HASH_STREEBOG256) */
249 
250 
251 #if defined(WITH_HASH_STREEBOG512)
252 
253 /* Init */
streebog512_init(streebog512_context * ctx)254 int streebog512_init(streebog512_context *ctx)
255 {
256 	int ret;
257 
258 	ret = streebog_init(ctx, STREEBOG512_DIGEST_SIZE, STREEBOG512_BLOCK_SIZE); EG(ret, err);
259 
260 	ctx->magic = STREEBOG512_HASH_MAGIC;
261 
262 	ret = 0;
263 
264 err:
265 	return ret;
266 }
267 
268 /* Update */
streebog512_update(streebog512_context * ctx,const u8 * input,u32 ilen)269 int streebog512_update(streebog512_context *ctx, const u8 *input, u32 ilen)
270 {
271 	int ret;
272 
273 	STREEBOG512_HASH_CHECK_INITIALIZED(ctx, ret, err);
274 
275 	ret = streebog_update(ctx, input, ilen);
276 
277 err:
278 	return ret;
279 }
280 
281 /* Finalize */
streebog512_final(streebog512_context * ctx,u8 output[STREEBOG512_DIGEST_SIZE])282 int streebog512_final(streebog512_context *ctx,
283 		       u8 output[STREEBOG512_DIGEST_SIZE])
284 {
285 	int ret;
286 
287 	STREEBOG512_HASH_CHECK_INITIALIZED(ctx, ret, err);
288 
289 	ret = streebog_final(ctx, output); EG(ret, err);
290 
291 	/* Uninit our context magic */
292 	ctx->magic = WORD(0);
293 
294 	ret = 0;
295 
296 err:
297 	return ret;
298 }
299 
streebog512_scattered(const u8 ** inputs,const u32 * ilens,u8 output[STREEBOG512_DIGEST_SIZE])300 int streebog512_scattered(const u8 **inputs, const u32 *ilens,
301 			   u8 output[STREEBOG512_DIGEST_SIZE])
302 {
303 	streebog512_context ctx;
304 	int pos = 0;
305 	int ret;
306 
307 	MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
308 
309 	ret = streebog512_init(&ctx); EG(ret, err);
310 
311 	while (inputs[pos] != NULL) {
312 		ret = streebog512_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
313 		pos += 1;
314 	}
315 
316 	ret = streebog512_final(&ctx, output);
317 
318 err:
319 	return ret;
320 }
321 
streebog512(const u8 * input,u32 ilen,u8 output[STREEBOG512_DIGEST_SIZE])322 int streebog512(const u8 *input, u32 ilen, u8 output[STREEBOG512_DIGEST_SIZE])
323 {
324 	int ret;
325 	streebog512_context ctx;
326 
327 	ret = streebog512_init(&ctx); EG(ret, err);
328 	ret = streebog512_update(&ctx, input, ilen); EG(ret, err);
329 	ret = streebog512_final(&ctx, output);
330 
331 err:
332 	return ret;
333 }
334 
335 #endif /* defined(WITH_HASH_STREEBOG512) */
336 
337 #else /* !(defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512)) */
338 /*
339  * Dummy definition to avoid the empty translation unit ISO C warning
340  */
341 typedef int dummy;
342 
343 #endif /* defined(WITH_HASH_STREEBOG256) || defined(WITH_HASH_STREEBOG512) */
344 
345