1 
2 #include <errno.h>
3 #include <limits.h>
4 #include <stddef.h>
5 #include <stdint.h>
6 #include <string.h>
7 
8 #include "argon2-core.h"
9 #include "argon2.h"
10 #include "crypto_pwhash_argon2id.h"
11 #include "private/common.h"
12 #include "randombytes.h"
13 #include "utils.h"
14 
15 #define STR_HASHBYTES 32U
16 
17 int
crypto_pwhash_argon2id_alg_argon2id13(void)18 crypto_pwhash_argon2id_alg_argon2id13(void)
19 {
20     return crypto_pwhash_argon2id_ALG_ARGON2ID13;
21 }
22 
23 size_t
crypto_pwhash_argon2id_bytes_min(void)24 crypto_pwhash_argon2id_bytes_min(void)
25 {
26     COMPILER_ASSERT(crypto_pwhash_argon2id_BYTES_MIN >= ARGON2_MIN_OUTLEN);
27     return crypto_pwhash_argon2id_BYTES_MIN;
28 }
29 
30 size_t
crypto_pwhash_argon2id_bytes_max(void)31 crypto_pwhash_argon2id_bytes_max(void)
32 {
33     COMPILER_ASSERT(crypto_pwhash_argon2id_BYTES_MAX <= ARGON2_MAX_OUTLEN);
34     return crypto_pwhash_argon2id_BYTES_MAX;
35 }
36 
37 size_t
crypto_pwhash_argon2id_passwd_min(void)38 crypto_pwhash_argon2id_passwd_min(void)
39 {
40     COMPILER_ASSERT(crypto_pwhash_argon2id_PASSWD_MIN >= ARGON2_MIN_PWD_LENGTH);
41     return crypto_pwhash_argon2id_PASSWD_MIN;
42 }
43 
44 size_t
crypto_pwhash_argon2id_passwd_max(void)45 crypto_pwhash_argon2id_passwd_max(void)
46 {
47     COMPILER_ASSERT(crypto_pwhash_argon2id_PASSWD_MAX <= ARGON2_MAX_PWD_LENGTH);
48     return crypto_pwhash_argon2id_PASSWD_MAX;
49 }
50 
51 size_t
crypto_pwhash_argon2id_saltbytes(void)52 crypto_pwhash_argon2id_saltbytes(void)
53 {
54     COMPILER_ASSERT(crypto_pwhash_argon2id_SALTBYTES >= ARGON2_MIN_SALT_LENGTH);
55     COMPILER_ASSERT(crypto_pwhash_argon2id_SALTBYTES <= ARGON2_MAX_SALT_LENGTH);
56     return crypto_pwhash_argon2id_SALTBYTES;
57 }
58 
59 size_t
crypto_pwhash_argon2id_strbytes(void)60 crypto_pwhash_argon2id_strbytes(void)
61 {
62     return crypto_pwhash_argon2id_STRBYTES;
63 }
64 
65 const char*
crypto_pwhash_argon2id_strprefix(void)66 crypto_pwhash_argon2id_strprefix(void)
67 {
68     return crypto_pwhash_argon2id_STRPREFIX;
69 }
70 
71 size_t
crypto_pwhash_argon2id_opslimit_min(void)72 crypto_pwhash_argon2id_opslimit_min(void)
73 {
74     COMPILER_ASSERT(crypto_pwhash_argon2id_OPSLIMIT_MIN >= ARGON2_MIN_TIME);
75     return crypto_pwhash_argon2id_OPSLIMIT_MIN;
76 }
77 
78 size_t
crypto_pwhash_argon2id_opslimit_max(void)79 crypto_pwhash_argon2id_opslimit_max(void)
80 {
81     COMPILER_ASSERT(crypto_pwhash_argon2id_OPSLIMIT_MAX <= ARGON2_MAX_TIME);
82     return crypto_pwhash_argon2id_OPSLIMIT_MAX;
83 }
84 
85 size_t
crypto_pwhash_argon2id_memlimit_min(void)86 crypto_pwhash_argon2id_memlimit_min(void)
87 {
88     COMPILER_ASSERT((crypto_pwhash_argon2id_MEMLIMIT_MIN / 1024U) >= ARGON2_MIN_MEMORY);
89     return crypto_pwhash_argon2id_MEMLIMIT_MIN;
90 }
91 
92 size_t
crypto_pwhash_argon2id_memlimit_max(void)93 crypto_pwhash_argon2id_memlimit_max(void)
94 {
95     COMPILER_ASSERT((crypto_pwhash_argon2id_MEMLIMIT_MAX / 1024U) <= ARGON2_MAX_MEMORY);
96     return crypto_pwhash_argon2id_MEMLIMIT_MAX;
97 }
98 
99 size_t
crypto_pwhash_argon2id_opslimit_interactive(void)100 crypto_pwhash_argon2id_opslimit_interactive(void)
101 {
102     return crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE;
103 }
104 
105 size_t
crypto_pwhash_argon2id_memlimit_interactive(void)106 crypto_pwhash_argon2id_memlimit_interactive(void)
107 {
108     return crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE;
109 }
110 
111 size_t
crypto_pwhash_argon2id_opslimit_moderate(void)112 crypto_pwhash_argon2id_opslimit_moderate(void)
113 {
114     return crypto_pwhash_argon2id_OPSLIMIT_MODERATE;
115 }
116 
117 size_t
crypto_pwhash_argon2id_memlimit_moderate(void)118 crypto_pwhash_argon2id_memlimit_moderate(void)
119 {
120     return crypto_pwhash_argon2id_MEMLIMIT_MODERATE;
121 }
122 
123 size_t
crypto_pwhash_argon2id_opslimit_sensitive(void)124 crypto_pwhash_argon2id_opslimit_sensitive(void)
125 {
126     return crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE;
127 }
128 
129 size_t
crypto_pwhash_argon2id_memlimit_sensitive(void)130 crypto_pwhash_argon2id_memlimit_sensitive(void)
131 {
132     return crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE;
133 }
134 
135 int
crypto_pwhash_argon2id(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)136 crypto_pwhash_argon2id(unsigned char *const out, unsigned long long outlen,
137                        const char *const passwd, unsigned long long passwdlen,
138                        const unsigned char *const salt,
139                        unsigned long long opslimit, size_t memlimit, int alg)
140 {
141     memset(out, 0, outlen);
142     if (outlen > crypto_pwhash_argon2id_BYTES_MAX) {
143         errno = EFBIG;
144         return -1;
145     }
146     if (outlen < crypto_pwhash_argon2id_BYTES_MIN) {
147         errno = EINVAL;
148         return -1;
149     }
150     if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX ||
151         opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX ||
152         memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX) {
153         errno = EFBIG;
154         return -1;
155     }
156     if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN ||
157         opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN ||
158         memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN) {
159         errno = EINVAL;
160         return -1;
161     }
162     if ((const void *) out == (const void *) passwd) {
163         errno = EINVAL;
164         return -1;
165     }
166     switch (alg) {
167     case crypto_pwhash_argon2id_ALG_ARGON2ID13:
168         if (argon2id_hash_raw((uint32_t) opslimit, (uint32_t) (memlimit / 1024U),
169                               (uint32_t) 1U, passwd, (size_t) passwdlen, salt,
170                               (size_t) crypto_pwhash_argon2id_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_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES],const char * const passwd,unsigned long long passwdlen,unsigned long long opslimit,size_t memlimit)182 crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_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_argon2id_SALTBYTES];
188 
189     memset(out, 0, crypto_pwhash_argon2id_STRBYTES);
190     if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX ||
191         opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX ||
192         memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX) {
193         errno = EFBIG;
194         return -1;
195     }
196     if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN ||
197         opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN ||
198         memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN) {
199         errno = EINVAL;
200         return -1;
201     }
202     randombytes_buf(salt, sizeof salt);
203     if (argon2id_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_argon2id_STRBYTES) != ARGON2_OK) {
207         return -1; /* LCOV_EXCL_LINE */
208     }
209     return 0;
210 }
211 
212 int
crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES],const char * const passwd,unsigned long long passwdlen)213 crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES],
214                                   const char *const  passwd,
215                                   unsigned long long passwdlen)
216 {
217     int verify_ret;
218 
219     if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX) {
220         errno = EFBIG;
221         return -1;
222     }
223     /* LCOV_EXCL_START */
224     if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN) {
225         errno = EINVAL;
226         return -1;
227     }
228     /* LCOV_EXCL_STOP */
229 
230     verify_ret = argon2id_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