hmac.c
Go to the documentation of this file.
1 /**
2  * @file hmac.c
3  * @brief HMAC (Keyed-Hashing for Message Authentication)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * HMAC is a mechanism for message authentication using cryptographic hash
30  * functions. HMAC can be used with any iterative cryptographic hash
31  * function (MD5, SHA-1 or SHA-256) in combination with a secret shared
32  * key. Refer to RFC 2104 for more details
33  *
34  * @author Oryx Embedded SARL (www.oryx-embedded.com)
35  * @version 2.4.4
36  **/
37 
38 //Switch to the appropriate trace level
39 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
40 
41 //Dependencies
42 #include "core/crypto.h"
43 #include "mac/hmac.h"
44 
45 //Check crypto library configuration
46 #if (HMAC_SUPPORT == ENABLED)
47 
48 //HMAC with MD5 OID (1.3.6.1.5.5.8.1.1)
49 const uint8_t HMAC_WITH_MD5_OID[8] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x08, 0x01, 0x01};
50 //HMAC with Tiger OID (1.3.6.1.5.5.8.1.3)
51 const uint8_t HMAC_WITH_TIGER_OID[8] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x08, 0x01, 0x03};
52 //HMAC with RIPEMD-160 OID (1.3.6.1.5.5.8.1.4)
53 const uint8_t HMAC_WITH_RIPEMD160_OID[8] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x08, 0x01, 0x04};
54 //HMAC with SHA-1 OID (1.2.840.113549.2.7)
55 const uint8_t HMAC_WITH_SHA1_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07};
56 //HMAC with SHA-224 OID (1.2.840.113549.2.8)
57 const uint8_t HMAC_WITH_SHA224_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x08};
58 //HMAC with SHA-256 OID (1.2.840.113549.2.9)
59 const uint8_t HMAC_WITH_SHA256_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x09};
60 //HMAC with SHA-384 OID (1.2.840.113549.2.10)
61 const uint8_t HMAC_WITH_SHA384_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0A};
62 //HMAC with SHA-512 OID (1.2.840.113549.2.11)
63 const uint8_t HMAC_WITH_SHA512_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0B};
64 //HMAC with SHA-512/224 OID (1.2.840.113549.2.12)
65 const uint8_t HMAC_WITH_SHA512_224_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0C};
66 //HMAC with SHA-512/256 OID (1.2.840.113549.2.13)
67 const uint8_t HMAC_WITH_SHA512_256_OID[8] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0D};
68 //HMAC with SHA-3-224 OID (2.16.840.1.101.3.4.2.13)
69 const uint8_t HMAC_WITH_SHA3_224_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0D};
70 //HMAC with SHA-3-256 OID (2.16.840.1.101.3.4.2.14)
71 const uint8_t HMAC_WITH_SHA3_256_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0E};
72 //HMAC with SHA-3-384 OID (2.16.840.1.101.3.4.2.15)
73 const uint8_t HMAC_WITH_SHA3_384_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0F};
74 //HMAC with SHA-3-512 OID (2.16.840.1.101.3.4.2.16)
75 const uint8_t HMAC_WITH_SHA3_512_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x10};
76 //HMAC with SM3 OID (1.2.156.10197.1.401.3.1)
77 const uint8_t HMAC_WITH_SM3_OID[10] = {0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x82, 0x91, 0x03, 0x01};
78 
79 
80 /**
81  * @brief Compute HMAC using the specified hash function
82  * @param[in] hash Hash algorithm used to compute HMAC
83  * @param[in] key Key to use in the hash algorithm
84  * @param[in] keyLen Length of the key
85  * @param[in] data The input data for which to compute the hash code
86  * @param[in] dataLen Length of the input data
87  * @param[out] digest The computed HMAC value
88  * @return Error code
89  **/
90 
91 __weak_func error_t hmacCompute(const HashAlgo *hash, const void *key, size_t keyLen,
92  const void *data, size_t dataLen, uint8_t *digest)
93 {
94  error_t error;
95 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
96  HmacContext *context;
97 #else
98  HmacContext context[1];
99 #endif
100 
101 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
102  //Allocate a memory buffer to hold the HMAC context
103  context = cryptoAllocMem(sizeof(HmacContext));
104  //Failed to allocate memory?
105  if(context == NULL)
106  return ERROR_OUT_OF_MEMORY;
107 #endif
108 
109  //Initialize the HMAC context
110  error = hmacInit(context, hash, key, keyLen);
111 
112  //Check status code
113  if(!error)
114  {
115  //Digest the message
116  hmacUpdate(context, data, dataLen);
117  //Finalize the HMAC computation
118  hmacFinal(context, digest);
119  }
120 
121 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
122  //Free previously allocated memory
123  cryptoFreeMem(context);
124 #endif
125 
126  //Return status code
127  return error;
128 }
129 
130 
131 /**
132  * @brief Initialize HMAC calculation
133  * @param[in] context Pointer to the HMAC context to initialize
134  * @param[in] hash Hash algorithm used to compute HMAC
135  * @param[in] key Key to use in the hash algorithm
136  * @param[in] keyLen Length of the key
137  * @return Error code
138  **/
139 
140 __weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash,
141  const void *key, size_t keyLen)
142 {
143  uint_t i;
144 
145  //Check parameters
146  if(context == NULL || hash == NULL)
148 
149  //Make sure the supplied key is valid
150  if(key == NULL && keyLen != 0)
152 
153  //Hash algorithm used to compute HMAC
154  context->hash = hash;
155 
156  //The key is longer than the block size?
157  if(keyLen > hash->blockSize)
158  {
159  //Initialize the hash function context
160  hash->init(&context->hashContext);
161  //Digest the original key
162  hash->update(&context->hashContext, key, keyLen);
163  //Finalize the message digest computation
164  hash->final(&context->hashContext, context->key);
165 
166  //Key is padded to the right with extra zeros
167  osMemset(context->key + hash->digestSize, 0,
168  hash->blockSize - hash->digestSize);
169  }
170  else
171  {
172  //Copy the key
173  osMemcpy(context->key, key, keyLen);
174  //Key is padded to the right with extra zeros
175  osMemset(context->key + keyLen, 0, hash->blockSize - keyLen);
176  }
177 
178  //XOR the resulting key with ipad
179  for(i = 0; i < hash->blockSize; i++)
180  {
181  context->key[i] ^= HMAC_IPAD;
182  }
183 
184  //Initialize context for the first pass
185  hash->init(&context->hashContext);
186  //Start with the inner pad
187  hash->update(&context->hashContext, context->key, hash->blockSize);
188 
189  //Successful initialization
190  return NO_ERROR;
191 }
192 
193 
194 /**
195  * @brief Update the HMAC context with a portion of the message being hashed
196  * @param[in] context Pointer to the HMAC context
197  * @param[in] data Pointer to the buffer being hashed
198  * @param[in] length Length of the buffer
199  **/
200 
201 __weak_func void hmacUpdate(HmacContext *context, const void *data, size_t length)
202 {
203  const HashAlgo *hash;
204 
205  //Hash algorithm used to compute HMAC
206  hash = context->hash;
207  //Digest the message (first pass)
208  hash->update(&context->hashContext, data, length);
209 }
210 
211 
212 /**
213  * @brief Finish the HMAC calculation
214  * @param[in] context Pointer to the HMAC context
215  * @param[out] digest Calculated HMAC value (optional parameter)
216  **/
217 
218 __weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
219 {
220  uint_t i;
221  const HashAlgo *hash;
222 
223  //Hash algorithm used to compute HMAC
224  hash = context->hash;
225  //Finish the first pass
226  hash->final(&context->hashContext, context->digest);
227 
228  //XOR the original key with opad
229  for(i = 0; i < hash->blockSize; i++)
230  {
231  context->key[i] ^= HMAC_IPAD ^ HMAC_OPAD;
232  }
233 
234  //Initialize context for the second pass
235  hash->init(&context->hashContext);
236  //Start with outer pad
237  hash->update(&context->hashContext, context->key, hash->blockSize);
238  //Then digest the result of the first hash
239  hash->update(&context->hashContext, context->digest, hash->digestSize);
240  //Finish the second pass
241  hash->final(&context->hashContext, context->digest);
242 
243  //Copy the resulting HMAC value
244  if(digest != NULL)
245  {
246  osMemcpy(digest, context->digest, hash->digestSize);
247  }
248 }
249 
250 
251 /**
252  * @brief Release HMAC context
253  * @param[in] context Pointer to the HMAC context
254  **/
255 
256 void hmacDeinit(HmacContext *context)
257 {
258  //Make sure the HMAC context is valid
259  if(context != NULL)
260  {
261  //Clear HMAC context
262  osMemset(context, 0, sizeof(HmacContext));
263  }
264 }
265 
266 
267 /**
268  * @brief Finish the HMAC calculation (no padding added)
269  * @param[in] context Pointer to the HMAC context
270  * @param[out] digest Calculated HMAC value (optional parameter)
271  **/
272 
273 void hmacFinalRaw(HmacContext *context, uint8_t *digest)
274 {
275  uint_t i;
276  const HashAlgo *hash;
277 
278  //Hash algorithm used to compute HMAC
279  hash = context->hash;
280 
281  //XOR the original key with opad
282  for(i = 0; i < hash->blockSize; i++)
283  {
284  context->key[i] ^= HMAC_IPAD ^ HMAC_OPAD;
285  }
286 
287  //Initialize context for the second pass
288  hash->init(&context->hashContext);
289  //Start with outer pad
290  hash->update(&context->hashContext, context->key, hash->blockSize);
291  //Then digest the result of the first hash
292  hash->update(&context->hashContext, context->digest, hash->digestSize);
293  //Finish the second pass
294  hash->final(&context->hashContext, context->digest);
295 
296  //Copy the resulting HMAC value
297  if(digest != NULL)
298  {
299  osMemcpy(digest, context->digest, hash->digestSize);
300  }
301 }
302 
303 #endif
const HashAlgo * hash
Definition: hmac.h:60
HashAlgoInit init
Definition: crypto.h:1056
HMAC algorithm context.
Definition: hmac.h:59
#define HMAC_OPAD
Definition: hmac.h:46
#define HMAC_IPAD
Definition: hmac.h:44
const uint8_t HMAC_WITH_SM3_OID[10]
Definition: hmac.c:77
const uint8_t HMAC_WITH_SHA1_OID[8]
Definition: hmac.c:55
const uint8_t HMAC_WITH_SHA256_OID[8]
Definition: hmac.c:59
uint8_t data[]
Definition: ethernet.h:222
const uint8_t HMAC_WITH_TIGER_OID[8]
Definition: hmac.c:51
size_t digestSize
Definition: crypto.h:1052
const uint8_t HMAC_WITH_RIPEMD160_OID[8]
Definition: hmac.c:53
HashAlgoUpdate update
Definition: crypto.h:1057
size_t blockSize
Definition: crypto.h:1051
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
uint8_t key[MAX_HASH_BLOCK_SIZE]
Definition: hmac.h:62
const uint8_t HMAC_WITH_SHA3_224_OID[9]
Definition: hmac.c:69
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
error_t
Error codes.
Definition: error.h:43
const uint8_t HMAC_WITH_SHA3_384_OID[9]
Definition: hmac.c:73
const uint8_t HMAC_WITH_SHA384_OID[8]
Definition: hmac.c:61
const uint8_t HMAC_WITH_MD5_OID[8]
Definition: hmac.c:49
General definitions for cryptographic algorithms.
void hmacFinalRaw(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation (no padding added)
Definition: hmac.c:273
uint8_t length
Definition: tcp.h:368
uint32_t dataLen
Definition: sftp_common.h:229
const uint8_t HMAC_WITH_SHA224_OID[8]
Definition: hmac.c:57
HashAlgoFinal final
Definition: crypto.h:1058
__weak_func void hmacUpdate(HmacContext *context, const void *data, size_t length)
Update the HMAC context with a portion of the message being hashed.
Definition: hmac.c:201
void hmacDeinit(HmacContext *context)
Release HMAC context.
Definition: hmac.c:256
__weak_func error_t hmacCompute(const HashAlgo *hash, const void *key, size_t keyLen, const void *data, size_t dataLen, uint8_t *digest)
Compute HMAC using the specified hash function.
Definition: hmac.c:91
uint8_t digest[MAX_HASH_DIGEST_SIZE]
Definition: hmac.h:63
const uint8_t HMAC_WITH_SHA512_OID[8]
Definition: hmac.c:63
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
#define cryptoFreeMem(p)
Definition: crypto.h:791
const uint8_t HMAC_WITH_SHA3_256_OID[9]
Definition: hmac.c:71
const uint8_t HMAC_WITH_SHA3_512_OID[9]
Definition: hmac.c:75
#define cryptoAllocMem(size)
Definition: crypto.h:786
HashContext hashContext
Definition: hmac.h:61
const uint8_t HMAC_WITH_SHA512_256_OID[8]
Definition: hmac.c:67
Common interface for hash algorithms.
Definition: crypto.h:1046
const uint8_t HMAC_WITH_SHA512_224_OID[8]
Definition: hmac.c:65
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:140
@ NO_ERROR
Success.
Definition: error.h:44
HMAC (Keyed-Hashing for Message Authentication)