1
2 #include <errno.h>
3 #include <limits.h>
4 #include <stddef.h>
5 #include <stdint.h>
6 #include <string.h>
7
8 #include "crypto_pwhash_scryptsalsa208sha256.h"
9 #include "crypto_scrypt.h"
10 #include "private/common.h"
11 #include "randombytes.h"
12 #include "utils.h"
13
14 #define SETTING_SIZE(saltbytes) \
15 ((sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */) + \
16 BYTES2CHARS(saltbytes))
17
18 static int
pickparams(unsigned long long opslimit,const size_t memlimit,uint32_t * const N_log2,uint32_t * const p,uint32_t * const r)19 pickparams(unsigned long long opslimit, const size_t memlimit,
20 uint32_t *const N_log2, uint32_t *const p, uint32_t *const r)
21 {
22 unsigned long long maxN;
23 unsigned long long maxrp;
24
25 if (opslimit < 32768) {
26 opslimit = 32768;
27 }
28 *r = 8;
29 if (opslimit < memlimit / 32) {
30 *p = 1;
31 maxN = opslimit / (*r * 4);
32 for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) {
33 if ((uint64_t)(1) << *N_log2 > maxN / 2) {
34 break;
35 }
36 }
37 } else {
38 maxN = memlimit / ((size_t) *r * 128);
39 for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) {
40 if ((uint64_t)(1) << *N_log2 > maxN / 2) {
41 break;
42 }
43 }
44 maxrp = (opslimit / 4) / ((uint64_t)(1) << *N_log2);
45 /* LCOV_EXCL_START */
46 if (maxrp > 0x3fffffff) {
47 maxrp = 0x3fffffff;
48 }
49 /* LCOV_EXCL_STOP */
50 *p = (uint32_t)(maxrp) / *r;
51 }
52 return 0;
53 }
54
55 size_t
crypto_pwhash_scryptsalsa208sha256_bytes_min(void)56 crypto_pwhash_scryptsalsa208sha256_bytes_min(void)
57 {
58 return crypto_pwhash_scryptsalsa208sha256_BYTES_MIN;
59 }
60
61 size_t
crypto_pwhash_scryptsalsa208sha256_bytes_max(void)62 crypto_pwhash_scryptsalsa208sha256_bytes_max(void)
63 {
64 return crypto_pwhash_scryptsalsa208sha256_BYTES_MAX;
65 }
66
67 size_t
crypto_pwhash_scryptsalsa208sha256_passwd_min(void)68 crypto_pwhash_scryptsalsa208sha256_passwd_min(void)
69 {
70 return crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN;
71 }
72
73 size_t
crypto_pwhash_scryptsalsa208sha256_passwd_max(void)74 crypto_pwhash_scryptsalsa208sha256_passwd_max(void)
75 {
76 return crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX;
77 }
78
79 size_t
crypto_pwhash_scryptsalsa208sha256_saltbytes(void)80 crypto_pwhash_scryptsalsa208sha256_saltbytes(void)
81 {
82 return crypto_pwhash_scryptsalsa208sha256_SALTBYTES;
83 }
84
85 size_t
crypto_pwhash_scryptsalsa208sha256_strbytes(void)86 crypto_pwhash_scryptsalsa208sha256_strbytes(void)
87 {
88 return crypto_pwhash_scryptsalsa208sha256_STRBYTES;
89 }
90
91 const char *
crypto_pwhash_scryptsalsa208sha256_strprefix(void)92 crypto_pwhash_scryptsalsa208sha256_strprefix(void)
93 {
94 return crypto_pwhash_scryptsalsa208sha256_STRPREFIX;
95 }
96
97 size_t
crypto_pwhash_scryptsalsa208sha256_opslimit_min(void)98 crypto_pwhash_scryptsalsa208sha256_opslimit_min(void)
99 {
100 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN;
101 }
102
103 size_t
crypto_pwhash_scryptsalsa208sha256_opslimit_max(void)104 crypto_pwhash_scryptsalsa208sha256_opslimit_max(void)
105 {
106 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX;
107 }
108
109 size_t
crypto_pwhash_scryptsalsa208sha256_memlimit_min(void)110 crypto_pwhash_scryptsalsa208sha256_memlimit_min(void)
111 {
112 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN;
113 }
114
115 size_t
crypto_pwhash_scryptsalsa208sha256_memlimit_max(void)116 crypto_pwhash_scryptsalsa208sha256_memlimit_max(void)
117 {
118 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX;
119 }
120
121 size_t
crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void)122 crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void)
123 {
124 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE;
125 }
126
127 size_t
crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void)128 crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void)
129 {
130 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE;
131 }
132
133 size_t
crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void)134 crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void)
135 {
136 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE;
137 }
138
139 size_t
crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void)140 crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void)
141 {
142 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE;
143 }
144
145 int
crypto_pwhash_scryptsalsa208sha256(unsigned char * const out,unsigned long long outlen,const char * const passwd,unsigned long long passwdlen,const unsigned char * const salt,unsigned long long opslimit,size_t memlimit)146 crypto_pwhash_scryptsalsa208sha256(unsigned char *const out,
147 unsigned long long outlen,
148 const char *const passwd,
149 unsigned long long passwdlen,
150 const unsigned char *const salt,
151 unsigned long long opslimit, size_t memlimit)
152 {
153 uint32_t N_log2;
154 uint32_t p;
155 uint32_t r;
156
157 memset(out, 0, outlen);
158 if (passwdlen > crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX ||
159 outlen > crypto_pwhash_scryptsalsa208sha256_BYTES_MAX) {
160 errno = EFBIG; /* LCOV_EXCL_LINE */
161 return -1; /* LCOV_EXCL_LINE */
162 }
163 if (outlen < crypto_pwhash_scryptsalsa208sha256_BYTES_MIN ||
164 pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) {
165 errno = EINVAL; /* LCOV_EXCL_LINE */
166 return -1; /* LCOV_EXCL_LINE */
167 }
168 return crypto_pwhash_scryptsalsa208sha256_ll(
169 (const uint8_t *) passwd, (size_t) passwdlen, (const uint8_t *) salt,
170 crypto_pwhash_scryptsalsa208sha256_SALTBYTES, (uint64_t)(1) << N_log2,
171 r, p, out, (size_t) outlen);
172 }
173
174 int
crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES],const char * const passwd,unsigned long long passwdlen,unsigned long long opslimit,size_t memlimit)175 crypto_pwhash_scryptsalsa208sha256_str(
176 char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES],
177 const char *const passwd, unsigned long long passwdlen,
178 unsigned long long opslimit, size_t memlimit)
179 {
180 uint8_t salt[crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES];
181 char setting[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U];
182 escrypt_local_t escrypt_local;
183 uint32_t N_log2;
184 uint32_t p;
185 uint32_t r;
186
187 memset(out, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES);
188 if (passwdlen > crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX) {
189 errno = EFBIG; /* LCOV_EXCL_LINE */
190 return -1; /* LCOV_EXCL_LINE */
191 }
192 if (passwdlen < crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN ||
193 pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) {
194 errno = EINVAL; /* LCOV_EXCL_LINE */
195 return -1; /* LCOV_EXCL_LINE */
196 }
197 randombytes_buf(salt, sizeof salt);
198 if (escrypt_gensalt_r(N_log2, r, p, salt, sizeof salt, (uint8_t *) setting,
199 sizeof setting) == NULL) {
200 errno = EINVAL; /* LCOV_EXCL_LINE */
201 return -1; /* LCOV_EXCL_LINE */
202 }
203 if (escrypt_init_local(&escrypt_local) != 0) {
204 return -1; /* LCOV_EXCL_LINE */
205 }
206 if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen,
207 (const uint8_t *) setting, (uint8_t *) out,
208 crypto_pwhash_scryptsalsa208sha256_STRBYTES) == NULL) {
209 /* LCOV_EXCL_START */
210 escrypt_free_local(&escrypt_local);
211 errno = EINVAL;
212 return -1;
213 /* LCOV_EXCL_STOP */
214 }
215 escrypt_free_local(&escrypt_local);
216
217 COMPILER_ASSERT(
218 SETTING_SIZE(crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES) ==
219 crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES);
220 COMPILER_ASSERT(
221 crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U +
222 crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1U ==
223 crypto_pwhash_scryptsalsa208sha256_STRBYTES);
224
225 return 0;
226 }
227
228 int
crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],const char * const passwd,unsigned long long passwdlen)229 crypto_pwhash_scryptsalsa208sha256_str_verify(
230 const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],
231 const char *const passwd, unsigned long long passwdlen)
232 {
233 char wanted[crypto_pwhash_scryptsalsa208sha256_STRBYTES];
234 escrypt_local_t escrypt_local;
235 int ret = -1;
236
237 if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) !=
238 &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) {
239 return -1;
240 }
241 if (escrypt_init_local(&escrypt_local) != 0) {
242 return -1; /* LCOV_EXCL_LINE */
243 }
244 memset(wanted, 0, sizeof wanted);
245 if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen,
246 (const uint8_t *) str, (uint8_t *) wanted,
247 sizeof wanted) == NULL) {
248 escrypt_free_local(&escrypt_local);
249 return -1;
250 }
251 escrypt_free_local(&escrypt_local);
252 ret = sodium_memcmp(wanted, str, sizeof wanted);
253 sodium_memzero(wanted, sizeof wanted);
254
255 return ret;
256 }
257
258 int
crypto_pwhash_scryptsalsa208sha256_str_needs_rehash(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],unsigned long long opslimit,size_t memlimit)259 crypto_pwhash_scryptsalsa208sha256_str_needs_rehash(
260 const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],
261 unsigned long long opslimit, size_t memlimit)
262 {
263 uint32_t N_log2, N_log2_;
264 uint32_t p, p_;
265 uint32_t r, r_;
266
267 if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) {
268 errno = EINVAL;
269 return -1;
270 }
271 if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) !=
272 &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) {
273 errno = EINVAL;
274 return -1;
275 }
276 if (escrypt_parse_setting((const uint8_t *) str,
277 &N_log2_, &r_, &p_) == NULL) {
278 errno = EINVAL;
279 return -1;
280 }
281 if (N_log2 != N_log2_ || r != r_ || p != p_) {
282 return 1;
283 }
284 return 0;
285 }
286