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 static size_t
sodium_strnlen(const char * str,size_t maxlen)56 sodium_strnlen(const char *str, size_t maxlen)
57 {
58 size_t i = 0U;
59
60 while (i < maxlen && str[i] != 0) {
61 i++;
62 }
63 return i;
64 }
65
66 size_t
crypto_pwhash_scryptsalsa208sha256_bytes_min(void)67 crypto_pwhash_scryptsalsa208sha256_bytes_min(void)
68 {
69 return crypto_pwhash_scryptsalsa208sha256_BYTES_MIN;
70 }
71
72 size_t
crypto_pwhash_scryptsalsa208sha256_bytes_max(void)73 crypto_pwhash_scryptsalsa208sha256_bytes_max(void)
74 {
75 return crypto_pwhash_scryptsalsa208sha256_BYTES_MAX;
76 }
77
78 size_t
crypto_pwhash_scryptsalsa208sha256_passwd_min(void)79 crypto_pwhash_scryptsalsa208sha256_passwd_min(void)
80 {
81 return crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN;
82 }
83
84 size_t
crypto_pwhash_scryptsalsa208sha256_passwd_max(void)85 crypto_pwhash_scryptsalsa208sha256_passwd_max(void)
86 {
87 return crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX;
88 }
89
90 size_t
crypto_pwhash_scryptsalsa208sha256_saltbytes(void)91 crypto_pwhash_scryptsalsa208sha256_saltbytes(void)
92 {
93 return crypto_pwhash_scryptsalsa208sha256_SALTBYTES;
94 }
95
96 size_t
crypto_pwhash_scryptsalsa208sha256_strbytes(void)97 crypto_pwhash_scryptsalsa208sha256_strbytes(void)
98 {
99 return crypto_pwhash_scryptsalsa208sha256_STRBYTES;
100 }
101
102 const char *
crypto_pwhash_scryptsalsa208sha256_strprefix(void)103 crypto_pwhash_scryptsalsa208sha256_strprefix(void)
104 {
105 return crypto_pwhash_scryptsalsa208sha256_STRPREFIX;
106 }
107
108 size_t
crypto_pwhash_scryptsalsa208sha256_opslimit_min(void)109 crypto_pwhash_scryptsalsa208sha256_opslimit_min(void)
110 {
111 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN;
112 }
113
114 size_t
crypto_pwhash_scryptsalsa208sha256_opslimit_max(void)115 crypto_pwhash_scryptsalsa208sha256_opslimit_max(void)
116 {
117 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX;
118 }
119
120 size_t
crypto_pwhash_scryptsalsa208sha256_memlimit_min(void)121 crypto_pwhash_scryptsalsa208sha256_memlimit_min(void)
122 {
123 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN;
124 }
125
126 size_t
crypto_pwhash_scryptsalsa208sha256_memlimit_max(void)127 crypto_pwhash_scryptsalsa208sha256_memlimit_max(void)
128 {
129 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX;
130 }
131
132 size_t
crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void)133 crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void)
134 {
135 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE;
136 }
137
138 size_t
crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void)139 crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void)
140 {
141 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE;
142 }
143
144 size_t
crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void)145 crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void)
146 {
147 return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE;
148 }
149
150 size_t
crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void)151 crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void)
152 {
153 return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE;
154 }
155
156 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)157 crypto_pwhash_scryptsalsa208sha256(unsigned char *const out,
158 unsigned long long outlen,
159 const char *const passwd,
160 unsigned long long passwdlen,
161 const unsigned char *const salt,
162 unsigned long long opslimit, size_t memlimit)
163 {
164 uint32_t N_log2;
165 uint32_t p;
166 uint32_t r;
167
168 memset(out, 0, outlen);
169 if (passwdlen > crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX ||
170 outlen > crypto_pwhash_scryptsalsa208sha256_BYTES_MAX) {
171 errno = EFBIG; /* LCOV_EXCL_LINE */
172 return -1; /* LCOV_EXCL_LINE */
173 }
174 if (outlen < crypto_pwhash_scryptsalsa208sha256_BYTES_MIN ||
175 pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) {
176 errno = EINVAL; /* LCOV_EXCL_LINE */
177 return -1; /* LCOV_EXCL_LINE */
178 }
179 return crypto_pwhash_scryptsalsa208sha256_ll(
180 (const uint8_t *) passwd, (size_t) passwdlen, (const uint8_t *) salt,
181 crypto_pwhash_scryptsalsa208sha256_SALTBYTES, (uint64_t)(1) << N_log2,
182 r, p, out, (size_t) outlen);
183 }
184
185 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)186 crypto_pwhash_scryptsalsa208sha256_str(
187 char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES],
188 const char *const passwd, unsigned long long passwdlen,
189 unsigned long long opslimit, size_t memlimit)
190 {
191 uint8_t salt[crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES];
192 char setting[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U];
193 escrypt_local_t escrypt_local;
194 uint32_t N_log2;
195 uint32_t p;
196 uint32_t r;
197
198 memset(out, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES);
199 if (passwdlen > crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX) {
200 errno = EFBIG; /* LCOV_EXCL_LINE */
201 return -1; /* LCOV_EXCL_LINE */
202 }
203 if (passwdlen < crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN ||
204 pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) {
205 errno = EINVAL; /* LCOV_EXCL_LINE */
206 return -1; /* LCOV_EXCL_LINE */
207 }
208 randombytes_buf(salt, sizeof salt);
209 if (escrypt_gensalt_r(N_log2, r, p, salt, sizeof salt, (uint8_t *) setting,
210 sizeof setting) == NULL) {
211 errno = EINVAL; /* LCOV_EXCL_LINE */
212 return -1; /* LCOV_EXCL_LINE */
213 }
214 if (escrypt_init_local(&escrypt_local) != 0) {
215 return -1; /* LCOV_EXCL_LINE */
216 }
217 if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen,
218 (const uint8_t *) setting, (uint8_t *) out,
219 crypto_pwhash_scryptsalsa208sha256_STRBYTES) == NULL) {
220 /* LCOV_EXCL_START */
221 escrypt_free_local(&escrypt_local);
222 errno = EINVAL;
223 return -1;
224 /* LCOV_EXCL_STOP */
225 }
226 escrypt_free_local(&escrypt_local);
227
228 COMPILER_ASSERT(
229 SETTING_SIZE(crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES) ==
230 crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES);
231 COMPILER_ASSERT(
232 crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U +
233 crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1U ==
234 crypto_pwhash_scryptsalsa208sha256_STRBYTES);
235
236 return 0;
237 }
238
239 int
crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],const char * const passwd,unsigned long long passwdlen)240 crypto_pwhash_scryptsalsa208sha256_str_verify(
241 const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],
242 const char *const passwd, unsigned long long passwdlen)
243 {
244 char wanted[crypto_pwhash_scryptsalsa208sha256_STRBYTES];
245 escrypt_local_t escrypt_local;
246 int ret = -1;
247
248 if (sodium_strnlen(str, crypto_pwhash_scryptsalsa208sha256_STRBYTES) !=
249 crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U) {
250 return -1;
251 }
252 if (escrypt_init_local(&escrypt_local) != 0) {
253 return -1; /* LCOV_EXCL_LINE */
254 }
255 memset(wanted, 0, sizeof wanted);
256 if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen,
257 (const uint8_t *) str, (uint8_t *) wanted,
258 sizeof wanted) == NULL) {
259 escrypt_free_local(&escrypt_local);
260 return -1;
261 }
262 escrypt_free_local(&escrypt_local);
263 ret = sodium_memcmp(wanted, str, sizeof wanted);
264 sodium_memzero(wanted, sizeof wanted);
265
266 return ret;
267 }
268
269 int
crypto_pwhash_scryptsalsa208sha256_str_needs_rehash(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],unsigned long long opslimit,size_t memlimit)270 crypto_pwhash_scryptsalsa208sha256_str_needs_rehash(
271 const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],
272 unsigned long long opslimit, size_t memlimit)
273 {
274 uint32_t N_log2, N_log2_;
275 uint32_t p, p_;
276 uint32_t r, r_;
277
278 if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) {
279 errno = EINVAL;
280 return -1;
281 }
282 if (sodium_strnlen(str, crypto_pwhash_scryptsalsa208sha256_STRBYTES) !=
283 crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U) {
284 errno = EINVAL;
285 return -1;
286 }
287 if (escrypt_parse_setting((const uint8_t *) str,
288 &N_log2_, &r_, &p_) == NULL) {
289 errno = EINVAL;
290 return -1;
291 }
292 if (N_log2 != N_log2_ || r != r_ || p != p_) {
293 return 1;
294 }
295 return 0;
296 }
297