hkdf.c
Go to the documentation of this file.
1 /**
2  * @file hkdf.c
3  * @brief HKDF (HMAC-based Key Derivation Function)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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  * HKDF is a simple HMAC-based key derivation function which can be used as a
30  * building block in various protocols and applications. Refer to RFC 5869 for
31  * more details
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 2.6.6
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
39 
40 //Dependencies
41 #include "core/crypto.h"
42 #include "kdf/hkdf.h"
43 #include "mac/hmac.h"
44 
45 //Check crypto library configuration
46 #if (HKDF_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief HKDF key derivation function
51  * @param[in] hashAlgo Underlying hash function
52  * @param[in] ikm input keying material
53  * @param[in] ikmLen Length in the input keying material
54  * @param[in] salt Optional salt value (a non-secret random value)
55  * @param[in] saltLen Length of the salt
56  * @param[in] info Optional application specific information
57  * @param[in] infoLen Length of the application specific information
58  * @param[out] okm output keying material
59  * @param[in] okmLen Length of the output keying material
60  * @return Error code
61  **/
62 
63 error_t hkdf(const HashAlgo *hashAlgo, const uint8_t *ikm, size_t ikmLen,
64  const uint8_t *salt, size_t saltLen, const uint8_t *info, size_t infoLen,
65  uint8_t *okm, size_t okmLen)
66 {
67  error_t error;
68  uint8_t prk[MAX_HASH_DIGEST_SIZE];
69 
70  //Perform HKDF extract step
71  error = hkdfExtract(hashAlgo, ikm, ikmLen, salt, saltLen, prk);
72 
73  //Check status code
74  if(!error)
75  {
76  //Perform HKDF expand step
77  error = hkdfExpand(hashAlgo, prk, hashAlgo->digestSize, info, infoLen,
78  okm, okmLen);
79  }
80 
81  //Return status code
82  return error;
83 }
84 
85 
86 /**
87  * @brief HKDF extract step
88  * @param[in] hashAlgo Underlying hash function
89  * @param[in] ikm input keying material
90  * @param[in] ikmLen Length in the input keying material
91  * @param[in] salt Optional salt value (a non-secret random value)
92  * @param[in] saltLen Length of the salt
93  * @param[out] prk Pseudorandom key
94  * @return Error code
95  **/
96 
97 error_t hkdfExtract(const HashAlgo *hashAlgo, const uint8_t *ikm, size_t ikmLen,
98  const uint8_t *salt, size_t saltLen, uint8_t *prk)
99 {
100 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
101  HmacContext *hmacContext;
102 #else
103  HmacContext hmacContext[1];
104 #endif
105 
106  //Check parameters
107  if(hashAlgo == NULL || ikm == NULL || prk == NULL)
109 
110  //The salt parameter is optional
111  if(salt == NULL && saltLen != 0)
113 
114 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
115  //Allocate a memory buffer to hold the HMAC context
116  hmacContext = cryptoAllocMem(sizeof(HmacContext));
117  //Failed to allocate memory?
118  if(hmacContext == NULL)
119  return ERROR_OUT_OF_MEMORY;
120 #endif
121 
122  //The salt parameter is optional
123  if(salt == NULL)
124  {
125  //If the salt is not provided, it is set to a string of HashLen zeros
126  osMemset(hmacContext->digest, 0, hashAlgo->digestSize);
127  salt = hmacContext->digest;
128  saltLen = hashAlgo->digestSize;
129  }
130 
131  //Compute PRK = HMAC-Hash(salt, IKM)
132  hmacInit(hmacContext, hashAlgo, salt, saltLen);
133  hmacUpdate(hmacContext, ikm, ikmLen);
134  hmacFinal(hmacContext, prk);
135 
136 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
137  //Free previously allocated memory
138  cryptoFreeMem(hmacContext);
139 #endif
140 
141  //Successful processing
142  return NO_ERROR;
143 }
144 
145 
146 /**
147  * @brief HKDF expand step
148  * @param[in] hashAlgo Underlying hash function
149  * @param[in] prk Pseudorandom key
150  * @param[in] prkLen Length of the pseudorandom key
151  * @param[in] info Optional application specific information
152  * @param[in] infoLen Length of the application specific information
153  * @param[out] okm output keying material
154  * @param[in] okmLen Length of the output keying material
155  * @return Error code
156  **/
157 
158 error_t hkdfExpand(const HashAlgo *hashAlgo, const uint8_t *prk, size_t prkLen,
159  const uint8_t *info, size_t infoLen, uint8_t *okm, size_t okmLen)
160 {
161  error_t error;
162  DataFrag infoFrags[1];
163 
164  //The application specific information parameter is optional
165  if(info == NULL && infoLen != 0)
167 
168  //The application specific information fits in a single fragment
169  infoFrags[0].buffer = info;
170  infoFrags[0].length = infoLen;
171 
172  //Perform HKDF expand step
173  error = hkdfExpandEx(hashAlgo, prk, prkLen, infoFrags, arraysize(infoFrags),
174  okm, okmLen);
175 
176  //Return status code
177  return error;
178 }
179 
180 
181 /**
182  * @brief HKDF expand step
183  * @param[in] hashAlgo Underlying hash function
184  * @param[in] prk Pseudorandom key
185  * @param[in] prkLen Length of the pseudorandom key
186  * @param[in] infoFrags Array of fragments representing the application
187  * specific information
188  * @param[in] infoNumFrags Number of fragments representing the application
189  * specific information
190  * @param[out] okm output keying material
191  * @param[in] okmLen Length of the output keying material
192  * @return Error code
193  **/
194 
195 error_t hkdfExpandEx(const HashAlgo *hashAlgo, const uint8_t *prk,
196  size_t prkLen, const DataFrag *infoFrags, size_t infoNumFrags, uint8_t *okm,
197  size_t okmLen)
198 {
199  uint8_t i;
200  uint_t j;
201  size_t tLen;
202  uint8_t t[MAX_HASH_DIGEST_SIZE];
203 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
204  HmacContext *hmacContext;
205 #else
206  HmacContext hmacContext[1];
207 #endif
208 
209  //Check parameters
210  if(hashAlgo == NULL || prk == NULL || okm == NULL)
212 
213  //PRK must be at least HashLen octets
214  if(prkLen < hashAlgo->digestSize)
215  return ERROR_INVALID_LENGTH;
216 
217  //Check the length of the output keying material
218  if(okmLen > (255 * hashAlgo->digestSize))
219  return ERROR_INVALID_LENGTH;
220 
221 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
222  //Allocate a memory buffer to hold the HMAC context
223  hmacContext = cryptoAllocMem(sizeof(HmacContext));
224  //Failed to allocate memory?
225  if(hmacContext == NULL)
226  return ERROR_OUT_OF_MEMORY;
227 #endif
228 
229  //T(0) is an empty string (zero length)
230  tLen = 0;
231 
232  //Iterate as many times as required
233  for(i = 1; okmLen > 0; i++)
234  {
235  //Compute T(i) = HMAC-Hash(PRK, T(i-1) | info | i)
236  hmacInit(hmacContext, hashAlgo, prk, prkLen);
237  hmacUpdate(hmacContext, t, tLen);
238 
239  for(j = 0; j < infoNumFrags; j++)
240  {
241  hmacUpdate(hmacContext, infoFrags[j].buffer, infoFrags[j].length);
242  }
243 
244  hmacUpdate(hmacContext, &i, sizeof(i));
245  hmacFinal(hmacContext, t);
246 
247  //Number of octets in the current block
248  tLen = MIN(okmLen, hashAlgo->digestSize);
249  //Save the resulting block
250  osMemcpy(okm, t, tLen);
251 
252  //Point to the next block
253  okm += tLen;
254  okmLen -= tLen;
255  }
256 
257 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
258  //Free previously allocated memory
259  cryptoFreeMem(hmacContext);
260 #endif
261 
262  //Successful processing
263  return NO_ERROR;
264 }
265 
266 #endif
const void * buffer
Definition: crypto.h:1165
HMAC algorithm context.
Definition: hmac.h:59
uint8_t t
Definition: lldp_ext_med.h:212
error_t hkdfExpand(const HashAlgo *hashAlgo, const uint8_t *prk, size_t prkLen, const uint8_t *info, size_t infoLen, uint8_t *okm, size_t okmLen)
HKDF expand step.
Definition: hkdf.c:158
size_t digestSize
Definition: crypto.h:1249
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
error_t hkdf(const HashAlgo *hashAlgo, const uint8_t *ikm, size_t ikmLen, const uint8_t *salt, size_t saltLen, const uint8_t *info, size_t infoLen, uint8_t *okm, size_t okmLen)
HKDF key derivation function.
Definition: hkdf.c:63
#define MAX_HASH_DIGEST_SIZE
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:147
error_t
Error codes.
Definition: error.h:43
Data fragment descriptor.
Definition: crypto.h:1164
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
size_t length
Definition: crypto.h:1166
uint8_t length
Definition: tcp.h:375
#define MIN(a, b)
Definition: os_port.h:63
__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
uint8_t digest[MAX_HASH_DIGEST_SIZE]
Definition: hmac.h:63
error_t hkdfExtract(const HashAlgo *hashAlgo, const uint8_t *ikm, size_t ikmLen, const uint8_t *salt, size_t saltLen, uint8_t *prk)
HKDF extract step.
Definition: hkdf.c:97
HKDF (HMAC-based Key Derivation Function)
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
#define cryptoFreeMem(p)
Definition: crypto.h:966
error_t hkdfExpandEx(const HashAlgo *hashAlgo, const uint8_t *prk, size_t prkLen, const DataFrag *infoFrags, size_t infoNumFrags, uint8_t *okm, size_t okmLen)
HKDF expand step.
Definition: hkdf.c:195
#define cryptoAllocMem(size)
Definition: crypto.h:961
Common interface for hash algorithms.
Definition: crypto.h:1243
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:141
__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)
#define arraysize(a)
Definition: os_port.h:71