xref: /freebsd/crypto/libecc/src/hash/hmac.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 #ifdef WITH_HMAC
13 
14 #include <libecc/hash/hmac.h>
15 
hmac_init(hmac_context * ctx,const u8 * hmackey,u32 hmackey_len,hash_alg_type hash_type)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 
hmac_update(hmac_context * ctx,const u8 * input,u32 ilen)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 
hmac_finalize(hmac_context * ctx,u8 * output,u8 * outlen)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 
hmac(const u8 * hmackey,u32 hmackey_len,hash_alg_type hash_type,const u8 * input,u32 ilen,u8 * output,u8 * outlen)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 */
hmac_scattered(const u8 * hmackey,u32 hmackey_len,hash_alg_type hash_type,const u8 ** inputs,const u32 * ilens,u8 * output,u8 * outlen)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 */
186