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 */ 186