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