hmac.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /*! \file
3  * \brief Keyed-Hash Message Authentication Code
4  *
5  * Copyright (c) 2012-2022 by the developers. See the LICENSE file for details.
6  *
7  * If nothing else is specified, function return zero to indicate success
8  * and a negative value to indicate an error.
9  */
10 
11 
12 /* ========================================================================== */
13 /* Include headers */
14 
15 #include "posix.h" /* Include this first because of feature test macros */
16 
17 #include "config.h"
18 
19 #if CFG_USE_TLS /* This requires data from "config.h" */
20 # include <openssl/evp.h>
21 # if !CFG_USE_OPENSSL_API_3
22 # include <openssl/hmac.h>
23 # endif /* !CFG_USE_OPENSSL_API_3 */
24 #endif /* CFG_USE_TLS */
25 #include <string.h>
26 
27 #include "hmac.h"
28 #include "main.h"
29 
30 
31 /* ========================================================================== */
32 /*! \defgroup HMAC HMAC: Hash-based Message Authentication Code
33  *
34  * This module provides optional support for Keyed-Hash Message Authentication
35  * Codes. It is intended to comply with RFC 2104.
36  *
37  * \attention
38  * This module currently works only if TLS support is available (because both
39  * share the cryptographic functions provided by OpenSSL).
40  */
41 /*! @{ */
42 
43 
44 /* ========================================================================== */
45 /* Constants */
46 
47 /*! \brief Message prefix for HMAC module */
48 #define MAIN_ERR_PREFIX "HMAC: "
49 
50 
51 /* ========================================================================== */
52 /* Data types */
53 
54 enum hmac_alg
55 {
56  HMAC_ALG_SHA1_160,
57  HMAC_ALG_SHA2_256
58 };
59 
60 
61 /* ========================================================================== */
62 /* Delegate digest calculation to OpenSSL */
63 
64 static int hmac_openssl(enum hmac_alg alg, const char* text,
65  size_t text_len, const char* key, size_t key_len,
66  unsigned char* mac)
67 {
68  int res = -1;
69 #if CFG_USE_TLS
70 # if CFG_USE_OPENSSL_API_3
71  EVP_MAC* evp_mac = NULL;
72  EVP_MAC_CTX* ctx = NULL;
73  OSSL_PARAM params[2];
74  const char *digest;
75  size_t mac_len = 0;
76  int rv;
77 # else /* CFG_USE_OPENSSL_API_3 */
78  HMAC_CTX* ctx = NULL;
79  const EVP_MD* hmac_id = NULL;
80  unsigned int mac_len = 0;
81 # endif /* CFG_USE_OPENSSL_API_3 */
82  size_t mac_len_check = 1; /* Value never used by real digest */
83  int alg_valid = 0;
84 
85  /* Select digest algorithm */
86  switch(alg)
87  {
88  case HMAC_ALG_SHA1_160:
89  {
90 # if CFG_USE_OPENSSL_API_3
91  digest = "sha1";
92 # else /* CFG_USE_OPENSSL_API_3 */
93  hmac_id = EVP_sha1();
94 # endif /* CFG_USE_OPENSSL_API_3 */
95  mac_len_check = HMAC_SHA1_160_LEN;
96  alg_valid = 1;
97  break;
98  }
99  case HMAC_ALG_SHA2_256:
100  {
101 # if CFG_USE_OPENSSL_API_3
102  digest = "sha256";
103 # else /* CFG_USE_OPENSSL_API_3 */
104  hmac_id = EVP_sha256();
105 # endif /* CFG_USE_OPENSSL_API_3 */
106  mac_len_check = HMAC_SHA2_256_LEN;
107  alg_valid = 1;
108  break;
109  }
110  default:
111  {
112  PRINT_ERROR("Requested algorithm not supported");
113  break;
114  }
115  }
116 
117  /* Calculate MAC */
118  if(alg_valid)
119  {
120  /* Create context (even if it is currently not used) */
121 # if CFG_USE_OPENSSL_API_3
122  evp_mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
123  if(NULL != evp_mac)
124  {
125  ctx = EVP_MAC_CTX_new(evp_mac);
126  }
127 /* CFG_USE_OPENSSL_API_3 */
128 # elif CFG_USE_OPENSSL_API_1_1 || CFG_USE_LIBRESSL_API_3_5
129  ctx = HMAC_CTX_new();
130 # else /* CFG_USE_OPENSSL_API_1_1 */
131  ctx = (HMAC_CTX*) posix_malloc(sizeof(HMAC_CTX));
132 # endif /* CFG_USE_OPENSSL_API_1_1 */
133  if(NULL == ctx) { PRINT_ERROR("Creating context failed"); }
134 
135  /* Check whether length values can be represented as data type 'int' */
136  else if(!(POSIX_INT_MAX >= text_len && POSIX_INT_MAX >= key_len))
137  {
138  PRINT_ERROR("Message or key is too long");
139  }
140  else
141  {
142  /* Delegate job to OpenSSL */
143 # if CFG_USE_OPENSSL_API_3
144  params[0] = OSSL_PARAM_construct_utf8_string("digest",
145  (char*) digest, 0);
146  params[1] = OSSL_PARAM_construct_end();
147  rv = EVP_MAC_init(ctx, (const unsigned char*) key, key_len, params);
148  if (1 != rv)
149  {
150  PRINT_ERROR("Initialization of algorithm failed");
151  }
152  else
153  {
154  rv = EVP_MAC_update(ctx, (const unsigned char*) text, text_len);
155  if (1 == rv)
156  {
157  rv = EVP_MAC_final(ctx, mac, &mac_len, mac_len_check);
158  }
159  if(1 != rv)
160  {
161  PRINT_ERROR("Calculation failed");
162  }
163  else if(NULL != mac && mac_len_check == (size_t) mac_len)
164  {
165  res = 0;
166  }
167  }
168 # else /* CFG_USE_OPENSSL_API_3 */
169 # if CFG_USE_OPENSSL_API_1_1 || CFG_USE_LIBRESSL_API_3_5
170  HMAC_CTX_reset(ctx);
171 # else /* CFG_USE_OPENSSL_API_1_1 */
172  HMAC_CTX_init(ctx);
173 # endif /* CFG_USE_OPENSSL_API_1_1 */
174  /* Note: OpenSSL documentation is wong! 5th argument is 'size_t' */
175  mac = HMAC(hmac_id, (void*) key, (int) key_len, (unsigned char*) text,
176  text_len, (unsigned char*) mac, &mac_len);
177  if(NULL != mac && mac_len_check == (size_t) mac_len) { res = 0; }
178 # endif /* CFG_USE_OPENSSL_API_3 */
179  }
180  }
181 
182  /* Destroy context */
183  if(NULL != ctx)
184  {
185 # if CFG_USE_OPENSSL_API_3
186  EVP_MAC_CTX_free(ctx);
187 # elif CFG_USE_OPENSSL_API_1_1 || CFG_USE_LIBRESSL_API_3_5
188  HMAC_CTX_free(ctx);
189 # else /* CFG_USE_OPENSSL_API_1_1 */
190  HMAC_CTX_cleanup(ctx);
191  posix_free((void*) ctx);
192 # endif /* CFG_USE_OPENSSL_API_1_1 */
193  }
194 
195 # if CFG_USE_OPENSSL_API_3
196  /* Destroy fetched MAC algorithm */
197  EVP_MAC_free(evp_mac);
198 # endif /* CFG_USE_OPENSSL_API_3 */
199 #endif /* CFG_USE_TLS */
200 
201  return(res);
202 }
203 
204 
205 /* ========================================================================== */
206 /*! \brief Message Authentication Code based on SHA1-160 hash algorithm
207  *
208  * \param[in] text Message
209  * \param[in] text_len Message length
210  * \param[in] key Key
211  * \param[in] key_len Key length
212  * \param[out] mac Result
213  *
214  * The values of paramaters \e text_len and \e key_len must represent bytes.
215  *
216  * On success, the result is written to \e mac and has a length of
217  * \c HMAC_SHA1_160_LEN bytes.
218  *
219  * \return
220  * - 0 on success
221  * - -1 on error
222  */
223 
224 int hmac_sha1_160(const char* text, size_t text_len,
225  const char* key, size_t key_len, unsigned char* mac)
226 {
227  return(hmac_openssl(HMAC_ALG_SHA1_160, text, text_len, key, key_len, mac));
228 }
229 
230 
231 /* ========================================================================== */
232 /*! \brief Message Authentication Code based on SHA2-256 hash algorithm
233  *
234  * \param[in] text Message
235  * \param[in] text_len Message length
236  * \param[in] key Key
237  * \param[in] key_len Key length
238  * \param[out] mac Result
239  *
240  * The values of paramaters \e text_len and \e key_len must represent bytes.
241  *
242  * On success, the result is written to \e mac and has a length of
243  * \c HMAC_SHA2_256_LEN bytes.
244  *
245  * \return
246  * - 0 on success
247  * - -1 on error
248  */
249 
250 int hmac_sha2_256(const char* text, size_t text_len,
251  const char* key, size_t key_len, unsigned char* mac)
252 {
253  return(hmac_openssl(HMAC_ALG_SHA2_256, text, text_len, key, key_len, mac));
254 }
255 
256 
257 /* ========================================================================== */
258 /*! \brief Initialize HMAC module */
259 
260 void hmac_init(void)
261 {
262  return;
263 }
264 
265 
266 /* ========================================================================== */
267 /*! \brief Shutdown HMAC module */
268 
269 void hmac_exit(void)
270 {
271  return;
272 }
273 
274 
275 /*! @} */
276 
277 /* EOF */
HMAC_SHA2_256_LEN
#define HMAC_SHA2_256_LEN
256 bit
Definition: hmac.h:19
hmac_sha1_160
int hmac_sha1_160(const char *text, size_t text_len, const char *key, size_t key_len, unsigned char *mac)
Message Authentication Code based on SHA1-160 hash algorithm.
Definition: hmac.c:224
hmac_exit
void hmac_exit(void)
Shutdown HMAC module.
Definition: hmac.c:269
hmac_sha2_256
int hmac_sha2_256(const char *text, size_t text_len, const char *key, size_t key_len, unsigned char *mac)
Message Authentication Code based on SHA2-256 hash algorithm.
Definition: hmac.c:250
hmac_init
void hmac_init(void)
Initialize HMAC module.
Definition: hmac.c:260
PRINT_ERROR
#define PRINT_ERROR(s)
Prepend module prefix and print error message.
Definition: main.h:19
HMAC_SHA1_160_LEN
#define HMAC_SHA1_160_LEN
160 bit
Definition: hmac.h:18

Generated at 2024-04-27 using  doxygen