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-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  * 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 1.9.8
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  HmacContext *hmacContext;
101 
102  //Check parameters
103  if(hash == NULL || ikm == NULL || prk == NULL)
105 
106  //The salt parameter is optional
107  if(salt == NULL && saltLen != 0)
109 
110  //Allocate a memory buffer to hold the HMAC context
111  hmacContext = cryptoAllocMem(sizeof(HmacContext));
112  //Failed to allocate memory?
113  if(hmacContext == NULL)
114  return ERROR_OUT_OF_MEMORY;
115 
116  //The salt parameter is optional
117  if(salt == NULL)
118  {
119  //If the salt is not provided, it is set to a string of HashLen zeros
120  osMemset(hmacContext->digest, 0, hash->digestSize);
121  salt = hmacContext->digest;
122  saltLen = hash->digestSize;
123  }
124 
125  //Compute PRK = HMAC-Hash(salt, IKM)
126  hmacInit(hmacContext, hash, salt, saltLen);
127  hmacUpdate(hmacContext, ikm, ikmLen);
128  hmacFinal(hmacContext, prk);
129 
130  //Free previously allocated memory
131  cryptoFreeMem(hmacContext);
132 
133  //Successful processing
134  return NO_ERROR;
135 }
136 
137 
138 /**
139  * @brief HKDF expand step
140  * @param[in] hash Underlying hash function
141  * @param[in] prk Pseudorandom key
142  * @param[in] prkLen Length of the pseudorandom key
143  * @param[in] info Optional application specific information
144  * @param[in] infoLen Length of the application specific information
145  * @param[out] okm output keying material
146  * @param[in] okmLen Length of the output keying material
147  * @return Error code
148  **/
149 
150 error_t hkdfExpand(const HashAlgo *hash, const uint8_t *prk, size_t prkLen,
151  const uint8_t *info, size_t infoLen, uint8_t *okm, size_t okmLen)
152 {
153  uint8_t i;
154  size_t tLen;
155  HmacContext *hmacContext;
156  uint8_t t[MAX_HASH_DIGEST_SIZE];
157 
158  //Check parameters
159  if(hash == NULL || prk == NULL || okm == NULL)
161 
162  //The application specific information parameter is optional
163  if(info == NULL && infoLen != 0)
165 
166  //PRK must be at least HashLen octets
167  if(prkLen < hash->digestSize)
168  return ERROR_INVALID_LENGTH;
169 
170  //Check the length of the output keying material
171  if(okmLen > (255 * hash->digestSize))
172  return ERROR_INVALID_LENGTH;
173 
174  //Allocate a memory buffer to hold the HMAC context
175  hmacContext = cryptoAllocMem(sizeof(HmacContext));
176  //Failed to allocate memory?
177  if(hmacContext == NULL)
178  return ERROR_OUT_OF_MEMORY;
179 
180  //T(0) is an empty string (zero length)
181  tLen = 0;
182 
183  //Iterate as many times as required
184  for(i = 1; okmLen > 0; i++)
185  {
186  //Compute T(i) = HMAC-Hash(PRK, T(i-1) | info | i)
187  hmacInit(hmacContext, hash, prk, prkLen);
188  hmacUpdate(hmacContext, t, tLen);
189  hmacUpdate(hmacContext, info, infoLen);
190  hmacUpdate(hmacContext, &i, sizeof(i));
191  hmacFinal(hmacContext, t);
192 
193  //Number of octets in the current block
194  tLen = MIN(okmLen, hash->digestSize);
195  //Save the resulting block
196  osMemcpy(okm, t, tLen);
197 
198  //Point to the next block
199  okm += tLen;
200  okmLen -= tLen;
201  }
202 
203  //Free previously allocated memory
204  cryptoFreeMem(hmacContext);
205 
206  //Successful processing
207  return NO_ERROR;
208 }
209 
210 #endif
HMAC algorithm context.
Definition: hmac.h:182
uint8_t t
Definition: llmnr_common.h:81
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:134
error_t
Error codes.
Definition: error.h:42
void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:185
General definitions for cryptographic algorithms.
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:150
#define MIN(a, b)
Definition: os_port.h:62
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
HKDF (HMAC-based Key Derivation Function)
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
#define cryptoFreeMem(p)
Definition: crypto.h:630
#define cryptoAllocMem(size)
Definition: crypto.h:625
Common interface for hash algorithms.
Definition: crypto.h:1062
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
#define MAX_HASH_DIGEST_SIZE
Definition: crypto.h:745
#define osMemset(p, value, length)
Definition: os_port.h:128
Success.
Definition: error.h:44
HMAC (Keyed-Hashing for Message Authentication)