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
17int
18crypto_pwhash_argon2id_alg_argon2id13(void)
19{
20    return crypto_pwhash_argon2id_ALG_ARGON2ID13;
21}
22
23size_t
24crypto_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
30size_t
31crypto_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
37size_t
38crypto_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
44size_t
45crypto_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
51size_t
52crypto_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
59size_t
60crypto_pwhash_argon2id_strbytes(void)
61{
62    return crypto_pwhash_argon2id_STRBYTES;
63}
64
65const char*
66crypto_pwhash_argon2id_strprefix(void)
67{
68    return crypto_pwhash_argon2id_STRPREFIX;
69}
70
71size_t
72crypto_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
78size_t
79crypto_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
85size_t
86crypto_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
92size_t
93crypto_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
99size_t
100crypto_pwhash_argon2id_opslimit_interactive(void)
101{
102    return crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE;
103}
104
105size_t
106crypto_pwhash_argon2id_memlimit_interactive(void)
107{
108    return crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE;
109}
110
111size_t
112crypto_pwhash_argon2id_opslimit_moderate(void)
113{
114    return crypto_pwhash_argon2id_OPSLIMIT_MODERATE;
115}
116
117size_t
118crypto_pwhash_argon2id_memlimit_moderate(void)
119{
120    return crypto_pwhash_argon2id_MEMLIMIT_MODERATE;
121}
122
123size_t
124crypto_pwhash_argon2id_opslimit_sensitive(void)
125{
126    return crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE;
127}
128
129size_t
130crypto_pwhash_argon2id_memlimit_sensitive(void)
131{
132    return crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE;
133}
134
135int
136crypto_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
177int
178crypto_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
208int
209crypto_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