crypt-argon2.c revision 1.6 1 1.1 jhigh #include <stdlib.h>
2 1.1 jhigh #include <stdio.h>
3 1.1 jhigh #include <unistd.h>
4 1.1 jhigh #include <stdio.h>
5 1.1 jhigh #include <string.h>
6 1.1 jhigh #include <time.h>
7 1.1 jhigh #include <pwd.h>
8 1.1 jhigh #include <errno.h>
9 1.1 jhigh #include <argon2.h>
10 1.6 nia #include <resolv.h> /* for b64_pton... */
11 1.1 jhigh
12 1.1 jhigh #include <err.h>
13 1.1 jhigh #include "crypt.h"
14 1.1 jhigh
15 1.1 jhigh /* defaults pulled from run.c */
16 1.1 jhigh #define HASHLEN 32
17 1.1 jhigh #define T_COST_DEF 3
18 1.1 jhigh #define LOG_M_COST_DEF 12 /* 2^12 = 4 MiB */
19 1.1 jhigh #define LANES_DEF 1
20 1.1 jhigh #define THREADS_DEF 1
21 1.1 jhigh #define OUTLEN_DEF 32
22 1.1 jhigh #define MAX_PASS_LEN 128
23 1.1 jhigh
24 1.1 jhigh #define ARGON2_CONTEXT_INITIALIZER \
25 1.1 jhigh {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
26 1.1 jhigh T_COST_DEF, LOG_M_COST_DEF,\
27 1.1 jhigh LANES_DEF, THREADS_DEF, \
28 1.1 jhigh ARGON2_VERSION_NUMBER, 0, 0, ARGON2_DEFAULT_FLAGS}
29 1.1 jhigh
30 1.1 jhigh #define ARGON2_ARGON2_STR "argon2"
31 1.1 jhigh #define ARGON2_ARGON2I_STR "argon2i"
32 1.1 jhigh #define ARGON2_ARGON2D_STR "argon2d"
33 1.1 jhigh #define ARGON2_ARGON2ID_STR "argon2id"
34 1.1 jhigh
35 1.1 jhigh /* process params to argon2 */
36 1.1 jhigh /* we don't force param order as input, */
37 1.1 jhigh /* but we do provide the expected order to argon2 api */
38 1.1 jhigh static int decode_option(argon2_context * ctx, argon2_type * atype, const char * option)
39 1.1 jhigh {
40 1.1 jhigh size_t tmp=0;
41 1.2 msaitoh char * in = 0,*inp;
42 1.1 jhigh char * a=0;
43 1.1 jhigh char * p=0;
44 1.1 jhigh size_t sl;
45 1.1 jhigh int error=0;
46 1.1 jhigh
47 1.1 jhigh in = (char *)strdup(option);
48 1.1 jhigh inp = in;
49 1.1 jhigh
50 1.1 jhigh if (*inp == '$') inp++;
51 1.1 jhigh
52 1.1 jhigh a = strsep(&inp, "$");
53 1.1 jhigh
54 1.1 jhigh sl = strlen(a);
55 1.1 jhigh
56 1.1 jhigh if (sl == strlen(ARGON2_ARGON2I_STR) &&
57 1.1 jhigh !(strcmp(ARGON2_ARGON2I_STR, a))) {
58 1.1 jhigh *atype=Argon2_i;
59 1.1 jhigh } else if (sl == strlen(ARGON2_ARGON2D_STR) &&
60 1.1 jhigh !(strcmp(ARGON2_ARGON2D_STR, a))) {
61 1.1 jhigh *atype=Argon2_d;
62 1.1 jhigh }
63 1.1 jhigh else if (sl == strlen(ARGON2_ARGON2ID_STR) &&
64 1.1 jhigh !(strcmp(ARGON2_ARGON2ID_STR, a))) {
65 1.1 jhigh *atype=Argon2_id;
66 1.1 jhigh } else { /* default to id, we assume simple mistake */
67 1.1 jhigh /* don't abandon yet */
68 1.1 jhigh *atype=Argon2_id;
69 1.1 jhigh }
70 1.1 jhigh
71 1.1 jhigh a = strsep(&inp, "$");
72 1.1 jhigh
73 1.3 nia /* parse the version number of the hash, if it's there */
74 1.3 nia if (strncmp(a, "v=", 2) == 0) {
75 1.3 nia a += 2;
76 1.3 nia if ((getnum(a, &tmp))<0) { /* on error, default to current */
77 1.3 nia /* should start thinking about aborting */
78 1.4 nia ctx->version = ARGON2_VERSION_10;
79 1.3 nia } else {
80 1.3 nia ctx->version = tmp;
81 1.3 nia }
82 1.3 nia a = strsep(&inp, "$");
83 1.3 nia } else {
84 1.3 nia /*
85 1.3 nia * This is a parameter list, not a version number, use the
86 1.3 nia * default version.
87 1.3 nia */
88 1.4 nia ctx->version = ARGON2_VERSION_10;
89 1.1 jhigh }
90 1.1 jhigh
91 1.1 jhigh /* parse labelled argon2 params */
92 1.1 jhigh /* m_cost (m)
93 1.1 jhigh * t_cost (t)
94 1.1 jhigh * threads (p)
95 1.1 jhigh */
96 1.1 jhigh while ((p = strsep(&a, ","))) {
97 1.1 jhigh switch (*p) {
98 1.1 jhigh case 'm':
99 1.1 jhigh p += strlen("m=");
100 1.1 jhigh if ((getnum(p, &tmp)) < 0) {
101 1.1 jhigh --error;
102 1.1 jhigh } else {
103 1.1 jhigh ctx->m_cost = tmp;
104 1.1 jhigh }
105 1.1 jhigh break;
106 1.1 jhigh case 't':
107 1.1 jhigh p += strlen("t=");
108 1.1 jhigh if ((getnum(p, &tmp)) < 0) {
109 1.1 jhigh --error;
110 1.1 jhigh } else {
111 1.1 jhigh ctx->t_cost = tmp;
112 1.1 jhigh }
113 1.1 jhigh break;
114 1.1 jhigh case 'p':
115 1.1 jhigh p += strlen("p=");
116 1.1 jhigh if ((getnum(p, &tmp)) < 0) {
117 1.1 jhigh --error;
118 1.1 jhigh } else {
119 1.1 jhigh ctx->threads = tmp;
120 1.1 jhigh }
121 1.1 jhigh break;
122 1.1 jhigh default:
123 1.1 jhigh return -1;
124 1.1 jhigh
125 1.1 jhigh }
126 1.1 jhigh }
127 1.1 jhigh
128 1.1 jhigh a = strsep(&inp, "$");
129 1.1 jhigh
130 1.6 nia b64_pton(a, ctx->salt, ctx->saltlen);
131 1.1 jhigh
132 1.1 jhigh a = strsep(&inp, "$");
133 1.1 jhigh
134 1.3 nia if (a) {
135 1.3 nia snprintf((char *)ctx->pwd, ctx->pwdlen, "%s", a);
136 1.1 jhigh } else {
137 1.1 jhigh /* don't care if passwd hash is missing */
138 1.1 jhigh /* if missing, most likely coming from */
139 1.1 jhigh /* pwhash or similar */
140 1.1 jhigh }
141 1.1 jhigh
142 1.1 jhigh /* free our token buffer */
143 1.1 jhigh free(in);
144 1.1 jhigh
145 1.1 jhigh /* 0 on success, <0 otherwise */
146 1.1 jhigh return error;
147 1.1 jhigh }
148 1.1 jhigh
149 1.1 jhigh char *
150 1.1 jhigh __crypt_argon2(const char *pw, const char * salt)
151 1.1 jhigh {
152 1.1 jhigh /* we use the libargon2 api to generate */
153 1.1 jhigh /* return code */
154 1.1 jhigh int rc=0;
155 1.1 jhigh /* output buffer */
156 1.1 jhigh char ebuf[32];
157 1.1 jhigh /* ptr into argon2 encoded buffer */
158 1.1 jhigh char * blkp=0;
159 1.1 jhigh /* argon2 variable, default to id */
160 1.1 jhigh argon2_type atype = Argon2_id;
161 1.1 jhigh /* default to current argon2 version */
162 1.1 jhigh /* argon2 context to collect params */
163 1.1 jhigh argon2_context ctx = ARGON2_CONTEXT_INITIALIZER;
164 1.1 jhigh /* argon2 encoded buffer */
165 1.1 jhigh char encodebuf[256];
166 1.1 jhigh /* argon2 salt buffer */
167 1.1 jhigh char saltbuf[128];
168 1.1 jhigh /* argon2 pwd buffer */
169 1.1 jhigh char pwdbuf[128];
170 1.1 jhigh /* returned static buffer */
171 1.1 jhigh static char rbuf[512];
172 1.1 jhigh
173 1.1 jhigh /* clear buffers */
174 1.6 nia explicit_memset(rbuf, 0, sizeof(rbuf));
175 1.1 jhigh
176 1.1 jhigh /* we use static buffers to avoid allocation */
177 1.1 jhigh /* and easier cleanup */
178 1.1 jhigh ctx.out = (uint8_t *)ebuf;
179 1.1 jhigh ctx.outlen = sizeof(ebuf);
180 1.1 jhigh
181 1.1 jhigh ctx.out = (uint8_t *)encodebuf;
182 1.1 jhigh ctx.outlen = sizeof(encodebuf);
183 1.1 jhigh
184 1.1 jhigh ctx.salt = (uint8_t *)saltbuf;
185 1.1 jhigh ctx.saltlen = sizeof(saltbuf);
186 1.1 jhigh
187 1.1 jhigh ctx.pwd= (uint8_t *)pwdbuf;
188 1.1 jhigh ctx.pwdlen = sizeof(pwdbuf);
189 1.1 jhigh
190 1.1 jhigh /* decode salt string to argon2 params */
191 1.1 jhigh /* argon2 context for param collection */
192 1.1 jhigh rc = decode_option(&ctx, &atype, salt);
193 1.1 jhigh
194 1.1 jhigh if (rc < 0) {
195 1.3 nia /* unable to parse input params */
196 1.1 jhigh return 0;
197 1.1 jhigh }
198 1.1 jhigh
199 1.1 jhigh rc = argon2_hash(ctx.t_cost, ctx.m_cost,
200 1.1 jhigh ctx.threads, pw, strlen(pw), ctx.salt, strlen((char*)ctx.salt),
201 1.1 jhigh ebuf, sizeof(ebuf), encodebuf, sizeof(encodebuf), atype, ctx.version);
202 1.1 jhigh
203 1.1 jhigh if (rc != ARGON2_OK) {
204 1.3 nia fprintf(stderr, "argon2: failed: %s\n",
205 1.3 nia argon2_error_message(rc));
206 1.1 jhigh return 0;
207 1.1 jhigh }
208 1.1 jhigh
209 1.1 jhigh /* get encoded passwd */
210 1.1 jhigh if ((blkp = strrchr(encodebuf, '$')) == NULL) {
211 1.1 jhigh return 0;
212 1.1 jhigh }
213 1.1 jhigh
214 1.1 jhigh /* skip over '$' */
215 1.1 jhigh blkp++;
216 1.1 jhigh
217 1.6 nia memcpy(rbuf, encodebuf, sizeof(encodebuf));
218 1.1 jhigh
219 1.1 jhigh /* clear buffers */
220 1.6 nia explicit_memset(ebuf, 0, sizeof(ebuf));
221 1.5 nia explicit_memset(encodebuf, 0, sizeof(encodebuf));
222 1.5 nia explicit_memset(saltbuf, 0, sizeof(saltbuf));
223 1.5 nia explicit_memset(pwdbuf, 0, sizeof(pwdbuf));
224 1.1 jhigh
225 1.1 jhigh /* return encoded str */
226 1.1 jhigh return rbuf;
227 1.1 jhigh }
228