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