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-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  * @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.6.6
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)
140  (const uint8_t *) password, passwordLen, salt, saltLen, 1, b,
141  p * blockSize);
142  //Any error to report?
143  if(error)
144  break;
145 
146  //Iterate as many times as desired
147  for(i = 0; i < p; i++)
148  {
149  //Compute B[i] = scryptROMix(r, B[i], N)
150  scryptRoMix(r, b + i * blockSize, n, v, y);
151  }
152 
153  //Compute DK = PBKDF2-HMAC-SHA256(P, B, 1, dkLen)
155  (const uint8_t *) password, passwordLen, b, p * blockSize, 1, dk,
156  dkLen);
157  //Any error to report?
158  if(error)
159  break;
160 
161  //End of exception handling block
162  } while(0);
163 
164  //Release array B
165  if(b != NULL)
166  {
167  cryptoFreeMem(b);
168  }
169 
170  //Release working array V
171  if(v != NULL)
172  {
173  cryptoFreeMem(v);
174  }
175 
176  //Release working array Y
177  if(y != NULL)
178  {
179  cryptoFreeMem(y);
180  }
181 
182  //Return status code
183  return error;
184 }
185 
186 
187 /**
188  * @brief scryptROMix algorithm
189  * @param[in] r Block size parameter
190  * @param[in,out] b Octet vector of length 128 * r octets
191  * @param[in] n CPU/Memory cost parameter
192  * @param[in,out] v Working array
193  * @param[in,out] y Working array
194  **/
195 
196 void scryptRoMix(uint_t r, uint8_t *b, uint_t n, uint8_t *v, uint8_t *y)
197 {
198  uint_t i;
199  uint32_t j;
200  uint8_t *x;
201  size_t blockSize;
202 
203  //Each block consists of 128 * r octets
204  blockSize = 128 * r;
205 
206  //Let X = B
207  x = b;
208 
209  //Compute V array
210  for(i = 0; i < n; i++)
211  {
212  //Let V[i] = X
213  osMemcpy(v + i * blockSize, x, blockSize);
214 
215  //Compute X = scryptBlockMix(r, X)
216  scryptBlockMix(r, x, y);
217  }
218 
219  //Compute B' array
220  for(i = 0; i < n; i++)
221  {
222  //Compute j = Integerify(X) mod N
223  j = LOAD32LE(x + blockSize - 64) & (n - 1);
224 
225  //Compute T = X xor V[j]
226  scryptXorBlock(x, x, v + j * blockSize, blockSize);
227 
228  //Compute X = scryptBlockMix(r, T)
229  scryptBlockMix(r, x, y);
230  }
231 }
232 
233 
234 /**
235  * @brief scryptBlockMix algorithm
236  * @param[in] r Block size parameter
237  * @param[in,out] b Octet vector of length 128 * r octets
238  * @param[in,out] y Working array
239  **/
240 
241 void scryptBlockMix(uint_t r, uint8_t *b, uint8_t *y)
242 {
243  uint_t i;
244  uint8_t x[64];
245 
246  //Let X = B[2 * r - 1]
247  osMemcpy(x, b + r * 128 - 64, 64);
248 
249  //Iterate as many times as desired
250  for(i = 0; i < (2 * r); i++)
251  {
252  //Compute T = X xor B[i]
253  scryptXorBlock(x, x, b + i * 64, 64);
254 
255  //Salsa20/8 Core is used as the hash function
256  salsa20ProcessBlock(x, x, 8);
257 
258  //Let Y[i] = X
259  osMemcpy(y + i * 64, x, 64);
260  }
261 
262  //Let B' = (Y[0], Y[2], ..., Y[2 * r - 2], Y[1], Y[3], ..., Y[2 * r - 1])
263  for(i = 0; i < r; i++)
264  {
265  osMemcpy(b + i * 64, y + i * 128, 64);
266  osMemcpy(b + (r + i) * 64, y + i * 128 + 64, 64);
267  }
268 }
269 
270 
271 /**
272  * @brief XOR operation
273  * @param[out] x Block resulting from the XOR operation
274  * @param[in] a First block
275  * @param[in] b Second block
276  * @param[in] n Size of the block
277  **/
278 
279 void scryptXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
280 {
281  size_t i;
282 
283  //Perform XOR operation
284  for(i = 0; i < n; i++)
285  {
286  x[i] = a[i] ^ b[i];
287  }
288 }
289 
290 
291 #endif
#define SHA256_HASH_ALGO
Definition: sha256.h:49
uint8_t b
Definition: nbns_common.h:122
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
uint8_t p
Definition: ndp.h:300
uint8_t x
Definition: lldp_ext_med.h:211
@ PBKDF2_TYPE_HMAC
Definition: pbkdf.h:49
scrypt PBKDF (Password-Based Key Derivation Function)
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
#define osStrlen(s)
Definition: os_port.h:171
uint8_t r
Definition: ndp.h:346
void scryptBlockMix(uint_t r, uint8_t *b, uint8_t *y)
scryptBlockMix algorithm
Definition: scrypt.c:241
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:147
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:279
void salsa20ProcessBlock(const uint8_t *input, uint8_t *output, uint_t nr)
Salsa20 core function.
Definition: salsa20.c:58
char char_t
Definition: compiler_port.h:55
SHA-256 (Secure Hash Algorithm 256)
PBKDF (Password-Based Key Derivation Function)
uint8_t n
#define cryptoFreeMem(p)
Definition: crypto.h:966
#define cryptoAllocMem(size)
Definition: crypto.h:961
void scryptRoMix(uint_t r, uint8_t *b, uint_t n, uint8_t *v, uint8_t *y)
scryptROMix algorithm
Definition: scrypt.c:196
#define LOAD32LE(p)
Definition: cpu_endian.h:203
unsigned int uint_t
Definition: compiler_port.h:57
Salsa20 encryption algorithm.