pbkdf.c
Go to the documentation of this file.
1 /**
2  * @file pbkdf.c
3  * @brief PBKDF (Password-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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "kdf/pbkdf.h"
37 #include "mac/mac_algorithms.h"
38 
39 //Check crypto library configuration
40 #if (PBKDF_SUPPORT == ENABLED)
41 
42 //PBKDF2 OID (1.2.840.113549.1.5.12)
43 const uint8_t PBKDF2_OID[9] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C};
44 
45 
46 /**
47  * @brief PBKDF1 key derivation function
48  *
49  * PBKDF1 applies a hash function, which shall be MD2, MD5 or SHA-1, to derive
50  * keys. The length of the derived key is bounded by the length of the hash
51  * function output, which is 16 octets for MD2 and MD5 and 20 octets for SHA-1
52  *
53  * @param[in] hashAlgo Underlying hash function (MD2, MD5 or SHA-1)
54  * @param[in] p Password, an octet string
55  * @param[in] pLen Length in octets of password
56  * @param[in] s Salt, an octet string
57  * @param[in] sLen Length in octets of salt
58  * @param[in] c Iteration count
59  * @param[out] dk Derived key
60  * @param[in] dkLen Intended length in octets of the derived key
61  * @return Error code
62  **/
63 
64 error_t pbkdf1(const HashAlgo *hashAlgo, const uint8_t *p, size_t pLen,
65  const uint8_t *s, size_t sLen, uint_t c, uint8_t *dk, size_t dkLen)
66 {
67  uint_t i;
68  uint8_t t[MAX_HASH_DIGEST_SIZE];
69 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
70  HashContext *hashContext;
71 #else
72  HashContext hashContext[1];
73 #endif
74 
75  //Check parameters
76  if(hashAlgo == NULL || p == NULL || s == NULL || dk == NULL)
78 
79  //The iteration count must be a positive integer
80  if(c < 1)
82 
83  //Check the intended length of the derived key
84  if(dkLen > hashAlgo->digestSize)
85  return ERROR_INVALID_LENGTH;
86 
87 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
88  //Allocate a memory buffer to hold the hash context
89  hashContext = cryptoAllocMem(hashAlgo->contextSize);
90  //Failed to allocate memory?
91  if(hashContext == NULL)
92  return ERROR_OUT_OF_MEMORY;
93 #endif
94 
95  //Apply the hash function to the concatenation of P and S
96  hashAlgo->init(hashContext);
97  hashAlgo->update(hashContext, p, pLen);
98  hashAlgo->update(hashContext, s, sLen);
99  hashAlgo->final(hashContext, t);
100 
101  //Iterate as many times as required
102  for(i = 1; i < c; i++)
103  {
104  //Apply the hash function to T(i - 1)
105  hashAlgo->init(hashContext);
106  hashAlgo->update(hashContext, t, hashAlgo->digestSize);
107  hashAlgo->final(hashContext, t);
108  }
109 
110  //Output the derived key DK
111  osMemcpy(dk, t, dkLen);
112 
113 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
114  //Free previously allocated memory
115  cryptoFreeMem(hashContext);
116 #endif
117 
118  //Successful processing
119  return NO_ERROR;
120 }
121 
122 
123 /**
124  * @brief PBKDF2 key derivation function
125  *
126  * PBKDF2 applies a pseudorandom function to derive keys. The length of the
127  * derived key is essentially unbounded
128  *
129  * @param[in] type Pseudorandom function (HMAC or AES-CMAC-PRF-128)
130  * @param[in] hashAlgo Underlying hash function (only for HMAC PRF)
131  * @param[in] p Password, an octet string
132  * @param[in] pLen Length in octets of password
133  * @param[in] s Salt, an octet string
134  * @param[in] sLen Length in octets of salt
135  * @param[in] c Iteration count
136  * @param[out] dk Derived key
137  * @param[in] dkLen Intended length in octets of the derived key
138  * @return Error code
139  **/
140 
141 error_t pbkdf2(Pbkdf2Type type, const HashAlgo *hashAlgo, const uint8_t *p,
142  size_t pLen, const uint8_t *s, size_t sLen, uint_t c, uint8_t *dk,
143  size_t dkLen)
144 {
145  error_t error;
146 
147  //HMAC or AES-CMAC-PRF-128 pseudorandom function?
148  if(type == PBKDF2_TYPE_HMAC)
149  {
150  error = pbkdf2Hmac(hashAlgo, p, pLen, s, sLen, c, dk, dkLen);
151  }
153  {
154  error = pbkdf2AesCmacPrf128(p, pLen, s, sLen, c, dk, dkLen);
155  }
156  else
157  {
158  error = ERROR_INVALID_PARAMETER;
159  }
160 
161  //Return status code
162  return error;
163 }
164 
165 
166 /**
167  * @brief PBKDF2 key derivation function (with HMAC)
168  * @param[in] hashAlgo Underlying hash function
169  * @param[in] p Password, an octet string
170  * @param[in] pLen Length in octets of password
171  * @param[in] s Salt, an octet string
172  * @param[in] sLen Length in octets of salt
173  * @param[in] c Iteration count
174  * @param[out] dk Derived key
175  * @param[in] dkLen Intended length in octets of the derived key
176  * @return Error code
177  **/
178 
179 error_t pbkdf2Hmac(const HashAlgo *hashAlgo, const uint8_t *p, size_t pLen,
180  const uint8_t *s, size_t sLen, uint_t c, uint8_t *dk, size_t dkLen)
181 {
182 #if (HMAC_SUPPORT == ENABLED)
183  uint_t i;
184  uint_t j;
185  uint_t k;
186  uint8_t a[4];
187  uint8_t t[MAX_HASH_DIGEST_SIZE];
188  uint8_t u[MAX_HASH_DIGEST_SIZE];
189 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
190  HmacContext *hmacContext;
191 #else
192  HmacContext hmacContext[1];
193 #endif
194 
195  //Check parameters
196  if(hashAlgo == NULL || p == NULL || s == NULL || dk == NULL)
198 
199  //The iteration count must be a positive integer
200  if(c < 1)
202 
203 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
204  //Allocate a memory buffer to hold the HMAC context
205  hmacContext = cryptoAllocMem(sizeof(HmacContext));
206  //Failed to allocate memory?
207  if(hmacContext == NULL)
208  return ERROR_OUT_OF_MEMORY;
209 #endif
210 
211  //For each block of the derived key apply the function F
212  for(i = 1; dkLen > 0; i++)
213  {
214  //Calculate the 4-octet encoding of the integer i (MSB first)
215  STORE32BE(i, a);
216 
217  //Compute U1 = PRF(P, S || INT(i))
218  hmacInit(hmacContext, hashAlgo, p, pLen);
219  hmacUpdate(hmacContext, s, sLen);
220  hmacUpdate(hmacContext, a, 4);
221  hmacFinal(hmacContext, u);
222 
223  //Save the resulting HMAC value
224  osMemcpy(t, u, hashAlgo->digestSize);
225 
226  //Iterate as many times as required
227  for(j = 1; j < c; j++)
228  {
229  //Compute U(j) = PRF(P, U(j-1))
230  hmacInit(hmacContext, hashAlgo, p, pLen);
231  hmacUpdate(hmacContext, u, hashAlgo->digestSize);
232  hmacFinal(hmacContext, u);
233 
234  //Compute T = U(1) xor U(2) xor ... xor U(c)
235  for(k = 0; k < hashAlgo->digestSize; k++)
236  {
237  t[k] ^= u[k];
238  }
239  }
240 
241  //Number of octets in the current block
242  k = MIN(dkLen, hashAlgo->digestSize);
243  //Save the resulting block
244  osMemcpy(dk, t, k);
245 
246  //Point to the next block
247  dk += k;
248  dkLen -= k;
249  }
250 
251 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
252  //Free previously allocated memory
253  cryptoFreeMem(hmacContext);
254 #endif
255 
256  //Successful processing
257  return NO_ERROR;
258 #else
259  //HMAC pseudorandom function is not implemented
260  return ERROR_NOT_IMPLEMENTED;
261 #endif
262 }
263 
264 
265 /**
266  * @brief PBKDF2 key derivation function (with AES-CMAC-PRF-128)
267  * @param[in] p Password, an octet string
268  * @param[in] pLen Length in octets of password
269  * @param[in] s Salt, an octet string
270  * @param[in] sLen Length in octets of salt
271  * @param[in] c Iteration count
272  * @param[out] dk Derived key
273  * @param[in] dkLen Intended length in octets of the derived key
274  * @return Error code
275  **/
276 
277 error_t pbkdf2AesCmacPrf128(const uint8_t *p, size_t pLen, const uint8_t *s,
278  size_t sLen, uint_t c, uint8_t *dk, size_t dkLen)
279 {
280 #if (CMAC_SUPPORT == ENABLED && AES_SUPPORT == ENABLED)
281  uint_t i;
282  uint_t j;
283  uint_t n;
284  uint8_t a[4];
285  uint8_t k[16];
286  uint8_t t[16];
287  uint8_t u[16];
288 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
289  CmacContext *cmacContext;
290 #else
291  CmacContext cmacContext[1];
292 #endif
293 
294  //Check parameters
295  if(p == NULL || s == NULL || dk == NULL)
297 
298  //The iteration count must be a positive integer
299  if(c < 1)
301 
302 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
303  //Allocate a memory buffer to hold the CMAC context
304  cmacContext = cryptoAllocMem(sizeof(CmacContext));
305  //Failed to allocate memory?
306  if(cmacContext == NULL)
307  return ERROR_OUT_OF_MEMORY;
308 #endif
309 
310  //Derive the 128-bit key K from the variable-length key VK
311  if(pLen == 16)
312  {
313  //If the key VK is exactly 128 bits, then we use it as-is
314  osMemcpy(k, p, pLen);
315  }
316  else
317  {
318  //If the key VK is longer or shorter than 128 bits, then we derive the
319  //key K by applying the AES-CMAC algorithm using the 128-bit all-zero
320  //string as the key and VK as the input message (refer to RFC 4615,
321  //section 3)
322  osMemset(k, 0, 16);
323 
324  //Compute K = AES-CMAC(0^128, VK, VKlen)
325  cmacInit(cmacContext, AES_CIPHER_ALGO, k, 16);
326  cmacUpdate(cmacContext, p, pLen);
327  cmacFinal(cmacContext, k, 16);
328  }
329 
330  //For each block of the derived key apply the function F
331  for(i = 1; dkLen > 0; i++)
332  {
333  //Calculate the 4-octet encoding of the integer i (MSB first)
334  STORE32BE(i, a);
335 
336  //Compute U1 = PRF(P, S || INT(i))
337  cmacInit(cmacContext, AES_CIPHER_ALGO, k, 16);
338  cmacUpdate(cmacContext, s, sLen);
339  cmacUpdate(cmacContext, a, 4);
340  cmacFinal(cmacContext, u, 16);
341 
342  //Save the resulting CMAC value
343  osMemcpy(t, u, 16);
344 
345  //Iterate as many times as required
346  for(j = 1; j < c; j++)
347  {
348  //Compute U(j) = PRF(P, U(j-1))
349  cmacInit(cmacContext, AES_CIPHER_ALGO, k, 16);
350  cmacUpdate(cmacContext, u, 16);
351  cmacFinal(cmacContext, u, 16);
352 
353  //Compute T = U(1) xor U(2) xor ... xor U(c)
354  for(n = 0; n < 16; n++)
355  {
356  t[n] ^= u[n];
357  }
358  }
359 
360  //Number of octets in the current block
361  n = MIN(dkLen, 16);
362  //Save the resulting block
363  osMemcpy(dk, t, n);
364 
365  //Point to the next block
366  dk += n;
367  dkLen -= n;
368  }
369 
370 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
371  //Free previously allocated memory
372  cryptoFreeMem(cmacContext);
373 #endif
374 
375  //Successful processing
376  return NO_ERROR;
377 #else
378  //AES-CMAC-PRF-128 pseudorandom function is not implemented
379  return ERROR_NOT_IMPLEMENTED;
380 #endif
381 }
382 
383 #endif
HashAlgoInit init
Definition: crypto.h:1253
Generic hash algorithm context.
HMAC algorithm context.
Definition: hmac.h:59
uint8_t a
Definition: ndp.h:411
error_t pbkdf2(Pbkdf2Type type, const HashAlgo *hashAlgo, const uint8_t *p, size_t pLen, const uint8_t *s, size_t sLen, uint_t c, uint8_t *dk, size_t dkLen)
PBKDF2 key derivation function.
Definition: pbkdf.c:141
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
Pbkdf2Type
PBKDF2 pseudorandom functions.
Definition: pbkdf.h:48
uint8_t p
Definition: ndp.h:300
uint8_t t
Definition: lldp_ext_med.h:212
size_t digestSize
Definition: crypto.h:1249
@ PBKDF2_TYPE_HMAC
Definition: pbkdf.h:49
HashAlgoUpdate update
Definition: crypto.h:1254
uint8_t type
Definition: coap_common.h:176
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
size_t contextSize
Definition: crypto.h:1247
#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 pbkdf2AesCmacPrf128(const uint8_t *p, size_t pLen, const uint8_t *s, size_t sLen, uint_t c, uint8_t *dk, size_t dkLen)
PBKDF2 key derivation function (with AES-CMAC-PRF-128)
Definition: pbkdf.c:277
error_t
Error codes.
Definition: error.h:43
error_t pbkdf2Hmac(const HashAlgo *hashAlgo, const uint8_t *p, size_t pLen, const uint8_t *s, size_t sLen, uint_t c, uint8_t *dk, size_t dkLen)
PBKDF2 key derivation function (with HMAC)
Definition: pbkdf.c:179
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
uint8_t u
Definition: lldp_ext_med.h:213
#define MIN(a, b)
Definition: os_port.h:63
CMAC algorithm context.
Definition: cmac.h:54
HashAlgoFinal final
Definition: crypto.h:1255
__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
PBKDF (Password-Based Key Derivation Function)
uint8_t n
__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 cmacInit(CmacContext *context, const CipherAlgo *cipher, const void *key, size_t keyLen)
Initialize CMAC calculation.
Definition: cmac.c:107
#define cryptoAllocMem(size)
Definition: crypto.h:961
#define AES_CIPHER_ALGO
Definition: aes.h:45
void cmacUpdate(CmacContext *context, const void *data, size_t dataLen)
Update the CMAC context with a portion of the message being hashed.
Definition: cmac.c:191
uint8_t s
Definition: igmp_common.h:234
Collection of MAC algorithms.
Common interface for hash algorithms.
Definition: crypto.h:1243
const uint8_t PBKDF2_OID[9]
Definition: pbkdf.c:43
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
@ PBKDF2_TYPE_AES_CMAC_PRF_128
Definition: pbkdf.h:50
error_t cmacFinal(CmacContext *context, uint8_t *mac, size_t macLen)
Finish the CMAC calculation.
Definition: cmac.c:237
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
error_t pbkdf1(const HashAlgo *hashAlgo, const uint8_t *p, size_t pLen, const uint8_t *s, size_t sLen, uint_t c, uint8_t *dk, size_t dkLen)
PBKDF1 key derivation function.
Definition: pbkdf.c:64
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514