crypt-argon2.c revision 1.10 1 /*
2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <time.h>
33 #include <pwd.h>
34 #include <errno.h>
35 #include <argon2.h>
36
37 #include <err.h>
38 #include "crypt.h"
39
40 /* defaults pulled from run.c */
41 #define HASHLEN 32
42 #define T_COST_DEF 3
43 #define LOG_M_COST_DEF 12 /* 2^12 = 4 MiB */
44 #define LANES_DEF 1
45 #define THREADS_DEF 1
46 #define OUTLEN_DEF 32
47 #define MAX_PASS_LEN 128
48
49 #define ARGON2_CONTEXT_INITIALIZER \
50 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
51 T_COST_DEF, LOG_M_COST_DEF,\
52 LANES_DEF, THREADS_DEF, \
53 ARGON2_VERSION_NUMBER, 0, 0, ARGON2_DEFAULT_FLAGS}
54
55 #define ARGON2_ARGON2_STR "argon2"
56 #define ARGON2_ARGON2I_STR "argon2i"
57 #define ARGON2_ARGON2D_STR "argon2d"
58 #define ARGON2_ARGON2ID_STR "argon2id"
59
60
61 /*
62 * Some macros for constant-time comparisons. These work over values in
63 * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".
64 */
65 #define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF)
66 #define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF)
67 #define GE(x, y) (GT(y, x) ^ 0xFF)
68 #define LT(x, y) GT(y, x)
69 #define LE(x, y) GE(y, x)
70
71 static unsigned
72 b64_char_to_byte(int c)
73 {
74 unsigned x;
75
76 x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) |
77 (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) |
78 (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) |
79 (EQ(c, '/') & 63);
80 return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));
81 }
82
83 static const char *
84 from_base64(void *dst, size_t *dst_len, const char *src)
85 {
86 size_t len;
87 unsigned char *buf;
88 unsigned acc, acc_len;
89
90 buf = (unsigned char *)dst;
91 len = 0;
92 acc = 0;
93 acc_len = 0;
94 for (;;) {
95 unsigned d;
96
97 d = b64_char_to_byte(*src);
98 if (d == 0xFF) {
99 break;
100 }
101 src++;
102 acc = (acc << 6) + d;
103 acc_len += 6;
104 if (acc_len >= 8) {
105 acc_len -= 8;
106 if ((len++) >= *dst_len) {
107 return NULL;
108 }
109 *buf++ = (acc >> acc_len) & 0xFF;
110 }
111 }
112
113 /*
114 * If the input length is equal to 1 modulo 4 (which is
115 * invalid), then there will remain 6 unprocessed bits;
116 * otherwise, only 0, 2 or 4 bits are buffered. The buffered
117 * bits must also all be zero.
118 */
119 if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) {
120 return NULL;
121 }
122 *dst_len = len;
123 return src;
124 }
125
126 /* process params to argon2 */
127 /* we don't force param order as input, */
128 /* but we do provide the expected order to argon2 api */
129 static int
130 decode_option(argon2_context *ctx, argon2_type *atype, const char *option)
131 {
132 size_t tmp = 0;
133 char *in = 0, *inp;
134 char *a = 0;
135 char *p = 0;
136 size_t sl;
137 int error = 0;
138
139 in = (char *)strdup(option);
140 inp = in;
141
142 if (*inp == '$') inp++;
143
144 a = strsep(&inp, "$");
145
146 sl = strlen(a);
147
148 if (sl == strlen(ARGON2_ARGON2I_STR) &&
149 !(strcmp(ARGON2_ARGON2I_STR, a))) {
150 *atype=Argon2_i;
151 } else if (sl == strlen(ARGON2_ARGON2D_STR) &&
152 !(strcmp(ARGON2_ARGON2D_STR, a))) {
153 *atype=Argon2_d;
154 }
155 else if (sl == strlen(ARGON2_ARGON2ID_STR) &&
156 !(strcmp(ARGON2_ARGON2ID_STR, a))) {
157 *atype=Argon2_id;
158 } else { /* default to id, we assume simple mistake */
159 /* don't abandon yet */
160 *atype=Argon2_id;
161 }
162
163 a = strsep(&inp, "$");
164
165 /* parse the version number of the hash, if it's there */
166 if (strncmp(a, "v=", 2) == 0) {
167 a += 2;
168 if ((getnum(a, &tmp))<0) { /* on error, default to current */
169 /* should start thinking about aborting */
170 ctx->version = ARGON2_VERSION_10;
171 } else {
172 ctx->version = tmp;
173 }
174 a = strsep(&inp, "$");
175 } else {
176 /*
177 * This is a parameter list, not a version number, use the
178 * default version.
179 */
180 ctx->version = ARGON2_VERSION_10;
181 }
182
183 /* parse labelled argon2 params */
184 /* m_cost (m)
185 * t_cost (t)
186 * threads (p)
187 */
188 while ((p = strsep(&a, ","))) {
189 switch (*p) {
190 case 'm':
191 p += strlen("m=");
192 if ((getnum(p, &tmp)) < 0) {
193 --error;
194 } else {
195 ctx->m_cost = tmp;
196 }
197 break;
198 case 't':
199 p += strlen("t=");
200 if ((getnum(p, &tmp)) < 0) {
201 --error;
202 } else {
203 ctx->t_cost = tmp;
204 }
205 break;
206 case 'p':
207 p += strlen("p=");
208 if ((getnum(p, &tmp)) < 0) {
209 --error;
210 } else {
211 ctx->threads = tmp;
212 }
213 break;
214 default:
215 return -1;
216
217 }
218 }
219
220 a = strsep(&inp, "$");
221
222 sl = ctx->saltlen;
223
224 if (from_base64(ctx->salt, &sl, a) == NULL)
225 return -1;
226
227 ctx->saltlen = sl;
228
229 a = strsep(&inp, "$");
230
231 if (a) {
232 snprintf((char *)ctx->pwd, ctx->pwdlen, "%s", a);
233 } else {
234 /* don't care if passwd hash is missing */
235 /* if missing, most likely coming from */
236 /* pwhash or similar */
237 }
238
239 /* free our token buffer */
240 free(in);
241
242 /* 0 on success, <0 otherwise */
243 return error;
244 }
245
246 crypt_private char *
247 __crypt_argon2(const char *pw, const char * salt)
248 {
249 /* we use the libargon2 api to generate */
250 /* return code */
251 int rc = 0;
252 /* output buffer */
253 char ebuf[32];
254 /* argon2 variable, default to id */
255 argon2_type atype = Argon2_id;
256 /* default to current argon2 version */
257 /* argon2 context to collect params */
258 argon2_context ctx = ARGON2_CONTEXT_INITIALIZER;
259 /* argon2 encoded buffer */
260 char encodebuf[256];
261 /* argon2 salt buffer */
262 char saltbuf[128];
263 /* argon2 pwd buffer */
264 char pwdbuf[128];
265 /* returned static buffer */
266 static char rbuf[512];
267
268 /* clear buffers */
269 explicit_memset(rbuf, 0, sizeof(rbuf));
270
271 /* we use static buffers to avoid allocation */
272 /* and easier cleanup */
273 ctx.out = (uint8_t *)ebuf;
274 ctx.outlen = sizeof(ebuf);
275
276 ctx.out = (uint8_t *)encodebuf;
277 ctx.outlen = sizeof(encodebuf);
278
279 ctx.salt = (uint8_t *)saltbuf;
280 ctx.saltlen = sizeof(saltbuf);
281
282 ctx.pwd = (uint8_t *)pwdbuf;
283 ctx.pwdlen = sizeof(pwdbuf);
284
285 /* decode salt string to argon2 params */
286 /* argon2 context for param collection */
287 rc = decode_option(&ctx, &atype, salt);
288
289 if (rc < 0) {
290 /* unable to parse input params */
291 return 0;
292 }
293
294 rc = argon2_hash(ctx.t_cost, ctx.m_cost,
295 ctx.threads, pw, strlen(pw), ctx.salt, ctx.saltlen,
296 ebuf, sizeof(ebuf), encodebuf, sizeof(encodebuf),
297 atype, ctx.version);
298
299 if (rc != ARGON2_OK) {
300 fprintf(stderr, "argon2: failed: %s\n",
301 argon2_error_message(rc));
302 return 0;
303 }
304
305 memcpy(rbuf, encodebuf, sizeof(encodebuf));
306
307 /* clear buffers */
308 explicit_memset(ebuf, 0, sizeof(ebuf));
309 explicit_memset(encodebuf, 0, sizeof(encodebuf));
310 explicit_memset(saltbuf, 0, sizeof(saltbuf));
311 explicit_memset(pwdbuf, 0, sizeof(pwdbuf));
312
313 /* return encoded str */
314 return rbuf;
315 }
316