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-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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
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/hmac.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] hash 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 *hash, 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(hash == 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 > hash->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(hash->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  hash->init(hashContext);
97  hash->update(hashContext, p, pLen);
98  hash->update(hashContext, s, sLen);
99  hash->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  hash->init(hashContext);
106  hash->update(hashContext, t, hash->digestSize);
107  hash->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
127  * length of the derived key is essentially unbounded
128  *
129  * @param[in] hash Hash algorithm used by the underlying PRF
130  * @param[in] p Password, an octet string
131  * @param[in] pLen Length in octets of password
132  * @param[in] s Salt, an octet string
133  * @param[in] sLen Length in octets of salt
134  * @param[in] c Iteration count
135  * @param[out] dk Derived key
136  * @param[in] dkLen Intended length in octets of the derived key
137  * @return Error code
138  **/
139 
140 error_t pbkdf2(const HashAlgo *hash, const uint8_t *p, size_t pLen,
141  const uint8_t *s, size_t sLen, uint_t c, uint8_t *dk, size_t dkLen)
142 {
143  uint_t i;
144  uint_t j;
145  uint_t k;
146  uint8_t a[4];
147  uint8_t t[MAX_HASH_DIGEST_SIZE];
148  uint8_t u[MAX_HASH_DIGEST_SIZE];
149 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
150  HmacContext *hmacContext;
151 #else
152  HmacContext hmacContext[1];
153 #endif
154 
155  //Check parameters
156  if(hash == NULL || p == NULL || s == NULL || dk == NULL)
158 
159  //The iteration count must be a positive integer
160  if(c < 1)
162 
163 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
164  //Allocate a memory buffer to hold the HMAC context
165  hmacContext = cryptoAllocMem(sizeof(HmacContext));
166  //Failed to allocate memory?
167  if(hmacContext == NULL)
168  return ERROR_OUT_OF_MEMORY;
169 #endif
170 
171  //For each block of the derived key apply the function F
172  for(i = 1; dkLen > 0; i++)
173  {
174  //Calculate the 4-octet encoding of the integer i (MSB first)
175  STORE32BE(i, a);
176 
177  //Compute U1 = PRF(P, S || INT(i))
178  hmacInit(hmacContext, hash, p, pLen);
179  hmacUpdate(hmacContext, s, sLen);
180  hmacUpdate(hmacContext, a, 4);
181  hmacFinal(hmacContext, u);
182 
183  //Save the resulting HMAC value
184  osMemcpy(t, u, hash->digestSize);
185 
186  //Iterate as many times as required
187  for(j = 1; j < c; j++)
188  {
189  //Compute U(j) = PRF(P, U(j-1))
190  hmacInit(hmacContext, hash, p, pLen);
191  hmacUpdate(hmacContext, u, hash->digestSize);
192  hmacFinal(hmacContext, u);
193 
194  //Compute T = U(1) xor U(2) xor ... xor U(c)
195  for(k = 0; k < hash->digestSize; k++)
196  {
197  t[k] ^= u[k];
198  }
199  }
200 
201  //Number of octets in the current block
202  k = MIN(dkLen, hash->digestSize);
203  //Save the resulting block
204  osMemcpy(dk, t, k);
205 
206  //Point to the next block
207  dk += k;
208  dkLen -= k;
209  }
210 
211 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
212  //Free previously allocated memory
213  cryptoFreeMem(hmacContext);
214 #endif
215 
216  //Successful processing
217  return NO_ERROR;
218 }
219 
220 #endif
unsigned int uint_t
Definition: compiler_port.h:50
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
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
__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 u
Definition: lldp_ext_med.h:213
uint8_t t
Definition: lldp_ext_med.h:212
uint8_t c
Definition: ndp.h:514
uint8_t s
Definition: ndp.h:345
uint8_t p
Definition: ndp.h:300
uint8_t a
Definition: ndp.h:411
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
error_t pbkdf2(const HashAlgo *hash, 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:140
error_t pbkdf1(const HashAlgo *hash, 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
const uint8_t PBKDF2_OID[9]
Definition: pbkdf.c:43
PBKDF (Password-Based Key Derivation Function)
Common interface for hash algorithms.
Definition: crypto.h:1014
HashAlgoFinal final
Definition: crypto.h:1026
size_t contextSize
Definition: crypto.h:1018
HashAlgoUpdate update
Definition: crypto.h:1025
size_t digestSize
Definition: crypto.h:1020
HashAlgoInit init
Definition: crypto.h:1024
HMAC algorithm context.
Definition: hmac.h:59
Generic hash algorithm context.