xref: /freebsd/sys/contrib/libsodium/src/libsodium/crypto_pwhash/argon2/pwhash_argon2i.c (revision 3611ec604864a7d4dcc9a3ea898c80eb35eef8a0)
1 
2 #include <errno.h>
3 #include <limits.h>
4 #include <stddef.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include "argon2-core.h"
10 #include "argon2-encoding.h"
11 #include "argon2.h"
12 #include "crypto_pwhash.h"
13 #include "crypto_pwhash_argon2i.h"
14 #include "crypto_pwhash_argon2id.h"
15 #include "private/common.h"
16 #include "randombytes.h"
17 #include "utils.h"
18 
19 #define STR_HASHBYTES 32U
20 
21 int
crypto_pwhash_argon2i_alg_argon2i13(void)22 crypto_pwhash_argon2i_alg_argon2i13(void)
23 {
24     return crypto_pwhash_argon2i_ALG_ARGON2I13;
25 }
26 
27 size_t
crypto_pwhash_argon2i_bytes_min(void)28 crypto_pwhash_argon2i_bytes_min(void)
29 {
30     COMPILER_ASSERT(crypto_pwhash_argon2i_BYTES_MIN >= ARGON2_MIN_OUTLEN);
31     return crypto_pwhash_argon2i_BYTES_MIN;
32 }
33 
34 size_t
crypto_pwhash_argon2i_bytes_max(void)35 crypto_pwhash_argon2i_bytes_max(void)
36 {
37     COMPILER_ASSERT(crypto_pwhash_argon2i_BYTES_MAX <= ARGON2_MAX_OUTLEN);
38     return crypto_pwhash_argon2i_BYTES_MAX;
39 }
40 
41 size_t
crypto_pwhash_argon2i_passwd_min(void)42 crypto_pwhash_argon2i_passwd_min(void)
43 {
44     COMPILER_ASSERT(crypto_pwhash_argon2i_PASSWD_MIN >= ARGON2_MIN_PWD_LENGTH);
45     return crypto_pwhash_argon2i_PASSWD_MIN;
46 }
47 
48 size_t
crypto_pwhash_argon2i_passwd_max(void)49 crypto_pwhash_argon2i_passwd_max(void)
50 {
51     COMPILER_ASSERT(crypto_pwhash_argon2i_PASSWD_MAX <= ARGON2_MAX_PWD_LENGTH);
52     return crypto_pwhash_argon2i_PASSWD_MAX;
53 }
54 
55 size_t
crypto_pwhash_argon2i_saltbytes(void)56 crypto_pwhash_argon2i_saltbytes(void)
57 {
58     COMPILER_ASSERT(crypto_pwhash_argon2i_SALTBYTES >= ARGON2_MIN_SALT_LENGTH);
59     COMPILER_ASSERT(crypto_pwhash_argon2i_SALTBYTES <= ARGON2_MAX_SALT_LENGTH);
60     return crypto_pwhash_argon2i_SALTBYTES;
61 }
62 
63 size_t
crypto_pwhash_argon2i_strbytes(void)64 crypto_pwhash_argon2i_strbytes(void)
65 {
66     return crypto_pwhash_argon2i_STRBYTES;
67 }
68 
69 const char*
crypto_pwhash_argon2i_strprefix(void)70 crypto_pwhash_argon2i_strprefix(void)
71 {
72     return crypto_pwhash_argon2i_STRPREFIX;
73 }
74 
75 size_t
crypto_pwhash_argon2i_opslimit_min(void)76 crypto_pwhash_argon2i_opslimit_min(void)
77 {
78     COMPILER_ASSERT(crypto_pwhash_argon2i_OPSLIMIT_MIN >= ARGON2_MIN_TIME);
79     return crypto_pwhash_argon2i_OPSLIMIT_MIN;
80 }
81 
82 size_t
crypto_pwhash_argon2i_opslimit_max(void)83 crypto_pwhash_argon2i_opslimit_max(void)
84 {
85     COMPILER_ASSERT(crypto_pwhash_argon2i_OPSLIMIT_MAX <= ARGON2_MAX_TIME);
86     return crypto_pwhash_argon2i_OPSLIMIT_MAX;
87 }
88 
89 size_t
crypto_pwhash_argon2i_memlimit_min(void)90 crypto_pwhash_argon2i_memlimit_min(void)
91 {
92     COMPILER_ASSERT((crypto_pwhash_argon2i_MEMLIMIT_MIN / 1024U) >= ARGON2_MIN_MEMORY);
93     return crypto_pwhash_argon2i_MEMLIMIT_MIN;
94 }
95 
96 size_t
crypto_pwhash_argon2i_memlimit_max(void)97 crypto_pwhash_argon2i_memlimit_max(void)
98 {
99     COMPILER_ASSERT((crypto_pwhash_argon2i_MEMLIMIT_MAX / 1024U) <= ARGON2_MAX_MEMORY);
100     return crypto_pwhash_argon2i_MEMLIMIT_MAX;
101 }
102 
103 size_t
crypto_pwhash_argon2i_opslimit_interactive(void)104 crypto_pwhash_argon2i_opslimit_interactive(void)
105 {
106     return crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE;
107 }
108 
109 size_t
crypto_pwhash_argon2i_memlimit_interactive(void)110 crypto_pwhash_argon2i_memlimit_interactive(void)
111 {
112     return crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE;
113 }
114 
115 size_t
crypto_pwhash_argon2i_opslimit_moderate(void)116 crypto_pwhash_argon2i_opslimit_moderate(void)
117 {
118     return crypto_pwhash_argon2i_OPSLIMIT_MODERATE;
119 }
120 
121 size_t
crypto_pwhash_argon2i_memlimit_moderate(void)122 crypto_pwhash_argon2i_memlimit_moderate(void)
123 {
124     return crypto_pwhash_argon2i_MEMLIMIT_MODERATE;
125 }
126 
127 size_t
crypto_pwhash_argon2i_opslimit_sensitive(void)128 crypto_pwhash_argon2i_opslimit_sensitive(void)
129 {
130     return crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE;
131 }
132 
133 size_t
crypto_pwhash_argon2i_memlimit_sensitive(void)134 crypto_pwhash_argon2i_memlimit_sensitive(void)
135 {
136     return crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE;
137 }
138 
139 int
crypto_pwhash_argon2i(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,int alg)140 crypto_pwhash_argon2i(unsigned char *const out, unsigned long long outlen,
141                       const char *const passwd, unsigned long long passwdlen,
142                       const unsigned char *const salt,
143                       unsigned long long opslimit, size_t memlimit, int alg)
144 {
145     memset(out, 0, outlen);
146     if (outlen > crypto_pwhash_argon2i_BYTES_MAX) {
147         errno = EFBIG;
148         return -1;
149     }
150     if (outlen < crypto_pwhash_argon2i_BYTES_MIN) {
151         errno = EINVAL;
152         return -1;
153     }
154     if (passwdlen > crypto_pwhash_argon2i_PASSWD_MAX ||
155         opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX ||
156         memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX) {
157         errno = EFBIG;
158         return -1;
159     }
160     if (passwdlen < crypto_pwhash_argon2i_PASSWD_MIN ||
161         opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN ||
162         memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN) {
163         errno = EINVAL;
164         return -1;
165     }
166     switch (alg) {
167     case crypto_pwhash_argon2i_ALG_ARGON2I13:
168         if (argon2i_hash_raw((uint32_t) opslimit, (uint32_t) (memlimit / 1024U),
169                              (uint32_t) 1U, passwd, (size_t) passwdlen, salt,
170                              (size_t) crypto_pwhash_argon2i_SALTBYTES, out,
171                              (size_t) outlen) != ARGON2_OK) {
172             return -1; /* LCOV_EXCL_LINE */
173         }
174         return 0;
175     default:
176         errno = EINVAL;
177         return -1;
178     }
179 }
180 
181 int
crypto_pwhash_argon2i_str(char out[crypto_pwhash_argon2i_STRBYTES],const char * const passwd,unsigned long long passwdlen,unsigned long long opslimit,size_t memlimit)182 crypto_pwhash_argon2i_str(char out[crypto_pwhash_argon2i_STRBYTES],
183                           const char *const passwd,
184                           unsigned long long passwdlen,
185                           unsigned long long opslimit, size_t memlimit)
186 {
187     unsigned char salt[crypto_pwhash_argon2i_SALTBYTES];
188 
189     memset(out, 0, crypto_pwhash_argon2i_STRBYTES);
190     if (passwdlen > crypto_pwhash_argon2i_PASSWD_MAX ||
191         opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX ||
192         memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX) {
193         errno = EFBIG;
194         return -1;
195     }
196     if (passwdlen < crypto_pwhash_argon2i_PASSWD_MIN ||
197         opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN ||
198         memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN) {
199         errno = EINVAL;
200         return -1;
201     }
202     randombytes_buf(salt, sizeof salt);
203     if (argon2i_hash_encoded((uint32_t) opslimit, (uint32_t) (memlimit / 1024U),
204                              (uint32_t) 1U, passwd, (size_t) passwdlen, salt,
205                              sizeof salt, STR_HASHBYTES, out,
206                              crypto_pwhash_argon2i_STRBYTES) != ARGON2_OK) {
207         return -1; /* LCOV_EXCL_LINE */
208     }
209     return 0;
210 }
211 
212 int
crypto_pwhash_argon2i_str_verify(const char str[crypto_pwhash_argon2i_STRBYTES],const char * const passwd,unsigned long long passwdlen)213 crypto_pwhash_argon2i_str_verify(const char str[crypto_pwhash_argon2i_STRBYTES],
214                                  const char *const  passwd,
215                                  unsigned long long passwdlen)
216 {
217     int verify_ret;
218 
219     if (passwdlen > crypto_pwhash_argon2i_PASSWD_MAX) {
220         errno = EFBIG;
221         return -1;
222     }
223     /* LCOV_EXCL_START */
224     if (passwdlen < crypto_pwhash_argon2i_PASSWD_MIN) {
225         errno = EINVAL;
226         return -1;
227     }
228     /* LCOV_EXCL_STOP */
229 
230     verify_ret = argon2i_verify(str, passwd, (size_t) passwdlen);
231     if (verify_ret == ARGON2_OK) {
232         return 0;
233     }
234     if (verify_ret == ARGON2_VERIFY_MISMATCH) {
235         errno = EINVAL;
236     }
237     return -1;
238 }
239 
240 static int
_needs_rehash(const char * str,unsigned long long opslimit,size_t memlimit,argon2_type type)241 _needs_rehash(const char *str, unsigned long long opslimit, size_t memlimit,
242               argon2_type type)
243 {
244     unsigned char  *fodder;
245     argon2_context  ctx;
246     size_t          fodder_len;
247     int             ret = -1;
248 
249     fodder_len = strlen(str);
250     memlimit /= 1024U;
251     if (opslimit > UINT32_MAX || memlimit > UINT32_MAX ||
252         fodder_len >= crypto_pwhash_STRBYTES) {
253         errno = EINVAL;
254         return -1;
255     }
256     memset(&ctx, 0, sizeof ctx);
257     if ((fodder = (unsigned char *) calloc(fodder_len, 1U)) == NULL) {
258         return -1; /* LCOV_EXCL_LINE */
259     }
260     ctx.out    = ctx.pwd       = ctx.salt    = fodder;
261     ctx.outlen = ctx.pwdlen    = ctx.saltlen = (uint32_t) fodder_len;
262     ctx.ad     = ctx.secret    = NULL;
263     ctx.adlen  = ctx.secretlen = 0U;
264     if (decode_string(&ctx, str, type) != 0) {
265         errno = EINVAL;
266         ret = -1;
267     } else if (ctx.t_cost != (uint32_t) opslimit ||
268                ctx.m_cost != (uint32_t) memlimit) {
269         ret = 1;
270     } else {
271         ret = 0;
272     }
273     free(fodder);
274 
275     return ret;
276 }
277 
278 int
crypto_pwhash_argon2i_str_needs_rehash(const char str[crypto_pwhash_argon2i_STRBYTES],unsigned long long opslimit,size_t memlimit)279 crypto_pwhash_argon2i_str_needs_rehash(const char str[crypto_pwhash_argon2i_STRBYTES],
280                                        unsigned long long opslimit, size_t memlimit)
281 {
282     return _needs_rehash(str, opslimit, memlimit, Argon2_i);
283 }
284 
285 int
crypto_pwhash_argon2id_str_needs_rehash(const char str[crypto_pwhash_argon2id_STRBYTES],unsigned long long opslimit,size_t memlimit)286 crypto_pwhash_argon2id_str_needs_rehash(const char str[crypto_pwhash_argon2id_STRBYTES],
287                                         unsigned long long opslimit, size_t memlimit)
288 {
289     return _needs_rehash(str, opslimit, memlimit, Argon2_id);
290 }
291