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-2020 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 1.9.8
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-3-224 object identifier (2.16.840.1.101.3.4.2.13)
65 const uint8_t HMAC_WITH_SHA3_224_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0D};
66 //HMAC with SHA-3-256 object identifier (2.16.840.1.101.3.4.2.14)
67 const uint8_t HMAC_WITH_SHA3_256_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0E};
68 //HMAC with SHA-3-384 object identifier (2.16.840.1.101.3.4.2.15)
69 const uint8_t HMAC_WITH_SHA3_384_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0F};
70 //HMAC with SHA-3-512 object identifier (2.16.840.1.101.3.4.2.16)
71 const uint8_t HMAC_WITH_SHA3_512_OID[9] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x10};
72 
73 
74 /**
75  * @brief Compute HMAC using the specified hash function
76  * @param[in] hash Hash algorithm used to compute HMAC
77  * @param[in] key Key to use in the hash algorithm
78  * @param[in] keyLen Length of the key
79  * @param[in] data The input data for which to compute the hash code
80  * @param[in] dataLen Length of the input data
81  * @param[out] digest The computed HMAC value
82  * @return Error code
83  **/
84 
85 error_t hmacCompute(const HashAlgo *hash, const void *key, size_t keyLen,
86  const void *data, size_t dataLen, uint8_t *digest)
87 {
88  HmacContext *context;
89 
90  //Allocate a memory buffer to hold the HMAC context
91  context = cryptoAllocMem(sizeof(HmacContext));
92  //Failed to allocate memory?
93  if(context == NULL)
94  return ERROR_OUT_OF_MEMORY;
95 
96  //Initialize the HMAC context
97  hmacInit(context, hash, key, keyLen);
98  //Digest the message
99  hmacUpdate(context, data, dataLen);
100  //Finalize the HMAC computation
101  hmacFinal(context, digest);
102 
103  //Free previously allocated memory
104  cryptoFreeMem(context);
105  //Successful processing
106  return NO_ERROR;
107 }
108 
109 
110 /**
111  * @brief Initialize HMAC calculation
112  * @param[in] context Pointer to the HMAC context to initialize
113  * @param[in] hash Hash algorithm used to compute HMAC
114  * @param[in] key Key to use in the hash algorithm
115  * @param[in] keyLen Length of the key
116  **/
117 
118 void hmacInit(HmacContext *context, const HashAlgo *hash,
119  const void *key, size_t keyLen)
120 {
121  uint_t i;
122 
123  //Hash algorithm used to compute HMAC
124  context->hash = hash;
125 
126  //The key is longer than the block size?
127  if(keyLen > hash->blockSize)
128  {
129  //Initialize the hash function context
130  hash->init(context->hashContext);
131  //Digest the original key
132  hash->update(context->hashContext, key, keyLen);
133  //Finalize the message digest computation
134  hash->final(context->hashContext, context->key);
135 
136  //Key is padded to the right with extra zeros
137  osMemset(context->key + hash->digestSize, 0,
138  hash->blockSize - hash->digestSize);
139  }
140  else
141  {
142  //Copy the key
143  osMemcpy(context->key, key, keyLen);
144  //Key is padded to the right with extra zeros
145  osMemset(context->key + keyLen, 0, hash->blockSize - keyLen);
146  }
147 
148  //XOR the resulting key with ipad
149  for(i = 0; i < hash->blockSize; i++)
150  {
151  context->key[i] ^= HMAC_IPAD;
152  }
153 
154  //Initialize context for the first pass
155  hash->init(context->hashContext);
156  //Start with the inner pad
157  hash->update(context->hashContext, context->key, hash->blockSize);
158 }
159 
160 
161 /**
162  * @brief Update the HMAC context with a portion of the message being hashed
163  * @param[in] context Pointer to the HMAC context
164  * @param[in] data Pointer to the buffer being hashed
165  * @param[in] length Length of the buffer
166  **/
167 
168 void hmacUpdate(HmacContext *context, const void *data, size_t length)
169 {
170  const HashAlgo *hash;
171 
172  //Hash algorithm used to compute HMAC
173  hash = context->hash;
174  //Digest the message (first pass)
175  hash->update(context->hashContext, data, length);
176 }
177 
178 
179 /**
180  * @brief Finish the HMAC calculation
181  * @param[in] context Pointer to the HMAC context
182  * @param[out] digest Calculated HMAC value (optional parameter)
183  **/
184 
185 void hmacFinal(HmacContext *context, uint8_t *digest)
186 {
187  uint_t i;
188  const HashAlgo *hash;
189 
190  //Hash algorithm used to compute HMAC
191  hash = context->hash;
192  //Finish the first pass
193  hash->final(context->hashContext, context->digest);
194 
195  //XOR the original key with opad
196  for(i = 0; i < hash->blockSize; i++)
197  {
198  context->key[i] ^= HMAC_IPAD ^ HMAC_OPAD;
199  }
200 
201  //Initialize context for the second pass
202  hash->init(context->hashContext);
203  //Start with outer pad
204  hash->update(context->hashContext, context->key, hash->blockSize);
205  //Then digest the result of the first hash
206  hash->update(context->hashContext, context->digest, hash->digestSize);
207  //Finish the second pass
208  hash->final(context->hashContext, context->digest);
209 
210  //Copy the resulting HMAC value
211  if(digest != NULL)
212  osMemcpy(digest, context->digest, hash->digestSize);
213 }
214 
215 
216 /**
217  * @brief Finish the HMAC calculation (no padding is added)
218  * @param[in] context Pointer to the HMAC context
219  * @param[out] digest Calculated HMAC value (optional parameter)
220  **/
221 
222 void hmacFinalRaw(HmacContext *context, uint8_t *digest)
223 {
224  uint_t i;
225  const HashAlgo *hash;
226 
227  //Hash algorithm used to compute HMAC
228  hash = context->hash;
229 
230  //XOR the original key with opad
231  for(i = 0; i < hash->blockSize; i++)
232  {
233  context->key[i] ^= HMAC_IPAD ^ HMAC_OPAD;
234  }
235 
236  //Initialize context for the second pass
237  hash->init(context->hashContext);
238  //Start with outer pad
239  hash->update(context->hashContext, context->key, hash->blockSize);
240  //Then digest the result of the first hash
241  hash->update(context->hashContext, context->digest, hash->digestSize);
242  //Finish the second pass
243  hash->final(context->hashContext, context->digest);
244 
245  //Copy the resulting HMAC value
246  if(digest != NULL)
247  osMemcpy(digest, context->digest, hash->digestSize);
248 }
249 
250 #endif
uint8_t length
Definition: coap_common.h:190
const HashAlgo * hash
Definition: hmac.h:184
HMAC algorithm context.
Definition: hmac.h:182
#define HMAC_OPAD
Definition: hmac.h:170
#define HMAC_IPAD
Definition: hmac.h:168
uint8_t data[]
Definition: ethernet.h:209
const uint8_t HMAC_WITH_SHA1_OID[8]
Definition: hmac.c:55
const uint8_t HMAC_WITH_SHA256_OID[8]
Definition: hmac.c:59
const uint8_t HMAC_WITH_TIGER_OID[8]
Definition: hmac.c:51
const uint8_t HMAC_WITH_RIPEMD160_OID[8]
Definition: hmac.c:53
uint8_t key[MAX_HASH_BLOCK_SIZE]
Definition: hmac.h:186
const uint8_t HMAC_WITH_SHA3_224_OID[9]
Definition: hmac.c:65
#define osMemcpy(dest, src, length)
Definition: os_port.h:134
error_t
Error codes.
Definition: error.h:42
const uint8_t HMAC_WITH_SHA3_384_OID[9]
Definition: hmac.c:69
const uint8_t HMAC_WITH_SHA384_OID[8]
Definition: hmac.c:61
void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:185
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 is added)
Definition: hmac.c:222
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:85
const uint8_t HMAC_WITH_SHA224_OID[8]
Definition: hmac.c:57
uint8_t hash
Definition: tls.h:1380
uint8_t digest[MAX_HASH_DIGEST_SIZE]
Definition: hmac.h:187
void hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:118
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:168
const uint8_t HMAC_WITH_SHA512_OID[8]
Definition: hmac.c:63
#define cryptoFreeMem(p)
Definition: crypto.h:630
const uint8_t HMAC_WITH_SHA3_256_OID[9]
Definition: hmac.c:67
const uint8_t HMAC_WITH_SHA3_512_OID[9]
Definition: hmac.c:71
#define cryptoAllocMem(size)
Definition: crypto.h:625
Common interface for hash algorithms.
Definition: crypto.h:1062
uint8_t hashContext[MAX_HASH_CONTEXT_SIZE]
Definition: hmac.h:185
unsigned int uint_t
Definition: compiler_port.h:45
#define osMemset(p, value, length)
Definition: os_port.h:128
Success.
Definition: error.h:44
HMAC (Keyed-Hashing for Message Authentication)