/ external / libecc / src / hash / hmac.c
hmac.c
  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  #ifdef WITH_HMAC
 13  
 14  #include <libecc/hash/hmac.h>
 15  
 16  int hmac_init(hmac_context *ctx, const u8 *hmackey, u32 hmackey_len,
 17  	      hash_alg_type hash_type)
 18  {
 19  	u8 ipad[MAX_BLOCK_SIZE];
 20  	u8 opad[MAX_BLOCK_SIZE];
 21  	u8 local_hmac_key[MAX_BLOCK_SIZE];
 22  	unsigned int i, local_hmac_key_len;
 23  	int ret;
 24  	const hash_mapping *h;
 25  
 26  	MUST_HAVE((ctx != NULL) && (hmackey != NULL), ret, err);
 27  
 28  	ret = local_memset(local_hmac_key, 0, sizeof(local_hmac_key)); EG(ret, err);
 29  	/* Set ipad and opad to appropriate values */
 30  	ret = local_memset(ipad, 0x36, sizeof(ipad)); EG(ret, err);
 31  	ret = local_memset(opad, 0x5c, sizeof(opad)); EG(ret, err);
 32  
 33  	/* Get the hash mapping of the current asked hash function */
 34  	ret = get_hash_by_type(hash_type, &(ctx->hash)); EG(ret, err);
 35  	MUST_HAVE((ctx->hash != NULL), ret, err);
 36  
 37  	/* Make things more readable */
 38  	h = ctx->hash;
 39  
 40  	if(hmackey_len <= ctx->hash->block_size){
 41  		/* The key size is less than the hash function block size */
 42  		ret = local_memcpy(local_hmac_key, hmackey, hmackey_len); EG(ret, err);
 43  		local_hmac_key_len = hmackey_len;
 44  	}
 45  	else{
 46  		/* The key size is greater than the hash function block size.
 47  		 * We hash it to shorten it.
 48  		 */
 49  		hash_context tmp_ctx;
 50  		/* Check our callback */
 51  		ret = hash_mapping_callbacks_sanity_check(h); EG(ret, err);
 52  		ret = h->hfunc_init(&tmp_ctx); EG(ret, err);
 53  		ret = h->hfunc_update(&tmp_ctx, hmackey, hmackey_len); EG(ret, err);
 54  		ret = h->hfunc_finalize(&tmp_ctx, local_hmac_key); EG(ret, err);
 55  		local_hmac_key_len = h->digest_size;
 56  	}
 57  
 58  	/* Initialize our input and output hash contexts */
 59  	/* Check our callback */
 60  	ret = hash_mapping_callbacks_sanity_check(h); EG(ret, err);
 61  	ret = h->hfunc_init(&(ctx->in_ctx)); EG(ret, err);
 62  	/* Check our callback */
 63  	ret = hash_mapping_callbacks_sanity_check(h); EG(ret, err);
 64  	ret = h->hfunc_init(&(ctx->out_ctx)); EG(ret, err);
 65  
 66  	/* Update our input context with K^ipad */
 67  	for(i = 0; i < local_hmac_key_len; i++){
 68  		ipad[i] ^= local_hmac_key[i];
 69  	}
 70  	ret = h->hfunc_update(&(ctx->in_ctx), ipad, h->block_size); EG(ret, err);
 71  	/* Update our output context with K^opad */
 72  	for(i = 0; i < local_hmac_key_len; i++){
 73  		opad[i] ^= local_hmac_key[i];
 74  	}
 75  	ret = h->hfunc_update(&(ctx->out_ctx), opad, h->block_size); EG(ret, err);
 76  
 77  	/* Initialize our magic */
 78  	ctx->magic = HMAC_MAGIC;
 79  
 80  err:
 81  	return ret;
 82  }
 83  
 84  int hmac_update(hmac_context *ctx, const u8 *input, u32 ilen)
 85  {
 86  	int ret;
 87  	const hash_mapping *h;
 88  
 89  	HMAC_CHECK_INITIALIZED(ctx, ret, err);
 90  	MUST_HAVE((input != NULL) || (ilen == 0), ret, err);
 91  
 92  	/* Make things more readable */
 93  	h = ctx->hash;
 94  	/* Check our callback */
 95  	ret = hash_mapping_callbacks_sanity_check(h); EG(ret, err);
 96  	ret = h->hfunc_update(&(ctx->in_ctx), input, ilen); EG(ret, err);
 97  
 98  err:
 99  	return ret;
100  }
101  
102  int hmac_finalize(hmac_context *ctx, u8 *output, u8 *outlen)
103  {
104  	int ret;
105  	u8 in_hash[MAX_DIGEST_SIZE];
106  	const hash_mapping *h;
107  
108  	HMAC_CHECK_INITIALIZED(ctx, ret, err);
109  	MUST_HAVE((output != NULL) && (outlen != NULL), ret, err);
110  
111  	/* Make things more readable */
112  	h = ctx->hash;
113  
114  	MUST_HAVE(((*outlen) >= h->digest_size), ret, err);
115  
116  	/* Check our callback */
117  	ret = hash_mapping_callbacks_sanity_check(h); EG(ret, err);
118  	ret = h->hfunc_finalize(&(ctx->in_ctx), in_hash); EG(ret, err);
119  	ret = h->hfunc_update(&(ctx->out_ctx), in_hash, h->digest_size); EG(ret, err);
120  	ret = h->hfunc_finalize(&(ctx->out_ctx), output); EG(ret, err);
121  	(*outlen) = h->digest_size;
122  
123  err:
124  	if(ctx != NULL){
125  		/* Clear the hash contexts that could contain sensitive data */
126  		IGNORE_RET_VAL(local_memset(ctx, 0, sizeof(hmac_context)));
127  		/* Uninitialize the context  */
128  		ctx->magic = WORD(0);
129  	}
130  	if(ret && (outlen != NULL)){
131  		(*outlen) = 0;
132  	}
133  	return ret;
134  }
135  
136  int hmac(const u8 *hmackey, u32 hmackey_len, hash_alg_type hash_type,
137  	 const u8 *input, u32 ilen, u8 *output, u8 *outlen)
138  {
139  	int ret;
140  	hmac_context ctx;
141  
142  	ret = hmac_init(&ctx, hmackey, hmackey_len, hash_type); EG(ret, err);
143  	ret = hmac_update(&ctx, input, ilen); EG(ret, err);
144  	ret = hmac_finalize(&ctx, output, outlen);
145  
146  err:
147  	/* Clean our context as it can contain sensitive data */
148  	IGNORE_RET_VAL(local_memset(&ctx, 0, sizeof(hmac_context)));
149  
150  	return ret;
151  }
152  
153  /* Scattered version */
154  int hmac_scattered(const u8 *hmackey, u32 hmackey_len, hash_alg_type hash_type,
155  	 const u8 **inputs, const u32 *ilens, u8 *output, u8 *outlen)
156  {
157  	int ret, pos = 0;
158  	hmac_context ctx;
159  
160  	MUST_HAVE((inputs != NULL) && (ilens != NULL) && (output != NULL), ret, err);
161  
162  	ret = hmac_init(&ctx, hmackey, hmackey_len, hash_type); EG(ret, err);
163  
164  	while (inputs[pos] != NULL) {
165  		ret = hmac_update(&ctx, inputs[pos], ilens[pos]); EG(ret, err);
166  		pos += 1;
167  	}
168  
169  	ret = hmac_finalize(&ctx, output, outlen);
170  
171  err:
172  	/* Clean our context as it can contain sensitive data */
173  	IGNORE_RET_VAL(local_memset(&ctx, 0, sizeof(hmac_context)));
174  
175  	return ret;
176  }
177  
178  
179  #else /* WITH_HMAC */
180  
181  /*
182   * Dummy definition to avoid the empty translation unit ISO C warning
183   */
184  typedef int dummy;
185  #endif /* WITH_HMAC */