scrypt.c
Go to the documentation of this file.
1 /**
2  * @file scrypt.c
3  * @brief scrypt 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  * @section Description
28  *
29  * scrypt is a password-based key derivation function. The function derives
30  * one or more secret keys from a secret string. It is based on memory-hard
31  * functions, which offer added protection against attacks using custom
32  * hardware. Refer to RFC 7914 for more details
33  *
34  * @author Oryx Embedded SARL (www.oryx-embedded.com)
35  * @version 2.4.4
36  **/
37 
38 //Switch to the appropriate trace level
39 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
40 
41 //Dependencies
42 #include "core/crypto.h"
43 #include "kdf/scrypt.h"
44 #include "kdf/pbkdf.h"
45 #include "hash/sha256.h"
46 #include "cipher/salsa20.h"
47 
48 //Check crypto library configuration
49 #if (SCRYPT_SUPPORT == ENABLED)
50 
51 
52 /**
53  * @brief scrypt algorithm
54  * @param[in] password NULL-terminated passphrase
55  * @param[in] salt Random salt
56  * @param[in] saltLen Length of the random salt, in bytes
57  * @param[in] n CPU/Memory cost parameter
58  * @param[in] r Block size parameter
59  * @param[in] p Parallelization parameter
60  * @param[out] dk Derived key
61  * @param[in] dkLen Intended output length in octets of the derived key
62  * @return Error code
63  **/
64 
65 error_t scrypt(const char_t *password, const uint8_t *salt, size_t saltLen,
66  uint_t n, uint_t r, uint_t p, uint8_t *dk, size_t dkLen)
67 {
68  error_t error;
69  uint_t i;
70  size_t blockSize;
71  size_t passwordLen;
72  uint8_t *b;
73  uint8_t *v;
74  uint8_t *y;
75 
76  //Check parameters
77  if(password == NULL || salt == NULL || dk == NULL)
79 
80  //Initialize variables
81  b = NULL;
82  v = NULL;
83  y = NULL;
84 
85  //The CPU/Memory cost parameter must be larger than 1, a power of 2, and
86  //less than 2^(128 * r / 8)
87  if(n <= 1 || (n & (n - 1)) != 0)
89 
90  //The block size parameter must be a positive integer
91  if(r == 0)
93 
94  //The parallelization parameter must be a positive integer less than or equal
95  //to ((2^32-1) * hLen) / MFLen where hLen is 32 and MFlen is 128 * r
96  if(p == 0)
98 
99  //Retrieve the length of the passphrase
100  passwordLen = osStrlen(password);
101 
102  //Each block consists of 128 * r octets
103  blockSize = 128 * r;
104 
105  //Start of exception handling block
106  do
107  {
108  //Initialize an array B consisting of p blocks
109  b = cryptoAllocMem(p * blockSize);
110  //Failed to allocate memory?
111  if(b == NULL)
112  {
113  //Report an error
114  error = ERROR_OUT_OF_MEMORY;
115  break;
116  }
117 
118  //Initialize a working array V consisting of N blocks
119  v = cryptoAllocMem(n * blockSize);
120  //Failed to allocate memory?
121  if(v == NULL)
122  {
123  //Report an error
124  error = ERROR_OUT_OF_MEMORY;
125  break;
126  }
127 
128  //Initialize a working array Y
129  y = cryptoAllocMem(blockSize);
130  //Failed to allocate memory?
131  if(y == NULL)
132  {
133  //Report an error
134  error = ERROR_OUT_OF_MEMORY;
135  break;
136  }
137 
138  //Compute B = PBKDF2-HMAC-SHA256(P, S, 1, p * 128 * r)
139  error = pbkdf2(SHA256_HASH_ALGO, (const uint8_t *) password,
140  passwordLen, salt, saltLen, 1, b, p * blockSize);
141  //Any error to report?
142  if(error)
143  break;
144 
145  //Iterate as many times as desired
146  for(i = 0; i < p; i++)
147  {
148  //Compute B[i] = scryptROMix(r, B[i], N)
149  scryptRoMix(r, b + i * blockSize, n, v, y);
150  }
151 
152  //Compute DK = PBKDF2-HMAC-SHA256(P, B, 1, dkLen)
153  error = pbkdf2(SHA256_HASH_ALGO, (const uint8_t *) password,
154  passwordLen, b, p * blockSize, 1, dk, dkLen);
155  //Any error to report?
156  if(error)
157  break;
158 
159  //End of exception handling block
160  } while(0);
161 
162  //Release array B
163  if(b != NULL)
164  {
165  cryptoFreeMem(b);
166  }
167 
168  //Release working array V
169  if(v != NULL)
170  {
171  cryptoFreeMem(v);
172  }
173 
174  //Release working array Y
175  if(y != NULL)
176  {
177  cryptoFreeMem(y);
178  }
179 
180  //Return status code
181  return error;
182 }
183 
184 
185 /**
186  * @brief scryptROMix algorithm
187  * @param[in] r Block size parameter
188  * @param[in,out] b Octet vector of length 128 * r octets
189  * @param[in] n CPU/Memory cost parameter
190  * @param[in,out] v Working array
191  * @param[in,out] y Working array
192  **/
193 
194 void scryptRoMix(uint_t r, uint8_t *b, uint_t n, uint8_t *v, uint8_t *y)
195 {
196  uint_t i;
197  uint32_t j;
198  uint8_t *x;
199  size_t blockSize;
200 
201  //Each block consists of 128 * r octets
202  blockSize = 128 * r;
203 
204  //Let X = B
205  x = b;
206 
207  //Compute V array
208  for(i = 0; i < n; i++)
209  {
210  //Let V[i] = X
211  osMemcpy(v + i * blockSize, x, blockSize);
212 
213  //Compute X = scryptBlockMix(r, X)
214  scryptBlockMix(r, x, y);
215  }
216 
217  //Compute B' array
218  for(i = 0; i < n; i++)
219  {
220  //Compute j = Integerify(X) mod N
221  j = LOAD32LE(x + blockSize - 64) & (n - 1);
222 
223  //Compute T = X xor V[j]
224  scryptXorBlock(x, x, v + j * blockSize, blockSize);
225 
226  //Compute X = scryptBlockMix(r, T)
227  scryptBlockMix(r, x, y);
228  }
229 }
230 
231 
232 /**
233  * @brief scryptBlockMix algorithm
234  * @param[in] r Block size parameter
235  * @param[in,out] b Octet vector of length 128 * r octets
236  * @param[in,out] y Working array
237  **/
238 
239 void scryptBlockMix(uint_t r, uint8_t *b, uint8_t *y)
240 {
241  uint_t i;
242  uint8_t x[64];
243 
244  //Let X = B[2 * r - 1]
245  osMemcpy(x, b + r * 128 - 64, 64);
246 
247  //Iterate as many times as desired
248  for(i = 0; i < (2 * r); i++)
249  {
250  //Compute T = X xor B[i]
251  scryptXorBlock(x, x, b + i * 64, 64);
252 
253  //Salsa20/8 Core is used as the hash function
254  salsa20ProcessBlock(x, x, 8);
255 
256  //Let Y[i] = X
257  osMemcpy(y + i * 64, x, 64);
258  }
259 
260  //Let B' = (Y[0], Y[2], ..., Y[2 * r - 2], Y[1], Y[3], ..., Y[2 * r - 1])
261  for(i = 0; i < r; i++)
262  {
263  osMemcpy(b + i * 64, y + i * 128, 64);
264  osMemcpy(b + (r + i) * 64, y + i * 128 + 64, 64);
265  }
266 }
267 
268 
269 /**
270  * @brief XOR operation
271  * @param[out] x Block resulting from the XOR operation
272  * @param[in] a First block
273  * @param[in] b Second block
274  * @param[in] n Size of the block
275  **/
276 
277 void scryptXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
278 {
279  size_t i;
280 
281  //Perform XOR operation
282  for(i = 0; i < n; i++)
283  {
284  x[i] = a[i] ^ b[i];
285  }
286 }
287 
288 
289 #endif
#define SHA256_HASH_ALGO
Definition: sha256.h:49
uint8_t b
Definition: nbns_common.h:104
uint8_t a
Definition: ndp.h:411
uint8_t p
Definition: ndp.h:300
uint8_t x
Definition: lldp_ext_med.h:211
scrypt PBKDF (Password-Based Key Derivation Function)
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
#define osStrlen(s)
Definition: os_port.h:165
uint8_t r
Definition: ndp.h:346
void scryptBlockMix(uint_t r, uint8_t *b, uint8_t *y)
scryptBlockMix algorithm
Definition: scrypt.c:239
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
error_t
Error codes.
Definition: error.h:43
error_t scrypt(const char_t *password, const uint8_t *salt, size_t saltLen, uint_t n, uint_t r, uint_t p, uint8_t *dk, size_t dkLen)
scrypt algorithm
Definition: scrypt.c:65
General definitions for cryptographic algorithms.
void scryptXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
XOR operation.
Definition: scrypt.c:277
void salsa20ProcessBlock(const uint8_t *input, uint8_t *output, uint_t nr)
Salsa20 core function.
Definition: salsa20.c:58
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
char char_t
Definition: compiler_port.h:48
SHA-256 (Secure Hash Algorithm 256)
PBKDF (Password-Based Key Derivation Function)
uint8_t n
#define cryptoFreeMem(p)
Definition: crypto.h:791
#define cryptoAllocMem(size)
Definition: crypto.h:786
void scryptRoMix(uint_t r, uint8_t *b, uint_t n, uint8_t *v, uint8_t *y)
scryptROMix algorithm
Definition: scrypt.c:194
#define LOAD32LE(p)
Definition: cpu_endian.h:203
unsigned int uint_t
Definition: compiler_port.h:50
Salsa20 encryption algorithm.