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