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-2019 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 1.9.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/pkcs5.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 = cryptoStrlen(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, password, passwordLen, salt, saltLen,
140  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, password, passwordLen, b,
154  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  cryptoFreeMem(b);
165 
166  //Release working array V
167  if(v != NULL)
168  cryptoFreeMem(v);
169 
170  //Release working array Y
171  if(y != NULL)
172  cryptoFreeMem(y);
173 
174  //Return status code
175  return error;
176 }
177 
178 
179 /**
180  * @brief scryptROMix algorithm
181  * @param[in] r Block size parameter
182  * @param[in,out] b Octet vector of length 128 * r octets
183  * @param[in] n CPU/Memory cost parameter
184  * @param[in,out] v Working array
185  * @param[in,out] y Working array
186  **/
187 
188 void scryptRoMix(uint_t r, uint8_t *b, uint_t n, uint8_t *v, uint8_t *y)
189 {
190  uint_t i;
191  uint32_t j;
192  uint8_t *x;
193  size_t blockSize;
194 
195  //Each block consists of 128 * r octets
196  blockSize = 128 * r;
197 
198  //Let X = B
199  x = b;
200 
201  //Compute V array
202  for(i = 0; i < n; i++)
203  {
204  //Let V[i] = X
205  cryptoMemcpy(v + i * blockSize, x, blockSize);
206 
207  //Compute X = scryptBlockMix(r, X)
208  scryptBlockMix(r, x, y);
209  }
210 
211  //Compute B' array
212  for(i = 0; i < n; i++)
213  {
214  //Compute j = Integerify(X) mod N
215  j = LOAD32LE(x + blockSize - 64) & (n - 1);
216 
217  //Compute T = X xor V[j]
218  scryptXorBlock(x, x, v + j * blockSize, blockSize);
219 
220  //Compute X = scryptBlockMix(r, T)
221  scryptBlockMix(r, x, y);
222  }
223 }
224 
225 
226 /**
227  * @brief scryptBlockMix algorithm
228  * @param[in] r Block size parameter
229  * @param[in,out] b Octet vector of length 128 * r octets
230  * @param[in,out] y Working array
231  **/
232 
233 void scryptBlockMix(uint_t r, uint8_t *b, uint8_t *y)
234 {
235  uint_t i;
236  uint8_t x[64];
237 
238  //Let X = B[2 * r - 1]
239  cryptoMemcpy(x, b + r * 128 - 64, 64);
240 
241  //Iterate as many times as desired
242  for(i = 0; i < (2 * r); i++)
243  {
244  //Compute T = X xor B[i]
245  scryptXorBlock(x, x, b + i * 64, 64);
246 
247  //Salsa20/8 Core is used as the hash function
248  salsa20ProcessBlock(x, x, 8);
249 
250  //Let Y[i] = X
251  cryptoMemcpy(y + i * 64, x, 64);
252  }
253 
254  //Let B' = (Y[0], Y[2], ..., Y[2 * r - 2], Y[1], Y[3], ..., Y[2 * r - 1])
255  for(i = 0; i < r; i++)
256  {
257  cryptoMemcpy(b + i * 64, y + i * 128, 64);
258  cryptoMemcpy(b + (r + i) * 64, y + i * 128 + 64, 64);
259  }
260 }
261 
262 
263 /**
264  * @brief XOR operation
265  * @param[out] x Block resulting from the XOR operation
266  * @param[in] a First block
267  * @param[in] b Second block
268  * @param[in] n Size of the block
269  **/
270 
271 void scryptXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
272 {
273  size_t i;
274 
275  //Perform XOR operation
276  for(i = 0; i < n; i++)
277  {
278  x[i] = a[i] ^ b[i];
279  }
280 }
281 
282 
283 #endif
#define SHA256_HASH_ALGO
Definition: sha256.h:46
uint8_t a
Definition: ndp.h:410
uint8_t b[6]
Definition: dtls_misc.h:139
uint8_t p
Definition: ndp.h:298
scrypt PBKDF (Password-Based Key Derivation Function)
PKCS #5 (Password-Based Cryptography Standard)
uint32_t r
Definition: ndp.h:345
void scryptBlockMix(uint_t r, uint8_t *b, uint8_t *y)
scryptBlockMix algorithm
Definition: scrypt.c:233
Invalid parameter.
Definition: error.h:47
#define cryptoStrlen(s)
Definition: crypto.h:660
error_t
Error codes.
Definition: error.h:42
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:271
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:43
SHA-256 (Secure Hash Algorithm 256)
uint8_t n
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: pkcs5.c:134
#define cryptoMemcpy(dest, src, length)
Definition: crypto.h:642
#define cryptoFreeMem(p)
Definition: crypto.h:630
#define cryptoAllocMem(size)
Definition: crypto.h:625
void scryptRoMix(uint_t r, uint8_t *b, uint_t n, uint8_t *v, uint8_t *y)
scryptROMix algorithm
Definition: scrypt.c:188
#define LOAD32LE(p)
Definition: cpu_endian.h:187
unsigned int uint_t
Definition: compiler_port.h:45
Salsa20 encryption algorithm.