hmac.c
Go to the documentation of this file.
1 
9 #include "hmac.h"
10 #include "security.h"
11 #include "string_util.h"
12 #include "mcl_core/mcl_assert.h"
13 #include "mcl_core/mcl_memory.h"
14 
15 // Allowed maximum key size must be greater than SHA256 results size.
16 #define HMAC_MAXIMUM_KEY_SIZE 64
17 #define HMAC_SHA256_SIZE 32
18 static const mcl_uint8_t hmac_ipad = 0x36;
19 static const mcl_uint8_t hmac_opad = 0x5C;
20 
21 mcl_error_t hmac_sha256(const mcl_uint8_t *data, mcl_size_t data_size, const mcl_uint8_t *key, mcl_size_t key_size, mcl_uint8_t **hash, mcl_size_t *hash_size)
22 {
23  const mcl_uint8_t *key_local = key;
24  mcl_error_t code;
25  mcl_size_t key_local_size = key_size;
26  mcl_size_t index = 0;
27  mcl_size_t key_ipad_size;
28  mcl_uint8_t *key_ipad;
29  mcl_size_t key_opad_size;
30  mcl_uint8_t *key_opad;
31  mcl_uint8_t *sha_output = MCL_NULL;
32  mcl_size_t sha_output_size;
33 
34  // If the key is too long, replace it by its hash sha256.
35  mcl_uint8_t *key_resized = MCL_NULL;
36 
37  MCL_DEBUG_ENTRY("const mcl_uint8_t *data = <%p>, mcl_size_t data_size = <%u>, const mcl_uint8_t *key = <%p>, mcl_size_t key_size = <%u>, "\
38  "mcl_uint8_t **hash = <%p>, mcl_size_t *hash_size = <%p>", data, data_size, key, key_size, hash, hash_size);
39 
40  MCL_ASSERT_CODE_MESSAGE(key_size > 0, MCL_INVALID_PARAMETER, "Size of key for HMAC must be greater than 0!");
41 
42  if (key_size > HMAC_MAXIMUM_KEY_SIZE)
43  {
44  MCL_DEBUG("Resizing given key to its SHA256 value.");
45 
46  code = security_hash_sha256(key, key_size, &key_resized, &key_local_size);
47  MCL_ASSERT_CODE_MESSAGE(MCL_OK == code, code, "Given HMAC key size = <%u> was greater than allowed = <%u>, "\
48  "but new key couldn't be constructed from its SHA256 hash!", key_size, HMAC_MAXIMUM_KEY_SIZE);
50  "SHA256 didn't returned expected length of data = <%u>!", HMAC_SHA256_SIZE);
51  key_local = key_resized;
52  }
53 
54  // Allocate buffers for key_ipad/key_opad.
55  MCL_DEBUG("Preparing buffers key_ipad and key_opad.");
56 
57  key_ipad_size = HMAC_MAXIMUM_KEY_SIZE + data_size;
58  key_ipad = MCL_MALLOC(key_ipad_size);
59 
60  if (MCL_NULL == key_ipad)
61  {
62  if (key_resized == key_local)
63  {
64  MCL_FREE(key_resized);
65  }
66  MCL_ERROR_RETURN(MCL_OUT_OF_MEMORY, "Memory to hold input data for XOR operation with ipad couldn't be allocated!");
67  }
68 
69  key_opad_size = HMAC_MAXIMUM_KEY_SIZE + HMAC_SHA256_SIZE;
70  key_opad = MCL_MALLOC(key_opad_size);
71 
72  if (MCL_NULL == key_opad)
73  {
74  MCL_FREE(key_ipad);
75  if (key_resized == key_local)
76  {
77  MCL_FREE(key_resized);
78  }
79  MCL_ERROR_RETURN(MCL_OUT_OF_MEMORY, "Memory to hold input data for XOR operation with opad couldn't be allocated!");
80  }
81 
82  // Initialize buffers as long as the key is sized.
83  for (index = 0; index < key_local_size; ++index)
84  {
85  key_ipad[index] = key_local[index] ^ hmac_ipad;
86  key_opad[index] = key_local[index] ^ hmac_opad;
87  }
88 
89  // Release key_local if calculated new.
90  if (key_resized == key_local)
91  {
92  MCL_FREE(key_resized);
93  }
94 
95  // Initialize the rest with hmac_ipad/hamc_opad.
96  for (index = key_local_size; index < HMAC_MAXIMUM_KEY_SIZE; ++index)
97  {
98  key_ipad[index] = hmac_ipad;
99  key_opad[index] = hmac_opad;
100  }
101 
102  // Copy given data.
103  MCL_DEBUG("Copying data to buffer.");
104  string_util_memcpy(&key_ipad[HMAC_MAXIMUM_KEY_SIZE], data, data_size);
105 
106  // Calculate SHA256 for key_ipad.
107  MCL_DEBUG("Calculating first SHA256 from XORed key + data.");
108 
109  code = security_hash_sha256(key_ipad, key_ipad_size, &sha_output, &sha_output_size);
110 
111  if (MCL_OK != code)
112  {
113  MCL_FREE(key_ipad);
114  MCL_FREE(key_opad);
115  MCL_FREE(sha_output);
116 
117  MCL_ERROR_RETURN(code, "SHA256 calculation for key_ipad failed!");
118  }
119 
120  if (HMAC_SHA256_SIZE != sha_output_size)
121  {
122  MCL_FREE(key_ipad);
123  MCL_FREE(key_opad);
124  MCL_FREE(sha_output);
125 
126  MCL_ERROR_RETURN(MCL_SHA256_CALCULATION_FAIL, "SHA256 calculation for key_ipad failed!");
127  }
128 
129  // Set SHA256 output to key_opad.
130  MCL_DEBUG("Copying first SHA256 result to buffer.");
131  string_util_memcpy(&key_opad[HMAC_MAXIMUM_KEY_SIZE], sha_output, sha_output_size);
132 
133  // Calculate SHA256 for key_opad.
134  MCL_DEBUG("Calculating second SHA256 from XORed key + <first SHA256>.");
135  code = security_hash_sha256(key_opad, key_opad_size, hash, hash_size);
136 
137  MCL_FREE(key_ipad);
138  MCL_FREE(key_opad);
139  MCL_FREE(sha_output);
140 
141  if (MCL_OK != code)
142  {
143  MCL_FREE(*hash);
144  *hash_size = 0;
145  MCL_ERROR_RETURN(code, "SHA256 calculation for key_opad failed!");
146  }
147 
148  if ((MCL_NULL != *hash) && (HMAC_SHA256_SIZE != *hash_size))
149  {
150  MCL_FREE(*hash);
151  *hash_size = 0;
152  MCL_ERROR_RETURN(MCL_SHA256_CALCULATION_FAIL, "SHA256 calculation for key_opad failed!");
153  }
154  else
155  {
156  MCL_DEBUG("HMAC SHA256 calculated hash = <%p>, hash_size = <%u>", *hash, *hash_size);
157  }
158 
159  MCL_DEBUG_LEAVE("retVal = <%d>", MCL_OK);
160  return MCL_OK;
161 }
size_t mcl_size_t
#define HMAC_MAXIMUM_KEY_SIZE
Definition: hmac.c:16
If SHA256 calculation fails.
Assert module header file.
Success.
#define MCL_DEBUG(...)
Definition: mcl_log_util.h:114
static const mcl_uint8_t hmac_ipad
Definition: hmac.c:18
mcl_int32_t mcl_error_t
#define MCL_DEBUG_ENTRY(...)
Definition: mcl_log_util.h:115
String utility module header file.
#define MCL_ASSERT_CODE_MESSAGE(condition, return_code,...)
Definition: mcl_assert.h:77
HMAC module header file.
#define MCL_NULL
static const mcl_uint8_t hmac_opad
Definition: hmac.c:19
#define MCL_FREE(p)
Definition: mcl_memory.h:59
mcl_error_t security_hash_sha256(const mcl_uint8_t *data, mcl_size_t data_size, mcl_uint8_t **hash, mcl_size_t *hash_size)
void string_util_memcpy(void *destination, const void *source, mcl_size_t count)
Definition: string_util.c:229
#define HMAC_SHA256_SIZE
Definition: hmac.c:17
uint8_t mcl_uint8_t
#define MCL_ASSERT_STATEMENT_CODE_MESSAGE(condition, statement, return_code,...)
Definition: mcl_assert.h:93
#define MCL_ERROR_RETURN(return_value,...)
Definition: mcl_assert.h:26
Security interface header file.
Memory allocation fail.
#define MCL_MALLOC(bytes)
Definition: mcl_memory.h:54
mcl_error_t hmac_sha256(const mcl_uint8_t *data, mcl_size_t data_size, const mcl_uint8_t *key, mcl_size_t key_size, mcl_uint8_t **hash, mcl_size_t *hash_size)
Definition: hmac.c:21
General invalid parameter fail.
#define MCL_DEBUG_LEAVE(...)
Definition: mcl_log_util.h:116
Memory module interface header file.