xref: /freebsd/crypto/libecc/src/examples/hash/mdc2.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1*f0865ec9SKyle Evans /*
2*f0865ec9SKyle Evans  *  Copyright (C) 2021 - This file is part of libecc project
3*f0865ec9SKyle Evans  *
4*f0865ec9SKyle Evans  *  Authors:
5*f0865ec9SKyle Evans  *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6*f0865ec9SKyle Evans  *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7*f0865ec9SKyle Evans  *
8*f0865ec9SKyle Evans  *  This software is licensed under a dual BSD and GPL v2 license.
9*f0865ec9SKyle Evans  *  See LICENSE file at the root folder of the project.
10*f0865ec9SKyle Evans  */
11*f0865ec9SKyle Evans #include "mdc2.h"
12*f0865ec9SKyle Evans 
13*f0865ec9SKyle Evans /* Include DES helpers */
14*f0865ec9SKyle Evans #include "tdes.h"
15*f0865ec9SKyle Evans 
mdc2_set_padding_type(mdc2_context * ctx,padding_type p)16*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_set_padding_type(mdc2_context *ctx,
17*f0865ec9SKyle Evans 								padding_type p)
18*f0865ec9SKyle Evans {
19*f0865ec9SKyle Evans 	int ret;
20*f0865ec9SKyle Evans 
21*f0865ec9SKyle Evans 	MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err);
22*f0865ec9SKyle Evans 
23*f0865ec9SKyle Evans 	/* We cannot change the padding type after the first update */
24*f0865ec9SKyle Evans 	MUST_HAVE((ctx->mdc2_total == 0), ret, err);
25*f0865ec9SKyle Evans 
26*f0865ec9SKyle Evans 	if((p != ISOIEC10118_TYPE1) && (p != ISOIEC10118_TYPE2)){
27*f0865ec9SKyle Evans 		ret = -1;
28*f0865ec9SKyle Evans 		goto err;
29*f0865ec9SKyle Evans 	}
30*f0865ec9SKyle Evans 
31*f0865ec9SKyle Evans 	ctx->padding = p;
32*f0865ec9SKyle Evans 
33*f0865ec9SKyle Evans 	ret = 0;
34*f0865ec9SKyle Evans 
35*f0865ec9SKyle Evans err:
36*f0865ec9SKyle Evans 	return ret;
37*f0865ec9SKyle Evans }
38*f0865ec9SKyle Evans 
39*f0865ec9SKyle Evans /* MDC-2 core processing. Returns 0 on success, -1 on error. */
mdc2_process(mdc2_context * ctx,const u8 data[MDC2_BLOCK_SIZE])40*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int mdc2_process(mdc2_context *ctx,
41*f0865ec9SKyle Evans 			   const u8 data[MDC2_BLOCK_SIZE])
42*f0865ec9SKyle Evans {
43*f0865ec9SKyle Evans 	int ret;
44*f0865ec9SKyle Evans 	unsigned int j;
45*f0865ec9SKyle Evans 	u8 V[8], W[8];
46*f0865ec9SKyle Evans 	u8 *A, *B;
47*f0865ec9SKyle Evans 	des_context des_ctx;
48*f0865ec9SKyle Evans 
49*f0865ec9SKyle Evans 	/* Get the current internal state in A and B */
50*f0865ec9SKyle Evans 	A = (u8*)&(ctx->mdc2_state[0]);
51*f0865ec9SKyle Evans 	B = (u8*)&(ctx->mdc2_state[8]);
52*f0865ec9SKyle Evans 
53*f0865ec9SKyle Evans 	A[0] = (u8)((A[0] & 0x9f) | 0x40);
54*f0865ec9SKyle Evans 	B[0] = (u8)((B[0] & 0x9f) | 0x20);
55*f0865ec9SKyle Evans 	/* Set odd parity */
56*f0865ec9SKyle Evans 	for(j = 0; j < 8; j++){
57*f0865ec9SKyle Evans 		A[j] = odd_parity[A[j]];
58*f0865ec9SKyle Evans 		B[j] = odd_parity[B[j]];
59*f0865ec9SKyle Evans 	}
60*f0865ec9SKyle Evans 	/* Compute V_i = M_i + E(M_i, A_i) */
61*f0865ec9SKyle Evans 	ret = local_memset(&des_ctx, 0, sizeof(des_context)); EG(ret, err);
62*f0865ec9SKyle Evans 	ret = des_set_key(&des_ctx, A, DES_ENCRYPTION); EG(ret, err);
63*f0865ec9SKyle Evans 	ret = des(&des_ctx, &data[0], V); EG(ret, err);
64*f0865ec9SKyle Evans 	for(j = 0; j < 8; j++){
65*f0865ec9SKyle Evans 		V[j] = (V[j] ^ data[j]);
66*f0865ec9SKyle Evans 	}
67*f0865ec9SKyle Evans 	/* Compute W_i = M_i + E(M_i, B_i) */
68*f0865ec9SKyle Evans 	ret = local_memset(&des_ctx, 0, sizeof(des_context)); EG(ret, err);
69*f0865ec9SKyle Evans 	ret = des_set_key(&des_ctx, B, DES_ENCRYPTION); EG(ret, err);
70*f0865ec9SKyle Evans 	ret = des(&des_ctx, &data[0], W); EG(ret, err);
71*f0865ec9SKyle Evans 	for(j = 0; j < 8; j++){
72*f0865ec9SKyle Evans 		W[j] = (W[j] ^ data[j]);
73*f0865ec9SKyle Evans 	}
74*f0865ec9SKyle Evans 	/* Cross the results */
75*f0865ec9SKyle Evans 	/* In A */
76*f0865ec9SKyle Evans 	ret = local_memcpy(&A[0], &V[0], 4); EG(ret, err);
77*f0865ec9SKyle Evans 	ret = local_memcpy(&A[4], &W[4], 4); EG(ret, err);
78*f0865ec9SKyle Evans 	/* In B */
79*f0865ec9SKyle Evans 	ret = local_memcpy(&B[0], &W[0], 4); EG(ret, err);
80*f0865ec9SKyle Evans 	ret = local_memcpy(&B[4], &V[4], 4); EG(ret, err);
81*f0865ec9SKyle Evans 
82*f0865ec9SKyle Evans err:
83*f0865ec9SKyle Evans 	return ret;
84*f0865ec9SKyle Evans }
85*f0865ec9SKyle Evans 
86*f0865ec9SKyle Evans /* Init hash function. Returns 0 on success, -1 on error. */
mdc2_init(mdc2_context * ctx)87*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_init(mdc2_context *ctx)
88*f0865ec9SKyle Evans {
89*f0865ec9SKyle Evans 	int ret;
90*f0865ec9SKyle Evans 
91*f0865ec9SKyle Evans 	MUST_HAVE((ctx != NULL), ret, err);
92*f0865ec9SKyle Evans 
93*f0865ec9SKyle Evans         /* Sanity check on size */
94*f0865ec9SKyle Evans 	MUST_HAVE((MDC2_DIGEST_SIZE <= MAX_DIGEST_SIZE), ret, err);
95*f0865ec9SKyle Evans 
96*f0865ec9SKyle Evans 	ctx->mdc2_total = 0;
97*f0865ec9SKyle Evans 	/* Initialize A1 */
98*f0865ec9SKyle Evans 	ret = local_memset(&(ctx->mdc2_state[0]), 0x52, 8); EG(ret, err);
99*f0865ec9SKyle Evans 	/* Initialize B1 */
100*f0865ec9SKyle Evans 	ret = local_memset(&(ctx->mdc2_state[8]), 0x25, 8); EG(ret, err);
101*f0865ec9SKyle Evans 	/* Initialize default padding type */
102*f0865ec9SKyle Evans 	ctx->padding = ISOIEC10118_TYPE1;
103*f0865ec9SKyle Evans 
104*f0865ec9SKyle Evans 	/* Tell that we are initialized */
105*f0865ec9SKyle Evans 	ctx->magic = MDC2_HASH_MAGIC;
106*f0865ec9SKyle Evans 
107*f0865ec9SKyle Evans 	ret = 0;
108*f0865ec9SKyle Evans 
109*f0865ec9SKyle Evans err:
110*f0865ec9SKyle Evans 	return ret;
111*f0865ec9SKyle Evans }
112*f0865ec9SKyle Evans 
mdc2_update(mdc2_context * ctx,const u8 * input,u32 ilen)113*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_update(mdc2_context *ctx, const u8 *input, u32 ilen)
114*f0865ec9SKyle Evans {
115*f0865ec9SKyle Evans 	const u8 *data_ptr = input;
116*f0865ec9SKyle Evans 	u32 remain_ilen = ilen;
117*f0865ec9SKyle Evans 	u16 fill;
118*f0865ec9SKyle Evans 	u8 left;
119*f0865ec9SKyle Evans 	int ret;
120*f0865ec9SKyle Evans 
121*f0865ec9SKyle Evans 	MUST_HAVE((input != NULL) || (ilen == 0), ret, err);
122*f0865ec9SKyle Evans 	MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err);
123*f0865ec9SKyle Evans 
124*f0865ec9SKyle Evans 	/* Nothing to process, return */
125*f0865ec9SKyle Evans 	if (ilen == 0) {
126*f0865ec9SKyle Evans 		ret = 0;
127*f0865ec9SKyle Evans 		goto err;
128*f0865ec9SKyle Evans 	}
129*f0865ec9SKyle Evans 
130*f0865ec9SKyle Evans 	/* Get what's left in our local buffer */
131*f0865ec9SKyle Evans 	left = (ctx->mdc2_total & 0xF);
132*f0865ec9SKyle Evans 	fill = (u16)(MDC2_BLOCK_SIZE - left);
133*f0865ec9SKyle Evans 
134*f0865ec9SKyle Evans 	ctx->mdc2_total += ilen;
135*f0865ec9SKyle Evans 
136*f0865ec9SKyle Evans 	if ((left > 0) && (remain_ilen >= fill)) {
137*f0865ec9SKyle Evans 		/* Copy data at the end of the buffer */
138*f0865ec9SKyle Evans 		ret = local_memcpy(ctx->mdc2_buffer + left, data_ptr, fill); EG(ret, err);
139*f0865ec9SKyle Evans 		ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err);
140*f0865ec9SKyle Evans 		data_ptr += fill;
141*f0865ec9SKyle Evans 		remain_ilen -= fill;
142*f0865ec9SKyle Evans 		left = 0;
143*f0865ec9SKyle Evans 	}
144*f0865ec9SKyle Evans 
145*f0865ec9SKyle Evans 	while (remain_ilen >= MDC2_BLOCK_SIZE) {
146*f0865ec9SKyle Evans 		ret = mdc2_process(ctx, data_ptr); EG(ret, err);
147*f0865ec9SKyle Evans 		data_ptr += MDC2_BLOCK_SIZE;
148*f0865ec9SKyle Evans 		remain_ilen -= MDC2_BLOCK_SIZE;
149*f0865ec9SKyle Evans 	}
150*f0865ec9SKyle Evans 
151*f0865ec9SKyle Evans 	if (remain_ilen > 0) {
152*f0865ec9SKyle Evans 		ret = local_memcpy(ctx->mdc2_buffer + left, data_ptr, remain_ilen); EG(ret, err);
153*f0865ec9SKyle Evans 	}
154*f0865ec9SKyle Evans 
155*f0865ec9SKyle Evans 	ret = 0;
156*f0865ec9SKyle Evans 
157*f0865ec9SKyle Evans err:
158*f0865ec9SKyle Evans 	return ret;
159*f0865ec9SKyle Evans }
160*f0865ec9SKyle Evans 
161*f0865ec9SKyle Evans /* Finalize. Returns 0 on success, -1 on error.*/
mdc2_final(mdc2_context * ctx,u8 output[MDC2_DIGEST_SIZE])162*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_final(mdc2_context *ctx, u8 output[MDC2_DIGEST_SIZE])
163*f0865ec9SKyle Evans {
164*f0865ec9SKyle Evans 	int ret;
165*f0865ec9SKyle Evans 	unsigned int i;
166*f0865ec9SKyle Evans 	u8 pad_byte;
167*f0865ec9SKyle Evans 
168*f0865ec9SKyle Evans 	MUST_HAVE((output != NULL), ret, err);
169*f0865ec9SKyle Evans 	MDC2_HASH_CHECK_INITIALIZED(ctx, ret, err);
170*f0865ec9SKyle Evans 
171*f0865ec9SKyle Evans 	if(ctx->padding == ISOIEC10118_TYPE1){
172*f0865ec9SKyle Evans 		/* "Padding method 1" in ISO-IEC-10118 */
173*f0865ec9SKyle Evans 		/* This is our final step, so we proceed with the padding: the last block
174*f0865ec9SKyle Evans 		 * is padded with zeroes.
175*f0865ec9SKyle Evans 		 */
176*f0865ec9SKyle Evans 		pad_byte = 0x00;
177*f0865ec9SKyle Evans 		if((ctx->mdc2_total % MDC2_BLOCK_SIZE) != 0){
178*f0865ec9SKyle Evans 			for(i = (ctx->mdc2_total % MDC2_BLOCK_SIZE); i < MDC2_BLOCK_SIZE; i++){
179*f0865ec9SKyle Evans 				ctx->mdc2_buffer[i] = pad_byte;
180*f0865ec9SKyle Evans 			}
181*f0865ec9SKyle Evans 			/* And process the block */
182*f0865ec9SKyle Evans 			ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err);
183*f0865ec9SKyle Evans 		}
184*f0865ec9SKyle Evans 	}
185*f0865ec9SKyle Evans 	else if(ctx->padding == ISOIEC10118_TYPE2){
186*f0865ec9SKyle Evans 		/* "Padding method 2" in ISO-IEC-10118 */
187*f0865ec9SKyle Evans 		/* This is our final step, so we proceed with the padding: the last block
188*f0865ec9SKyle Evans 		 * is appended 0x80 and then padded with zeroes.
189*f0865ec9SKyle Evans 		 */
190*f0865ec9SKyle Evans 		ctx->mdc2_buffer[(ctx->mdc2_total % MDC2_BLOCK_SIZE)] = 0x80;
191*f0865ec9SKyle Evans 		pad_byte = 0x00;
192*f0865ec9SKyle Evans 		for(i = ((unsigned int)(ctx->mdc2_total % MDC2_BLOCK_SIZE) + 1); i < MDC2_BLOCK_SIZE; i++){
193*f0865ec9SKyle Evans 			ctx->mdc2_buffer[i] = pad_byte;
194*f0865ec9SKyle Evans 		}
195*f0865ec9SKyle Evans 		/* And process the block */
196*f0865ec9SKyle Evans 		ret = mdc2_process(ctx, ctx->mdc2_buffer); EG(ret, err);
197*f0865ec9SKyle Evans 	}
198*f0865ec9SKyle Evans 	else{
199*f0865ec9SKyle Evans 		/* Unkown padding */
200*f0865ec9SKyle Evans 		ret = -1;
201*f0865ec9SKyle Evans 		goto err;
202*f0865ec9SKyle Evans 	}
203*f0865ec9SKyle Evans 
204*f0865ec9SKyle Evans 	/* Output the hash result */
205*f0865ec9SKyle Evans 	ret = local_memcpy(output, ctx->mdc2_state, MDC2_DIGEST_SIZE); EG(ret, err);
206*f0865ec9SKyle Evans 
207*f0865ec9SKyle Evans 	/* Tell that we are uninitialized */
208*f0865ec9SKyle Evans 	ctx->magic = WORD(0);
209*f0865ec9SKyle Evans 
210*f0865ec9SKyle Evans 	ret = 0;
211*f0865ec9SKyle Evans 
212*f0865ec9SKyle Evans err:
213*f0865ec9SKyle Evans 	return ret;
214*f0865ec9SKyle Evans }
215*f0865ec9SKyle Evans 
216*f0865ec9SKyle Evans 
217*f0865ec9SKyle Evans /*
218*f0865ec9SKyle Evans  * Scattered version performing init/update/finalize on a vector of buffers
219*f0865ec9SKyle Evans  * 'inputs' with the length of each buffer passed via 'ilens'. The function
220*f0865ec9SKyle Evans  * loops on pointers in 'inputs' until it finds a NULL pointer. The function
221*f0865ec9SKyle Evans  * returns 0 on success, -1 on error.
222*f0865ec9SKyle Evans  */
mdc2_scattered(const u8 ** inputs,const u32 * ilens,u8 output[MDC2_DIGEST_SIZE],padding_type p)223*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered(const u8 **inputs, const u32 *ilens,
224*f0865ec9SKyle Evans 		      u8 output[MDC2_DIGEST_SIZE], padding_type p)
225*f0865ec9SKyle Evans {
226*f0865ec9SKyle Evans 	mdc2_context ctx;
227*f0865ec9SKyle Evans 	int ret, pos = 0;
228*f0865ec9SKyle Evans 
229*f0865ec9SKyle Evans 	MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
230*f0865ec9SKyle Evans 
231*f0865ec9SKyle Evans 	ret = mdc2_init(&ctx); EG(ret, err);
232*f0865ec9SKyle Evans 
233*f0865ec9SKyle Evans 	ret = mdc2_set_padding_type(&ctx, p); EG(ret, err);
234*f0865ec9SKyle Evans 
235*f0865ec9SKyle Evans 	while (inputs[pos] != NULL) {
236*f0865ec9SKyle Evans 		ret = mdc2_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
237*f0865ec9SKyle Evans 		pos += 1;
238*f0865ec9SKyle Evans 	}
239*f0865ec9SKyle Evans 
240*f0865ec9SKyle Evans 	ret = mdc2_final(&ctx, output);
241*f0865ec9SKyle Evans 
242*f0865ec9SKyle Evans err:
243*f0865ec9SKyle Evans 	return ret;
244*f0865ec9SKyle Evans }
245*f0865ec9SKyle Evans 
246*f0865ec9SKyle Evans /*
247*f0865ec9SKyle Evans  * Scattered version performing init/update/finalize on a vector of buffers
248*f0865ec9SKyle Evans  * 'inputs' with the length of each buffer passed via 'ilens'. The function
249*f0865ec9SKyle Evans  * loops on pointers in 'inputs' until it finds a NULL pointer. The function
250*f0865ec9SKyle Evans  * returns 0 on success, -1 on error.
251*f0865ec9SKyle Evans  */
mdc2_scattered_padding1(const u8 ** inputs,const u32 * ilens,u8 output[MDC2_DIGEST_SIZE])252*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered_padding1(const u8 **inputs, const u32 *ilens,
253*f0865ec9SKyle Evans 		      u8 output[MDC2_DIGEST_SIZE])
254*f0865ec9SKyle Evans {
255*f0865ec9SKyle Evans 	return mdc2_scattered(inputs, ilens, output, ISOIEC10118_TYPE1);
256*f0865ec9SKyle Evans }
257*f0865ec9SKyle Evans 
258*f0865ec9SKyle Evans /*
259*f0865ec9SKyle Evans  * Scattered version performing init/update/finalize on a vector of buffers
260*f0865ec9SKyle Evans  * 'inputs' with the length of each buffer passed via 'ilens'. The function
261*f0865ec9SKyle Evans  * loops on pointers in 'inputs' until it finds a NULL pointer. The function
262*f0865ec9SKyle Evans  * returns 0 on success, -1 on error.
263*f0865ec9SKyle Evans  */
mdc2_scattered_padding2(const u8 ** inputs,const u32 * ilens,u8 output[MDC2_DIGEST_SIZE])264*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_scattered_padding2(const u8 **inputs, const u32 *ilens,
265*f0865ec9SKyle Evans 		      u8 output[MDC2_DIGEST_SIZE])
266*f0865ec9SKyle Evans {
267*f0865ec9SKyle Evans 	return mdc2_scattered(inputs, ilens, output, ISOIEC10118_TYPE2);
268*f0865ec9SKyle Evans }
269*f0865ec9SKyle Evans 
270*f0865ec9SKyle Evans /*
271*f0865ec9SKyle Evans  * Single call version performing init/update/final on given input.
272*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
273*f0865ec9SKyle Evans  */
mdc2(const u8 * input,u32 ilen,u8 output[MDC2_DIGEST_SIZE],padding_type p)274*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE], padding_type p)
275*f0865ec9SKyle Evans {
276*f0865ec9SKyle Evans 	mdc2_context ctx;
277*f0865ec9SKyle Evans 	int ret;
278*f0865ec9SKyle Evans 
279*f0865ec9SKyle Evans 	ret = mdc2_init(&ctx); EG(ret, err);
280*f0865ec9SKyle Evans 	ret = mdc2_set_padding_type(&ctx, p); EG(ret, err);
281*f0865ec9SKyle Evans 	ret = mdc2_update(&ctx, input, ilen); EG(ret, err);
282*f0865ec9SKyle Evans 	ret = mdc2_final(&ctx, output);
283*f0865ec9SKyle Evans 
284*f0865ec9SKyle Evans err:
285*f0865ec9SKyle Evans 	return ret;
286*f0865ec9SKyle Evans }
287*f0865ec9SKyle Evans 
288*f0865ec9SKyle Evans 
289*f0865ec9SKyle Evans /*
290*f0865ec9SKyle Evans  * Single call version performing init/update/final on given input.
291*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
292*f0865ec9SKyle Evans  */
mdc2_padding1(const u8 * input,u32 ilen,u8 output[MDC2_DIGEST_SIZE])293*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_padding1(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE])
294*f0865ec9SKyle Evans {
295*f0865ec9SKyle Evans 	return mdc2(input, ilen, output, ISOIEC10118_TYPE1);
296*f0865ec9SKyle Evans }
297*f0865ec9SKyle Evans 
298*f0865ec9SKyle Evans /*
299*f0865ec9SKyle Evans  * Single call version performing init/update/final on given input.
300*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
301*f0865ec9SKyle Evans  */
mdc2_padding2(const u8 * input,u32 ilen,u8 output[MDC2_DIGEST_SIZE])302*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET int mdc2_padding2(const u8 *input, u32 ilen, u8 output[MDC2_DIGEST_SIZE])
303*f0865ec9SKyle Evans {
304*f0865ec9SKyle Evans 	return mdc2(input, ilen, output, ISOIEC10118_TYPE2);
305*f0865ec9SKyle Evans }
306