/ external / libecc / src / hash / sha384.c
sha384.c
  1  /*
  2   *  Copyright (C) 2017 - 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   *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
  8   *
  9   *  Contributors:
 10   *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
 11   *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
 12   *
 13   *  This software is licensed under a dual BSD and GPL v2 license.
 14   *  See LICENSE file at the root folder of the project.
 15   */
 16  #include <libecc/lib_ecc_config.h>
 17  #ifdef WITH_HASH_SHA384
 18  
 19  #include <libecc/hash/sha384.h>
 20  
 21  /* SHA-2 core processing. Returns 0 on success, -1 on error. */
 22  ATTRIBUTE_WARN_UNUSED_RET static int sha384_process(sha384_context *ctx,
 23  			   const u8 data[SHA384_BLOCK_SIZE])
 24  {
 25  	u64 a, b, c, d, e, f, g, h;
 26  	u64 W[80];
 27  	unsigned int i;
 28  	int ret;
 29  
 30  	MUST_HAVE((data != NULL), ret, err);
 31  	SHA384_HASH_CHECK_INITIALIZED(ctx, ret, err);
 32  
 33  	/* Init our inner variables */
 34  	a = ctx->sha384_state[0];
 35  	b = ctx->sha384_state[1];
 36  	c = ctx->sha384_state[2];
 37  	d = ctx->sha384_state[3];
 38  	e = ctx->sha384_state[4];
 39  	f = ctx->sha384_state[5];
 40  	g = ctx->sha384_state[6];
 41  	h = ctx->sha384_state[7];
 42  
 43  	for (i = 0; i < 16; i++) {
 44  		GET_UINT64_BE(W[i], data, 8 * i);
 45  		SHA2CORE_SHA512(a, b, c, d, e, f, g, h, W[i], K_SHA512[i]);
 46  	}
 47  
 48  	for (i = 16; i < 80; i++) {
 49  		SHA2CORE_SHA512(a, b, c, d, e, f, g, h, UPDATEW_SHA512(W, i),
 50  				K_SHA512[i]);
 51  	}
 52  
 53  	/* Update state */
 54  	ctx->sha384_state[0] += a;
 55  	ctx->sha384_state[1] += b;
 56  	ctx->sha384_state[2] += c;
 57  	ctx->sha384_state[3] += d;
 58  	ctx->sha384_state[4] += e;
 59  	ctx->sha384_state[5] += f;
 60  	ctx->sha384_state[6] += g;
 61  	ctx->sha384_state[7] += h;
 62  
 63  	ret = 0;
 64  
 65  err:
 66  	return ret;
 67  }
 68  
 69  /* Init hash function. Returns 0 on success, -1 on error. */
 70  int sha384_init(sha384_context *ctx)
 71  {
 72  	int ret;
 73  
 74  	MUST_HAVE((ctx != NULL), ret, err);
 75  
 76  	ctx->sha384_total[0] = ctx->sha384_total[1] = 0;
 77  	ctx->sha384_state[0] = (u64)(0xCBBB9D5DC1059ED8);
 78  	ctx->sha384_state[1] = (u64)(0x629A292A367CD507);
 79  	ctx->sha384_state[2] = (u64)(0x9159015A3070DD17);
 80  	ctx->sha384_state[3] = (u64)(0x152FECD8F70E5939);
 81  	ctx->sha384_state[4] = (u64)(0x67332667FFC00B31);
 82  	ctx->sha384_state[5] = (u64)(0x8EB44A8768581511);
 83  	ctx->sha384_state[6] = (u64)(0xDB0C2E0D64F98FA7);
 84  	ctx->sha384_state[7] = (u64)(0x47B5481DBEFA4FA4);
 85  
 86  	/* Tell that we are initialized */
 87  	ctx->magic = SHA384_HASH_MAGIC;
 88  	ret = 0;
 89  
 90  err:
 91  	return ret;
 92  }
 93  
 94  /* Update hash function. Returns 0 on success, -1 on error. */
 95  int sha384_update(sha384_context *ctx, const u8 *input, u32 ilen)
 96  {
 97  	u32 left;
 98  	u32 fill;
 99  	const u8 *data_ptr = input;
100  	u32 remain_ilen = ilen;
101  	int ret;
102  
103  	MUST_HAVE((input != NULL), ret, err);
104  	SHA384_HASH_CHECK_INITIALIZED(ctx, ret, err);
105  
106  	/* Nothing to process, return */
107  	if (ilen == 0) {
108  		ret = 0;
109  		goto err;
110  	}
111  
112  	/* Get what's left in our local buffer */
113  	left = (ctx->sha384_total[0] & 0x7F);
114  	fill = (SHA384_BLOCK_SIZE - left);
115  
116  	ADD_UINT128_UINT64(ctx->sha384_total[0], ctx->sha384_total[1], ilen);
117  
118  	if ((left > 0) && (remain_ilen >= fill)) {
119  		/* Copy data at the end of the buffer */
120  		ret = local_memcpy(ctx->sha384_buffer + left, data_ptr, fill); EG(ret, err);
121  		ret = sha384_process(ctx, ctx->sha384_buffer); EG(ret, err);
122  		data_ptr += fill;
123  		remain_ilen -= fill;
124  		left = 0;
125  	}
126  
127  	while (remain_ilen >= SHA384_BLOCK_SIZE) {
128  		ret = sha384_process(ctx, data_ptr); EG(ret, err);
129  		data_ptr += SHA384_BLOCK_SIZE;
130  		remain_ilen -= SHA384_BLOCK_SIZE;
131  	}
132  
133  	if (remain_ilen > 0) {
134  		ret = local_memcpy(ctx->sha384_buffer + left, data_ptr, remain_ilen); EG(ret, err);
135  	}
136  
137  	ret = 0;
138  
139  err:
140  	return ret;
141  }
142  
143  /*
144   * Finalize hash function. Returns 0 on success, -1 on error. In all
145   * cases (success or error), hash context is no more usable after the
146   * call.
147   */
148  int sha384_final(sha384_context *ctx, u8 output[SHA384_DIGEST_SIZE])
149  {
150  	unsigned int block_present = 0;
151  	u8 last_padded_block[2 * SHA384_BLOCK_SIZE];
152  	int ret;
153  
154  	MUST_HAVE((output != NULL), ret, err);
155  	SHA384_HASH_CHECK_INITIALIZED(ctx, ret, err);
156  
157  	/* Fill in our last block with zeroes */
158  	ret = local_memset(last_padded_block, 0, sizeof(last_padded_block)); EG(ret, err);
159  
160  	/* This is our final step, so we proceed with the padding */
161  	block_present = (ctx->sha384_total[0] % SHA384_BLOCK_SIZE);
162  	if (block_present != 0) {
163  		/* Copy what's left in our temporary context buffer */
164  		ret = local_memcpy(last_padded_block, ctx->sha384_buffer,
165  			     block_present); EG(ret, err);
166  	}
167  
168  	/* Put the 0x80 byte, beginning of padding  */
169  	last_padded_block[block_present] = 0x80;
170  
171  	/* Handle possible additional block */
172  	if (block_present > (SHA384_BLOCK_SIZE - 1 - (2 * sizeof(u64)))) {
173  		/* We need an additional block */
174  		PUT_MUL8_UINT128_BE(ctx->sha384_total[0], ctx->sha384_total[1],
175  				    last_padded_block,
176  				    2 * (SHA384_BLOCK_SIZE - sizeof(u64)));
177  		ret = sha384_process(ctx, last_padded_block); EG(ret, err);
178  		ret = sha384_process(ctx, last_padded_block + SHA384_BLOCK_SIZE); EG(ret, err);
179  	} else {
180  		/* We do not need an additional block */
181  		PUT_MUL8_UINT128_BE(ctx->sha384_total[0], ctx->sha384_total[1],
182  				    last_padded_block,
183  				    SHA384_BLOCK_SIZE - (2 * sizeof(u64)));
184  		ret = sha384_process(ctx, last_padded_block); EG(ret, err);
185  	}
186  
187  	/* Output the hash result */
188  	PUT_UINT64_BE(ctx->sha384_state[0], output, 0);
189  	PUT_UINT64_BE(ctx->sha384_state[1], output, 8);
190  	PUT_UINT64_BE(ctx->sha384_state[2], output, 16);
191  	PUT_UINT64_BE(ctx->sha384_state[3], output, 24);
192  	PUT_UINT64_BE(ctx->sha384_state[4], output, 32);
193  	PUT_UINT64_BE(ctx->sha384_state[5], output, 40);
194  
195  	/* Tell that we are uninitialized */
196  	ctx->magic = WORD(0);
197  
198  	ret = 0;
199  
200  err:
201  	return ret;
202  }
203  
204  /*
205   * Scattered version performing init/update/finalize on a vector of buffers
206   * 'inputs' with the length of each buffer passed via 'ilens'. The function
207   * loops on pointers in 'inputs' until it finds a NULL pointer. The function
208   * returns 0 on success, -1 on error.
209   */
210  int sha384_scattered(const u8 **inputs, const u32 *ilens,
211  		      u8 output[SHA384_DIGEST_SIZE])
212  {
213  	sha384_context ctx;
214  	int pos = 0;
215  	int ret;
216  
217  	MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
218  
219  	ret = sha384_init(&ctx); EG(ret, err);
220  
221  	while (inputs[pos] != NULL) {
222  		const u8 *buf = inputs[pos];
223  		u32 buflen = ilens[pos];
224  
225  		ret = sha384_update(&ctx, buf, buflen); EG(ret, err);
226  		pos += 1;
227  	}
228  
229  	ret = sha384_final(&ctx, output);
230  
231  err:
232  	return ret;
233  }
234  
235  /* init/update/finalize on a single buffer 'input' of length 'ilen'. */
236  int sha384(const u8 *input, u32 ilen, u8 output[SHA384_DIGEST_SIZE])
237  {
238  	sha384_context ctx;
239  	int ret;
240  
241  	ret = sha384_init(&ctx); EG(ret, err);
242  	ret = sha384_update(&ctx, input, ilen); EG(ret, err);
243  	ret = sha384_final(&ctx, output);
244  
245  err:
246  	return ret;
247  }
248  
249  #else /* WITH_HASH_SHA384 */
250  
251  /*
252   * Dummy definition to avoid the empty translation unit ISO C warning
253   */
254  typedef int dummy;
255  #endif /* WITH_HASH_SHA384 */