xref: /freebsd/sys/contrib/libsodium/src/libsodium/crypto_pwhash/argon2/pwhash_argon2id.c (revision 3611ec604864a7d4dcc9a3ea898c80eb35eef8a0)
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     switch (alg) {
163     case crypto_pwhash_argon2id_ALG_ARGON2ID13:
164         if (argon2id_hash_raw((uint32_t) opslimit, (uint32_t) (memlimit / 1024U),
165                               (uint32_t) 1U, passwd, (size_t) passwdlen, salt,
166                               (size_t) crypto_pwhash_argon2id_SALTBYTES, out,
167                               (size_t) outlen) != ARGON2_OK) {
168             return -1; /* LCOV_EXCL_LINE */
169         }
170         return 0;
171     default:
172         errno = EINVAL;
173         return -1;
174     }
175 }
176 
177 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)178 crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES],
179                            const char *const passwd,
180                            unsigned long long passwdlen,
181                            unsigned long long opslimit, size_t memlimit)
182 {
183     unsigned char salt[crypto_pwhash_argon2id_SALTBYTES];
184 
185     memset(out, 0, crypto_pwhash_argon2id_STRBYTES);
186     if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX ||
187         opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX ||
188         memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX) {
189         errno = EFBIG;
190         return -1;
191     }
192     if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN ||
193         opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN ||
194         memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN) {
195         errno = EINVAL;
196         return -1;
197     }
198     randombytes_buf(salt, sizeof salt);
199     if (argon2id_hash_encoded((uint32_t) opslimit, (uint32_t) (memlimit / 1024U),
200                               (uint32_t) 1U, passwd, (size_t) passwdlen, salt,
201                               sizeof salt, STR_HASHBYTES, out,
202                               crypto_pwhash_argon2id_STRBYTES) != ARGON2_OK) {
203         return -1; /* LCOV_EXCL_LINE */
204     }
205     return 0;
206 }
207 
208 int
crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES],const char * const passwd,unsigned long long passwdlen)209 crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES],
210                                   const char *const  passwd,
211                                   unsigned long long passwdlen)
212 {
213     int verify_ret;
214 
215     if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX) {
216         errno = EFBIG;
217         return -1;
218     }
219     /* LCOV_EXCL_START */
220     if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN) {
221         errno = EINVAL;
222         return -1;
223     }
224     /* LCOV_EXCL_STOP */
225 
226     verify_ret = argon2id_verify(str, passwd, (size_t) passwdlen);
227     if (verify_ret == ARGON2_OK) {
228         return 0;
229     }
230     if (verify_ret == ARGON2_VERIFY_MISMATCH) {
231         errno = EINVAL;
232     }
233     return -1;
234 }
235