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