hmac.c
Go to the documentation of this file.
1 /*!**********************************************************************
2  *
3  * @copyright Copyright (C) 2016 Siemens Aktiengesellschaft.\n
4  * All rights reserved.
5  *
6  *************************************************************************
7  *
8  * @file hmac.c
9  * @date Aug 16, 2016
10  * @brief HMAC module implementation file.
11  *
12  ************************************************************************/
13 
14 #include "hmac.h"
15 #include "memory.h"
16 #include "security.h"
17 #include "log_util.h"
18 #include "string_util.h"
19 #include "definitions.h"
20 
21 // Allowed maximum key size must be greater than SHA256 results size
22 #define HMAC_MAXIMUM_KEY_SIZE 64
23 #define HMAC_SHA256_SIZE 32
24 static const mcl_uint8_t hmac_ipad = 0x36;
25 static const mcl_uint8_t hmac_opad = 0x5C;
26 
27 E_MCL_ERROR_CODE 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)
28 {
29  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>, mcl_uint8_t **hash = <%p>, mcl_size_t *hash_size = <%p>",
30  data, data_size, key, key_size, hash, hash_size)
31 
32  const mcl_uint8_t *key_local = key;
33  E_MCL_ERROR_CODE code;
34  mcl_size_t key_local_size = key_size;
35  mcl_size_t index = 0;
36  mcl_size_t key_ipad_size;
37  mcl_uint8_t *key_ipad;
38  mcl_size_t key_opad_size;
39  mcl_uint8_t *key_opad;
40  mcl_uint8_t *sha_output = MCL_NULL;
41  mcl_size_t sha_output_size;
42 
43  // If the key is too long, replace it by its hash sha256.
44  mcl_uint8_t *key_resized = MCL_NULL;
45 
46  ASSERT_CODE_MESSAGE(key_size > 0, MCL_INVALID_PARAMETER, "Size of key for HMAC must be greater than 0!");
47 
48  if (key_size > HMAC_MAXIMUM_KEY_SIZE)
49  {
50  MCL_DEBUG("Resizing given key to its SHA256 value.");
51 
52  code = security_hash_sha256(key, key_size, &key_resized, &key_local_size);
53  ASSERT_CODE_MESSAGE(MCL_OK == code, code, "Given HMAC key size = <%u> was greater than allowed = <%u>, but new key couldn't be constructed from its SHA256 hash!",
54  key_size, HMAC_MAXIMUM_KEY_SIZE);
56  "SHA256 didn't returned expected length of data = <%u>!", HMAC_SHA256_SIZE);
57  key_local = key_resized;
58  }
59 
60  // allocate buffers for key_ipad/key_opad
61  MCL_DEBUG("Preparing buffers key_ipad and key_opad.");
62 
63  key_ipad_size = HMAC_MAXIMUM_KEY_SIZE + data_size;
64  key_ipad = MCL_MALLOC(key_ipad_size);
65 
66  if (MCL_NULL == key_ipad)
67  {
68  if (key_resized == key_local)
69  {
70  MCL_FREE(key_resized);
71  }
72  MCL_ERROR_RETURN(MCL_OUT_OF_MEMORY, "Memory to hold input data for XOR operation with ipad couldn't be allocated!");
73  }
74 
75  key_opad_size = HMAC_MAXIMUM_KEY_SIZE + HMAC_SHA256_SIZE;
76  key_opad = MCL_MALLOC(key_opad_size);
77 
78  if (MCL_NULL == key_opad)
79  {
80  MCL_FREE(key_ipad);
81  if (key_resized == key_local)
82  {
83  MCL_FREE(key_resized);
84  }
85  MCL_ERROR_RETURN(MCL_OUT_OF_MEMORY, "Memory to hold input data for XOR operation with opad couldn't be allocated!");
86  }
87 
88  // initialize buffers as long as the key is sized
89  for (index = 0; index < key_local_size; index++)
90  {
91  key_ipad[index] = key_local[index] ^ hmac_ipad;
92  key_opad[index] = key_local[index] ^ hmac_opad;
93  }
94 
95  // Release key_local if calculated new
96  if (key_resized == key_local)
97  {
98  MCL_FREE(key_resized);
99  }
100 
101  // initialize the rest with hmac_ipad/hamc_opad
102  for (index = key_local_size; index < HMAC_MAXIMUM_KEY_SIZE; index++)
103  {
104  key_ipad[index] = hmac_ipad;
105  key_opad[index] = hmac_opad;
106  }
107 
108  // copy given data
109  MCL_DEBUG("Copying data to buffer.");
110  string_util_memcpy(&key_ipad[HMAC_MAXIMUM_KEY_SIZE], data, data_size);
111 
112  // calculate SHA256 for key_ipad
113  MCL_DEBUG("Calculating first SHA256 from XORed key + data");
114 
115  code = security_hash_sha256(key_ipad, key_ipad_size, &sha_output, &sha_output_size);
116 
117  if (MCL_OK != code)
118  {
119  MCL_FREE(key_ipad);
120  MCL_FREE(key_opad);
121  MCL_FREE(sha_output);
122 
123  MCL_ERROR_RETURN(code, "SHA256 calculation for key_ipad failed!");
124  }
125 
126  if (HMAC_SHA256_SIZE != sha_output_size)
127  {
128  MCL_FREE(key_ipad);
129  MCL_FREE(key_opad);
130  MCL_FREE(sha_output);
131 
132  MCL_ERROR_RETURN(MCL_SHA256_CALCULATION_FAIL, "SHA256 calculation for key_ipad failed!");
133  }
134 
135  // set SHA256 output to key_opad
136  MCL_DEBUG("Copying first SHA256 result to buffer.");
137  string_util_memcpy(&key_opad[HMAC_MAXIMUM_KEY_SIZE], sha_output, sha_output_size);
138 
139  // calculate SHA256 for key_opad
140  MCL_DEBUG("Calculating second SHA256 from XORed key + <first SHA256>");
141  code = security_hash_sha256(key_opad, key_opad_size, hash, hash_size);
142 
143  MCL_FREE(key_ipad);
144  MCL_FREE(key_opad);
145  MCL_FREE(sha_output);
146 
147  if (MCL_OK != code)
148  {
149  MCL_FREE(*hash);
150  *hash_size = 0;
151  MCL_ERROR_RETURN(code, "SHA256 calculation for key_opad failed!");
152  }
153 
154  if ((MCL_NULL != *hash) && (HMAC_SHA256_SIZE != *hash_size))
155  {
156  MCL_FREE(*hash);
157  *hash_size = 0;
158  MCL_ERROR_RETURN(MCL_SHA256_CALCULATION_FAIL, "SHA256 calculation for key_opad failed!");
159  }
160  else
161  {
162  MCL_DEBUG("HMAC SHA256 calculated hash = <%p>, hash_size = <%u>", *hash, *hash_size);
163  }
164 
165  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
166  return MCL_OK;
167 }
#define HMAC_MAXIMUM_KEY_SIZE
Definition: hmac.c:22
Memory module header file.
#define DEBUG_LEAVE(...)
Definition: log_util.h:81
#define DEBUG_ENTRY(...)
Definition: log_util.h:80
static const mcl_uint8_t hmac_ipad
Definition: hmac.c:24
#define MCL_DEBUG(...)
Definition: log_util.h:70
#define MCL_MALLOC(bytes)
Definition: memory.h:120
Log utility module header file.
String utility module implementation file.
E_MCL_ERROR_CODE
MCL Error code definitions. Every function returning an error code uses this enum values...
Definition: mcl_common.h:137
E_MCL_ERROR_CODE 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:27
#define MCL_FREE(p)
Definition: memory.h:125
HMAC module header file.
#define ASSERT_STATEMENT_CODE_MESSAGE(condition, statement, return_code,...)
Definition: definitions.h:121
static const mcl_uint8_t hmac_opad
Definition: hmac.c:25
E_MCL_ERROR_CODE security_hash_sha256(const mcl_uint8_t *data, mcl_size_t data_size, mcl_uint8_t **hash, mcl_size_t *hash_size)
General invalid parameter fail.
Definition: mcl_common.h:144
uint8_t mcl_uint8_t
Definition: mcl_common.h:43
void string_util_memcpy(void *destination, const void *source, mcl_size_t count)
Standard library memcpy wrapper.
Definition: string_util.c:131
#define HMAC_SHA256_SIZE
Definition: hmac.c:23
#define ASSERT_CODE_MESSAGE(condition, return_code,...)
Definition: definitions.h:105
Definitions module header file.
size_t mcl_size_t
Definition: mcl_common.h:38
Success.
Definition: mcl_common.h:140
Security module header file.Inner security interface. Contains security related functions like hashin...
Memory allocation fail.
Definition: mcl_common.h:143
#define MCL_NULL
Definition: definitions.h:24
If SHA256 calculation fails.
Definition: mcl_common.h:209
#define MCL_ERROR_RETURN(return_value,...)
Definition: definitions.h:69