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-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  * 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.4.0
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] hash 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 *hash, 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(hash, ikm, ikmLen, salt, saltLen, prk);
72 
73  //Check status code
74  if(!error)
75  {
76  //Perform HKDF expand step
77  error = hkdfExpand(hash, prk, hash->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] hash 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 *hash, 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(hash == 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, hash->digestSize);
127  salt = hmacContext->digest;
128  saltLen = hash->digestSize;
129  }
130 
131  //Compute PRK = HMAC-Hash(salt, IKM)
132  hmacInit(hmacContext, hash, 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] hash 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 *hash, const uint8_t *prk, size_t prkLen,
159  const uint8_t *info, size_t infoLen, uint8_t *okm, size_t okmLen)
160 {
161  uint8_t i;
162  size_t tLen;
163  uint8_t t[MAX_HASH_DIGEST_SIZE];
164 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
165  HmacContext *hmacContext;
166 #else
167  HmacContext hmacContext[1];
168 #endif
169 
170  //Check parameters
171  if(hash == NULL || prk == NULL || okm == NULL)
173 
174  //The application specific information parameter is optional
175  if(info == NULL && infoLen != 0)
177 
178  //PRK must be at least HashLen octets
179  if(prkLen < hash->digestSize)
180  return ERROR_INVALID_LENGTH;
181 
182  //Check the length of the output keying material
183  if(okmLen > (255 * hash->digestSize))
184  return ERROR_INVALID_LENGTH;
185 
186 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
187  //Allocate a memory buffer to hold the HMAC context
188  hmacContext = cryptoAllocMem(sizeof(HmacContext));
189  //Failed to allocate memory?
190  if(hmacContext == NULL)
191  return ERROR_OUT_OF_MEMORY;
192 #endif
193 
194  //T(0) is an empty string (zero length)
195  tLen = 0;
196 
197  //Iterate as many times as required
198  for(i = 1; okmLen > 0; i++)
199  {
200  //Compute T(i) = HMAC-Hash(PRK, T(i-1) | info | i)
201  hmacInit(hmacContext, hash, prk, prkLen);
202  hmacUpdate(hmacContext, t, tLen);
203  hmacUpdate(hmacContext, info, infoLen);
204  hmacUpdate(hmacContext, &i, sizeof(i));
205  hmacFinal(hmacContext, t);
206 
207  //Number of octets in the current block
208  tLen = MIN(okmLen, hash->digestSize);
209  //Save the resulting block
210  osMemcpy(okm, t, tLen);
211 
212  //Point to the next block
213  okm += tLen;
214  okmLen -= tLen;
215  }
216 
217 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
218  //Free previously allocated memory
219  cryptoFreeMem(hmacContext);
220 #endif
221 
222  //Successful processing
223  return NO_ERROR;
224 }
225 
226 #endif
General definitions for cryptographic algorithms.
#define cryptoAllocMem(size)
Definition: crypto.h:765
#define cryptoFreeMem(p)
Definition: crypto.h:770
error_t
Error codes.
Definition: error.h:43
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define MAX_HASH_DIGEST_SIZE
error_t hkdf(const HashAlgo *hash, 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
error_t hkdfExtract(const HashAlgo *hash, const uint8_t *ikm, size_t ikmLen, const uint8_t *salt, size_t saltLen, uint8_t *prk)
HKDF extract step.
Definition: hkdf.c:97
error_t hkdfExpand(const HashAlgo *hash, 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
HKDF (HMAC-based Key Derivation Function)
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:140
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
__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
HMAC (Keyed-Hashing for Message Authentication)
uint8_t t
Definition: lldp_ext_med.h:212
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
Common interface for hash algorithms.
Definition: crypto.h:1014
size_t digestSize
Definition: crypto.h:1020
HMAC algorithm context.
Definition: hmac.h:59
uint8_t digest[MAX_HASH_DIGEST_SIZE]
Definition: hmac.h:63