xref: /netbsd-src/external/apache2/argon2/dist/phc-winner-argon2/src/run.c (revision ae87de8892f277bece3527c15b186ebcfa188227)
1 /*
2  * Argon2 reference source code package - reference C implementations
3  *
4  * Copyright 2015
5  * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
6  *
7  * You may use this work under the terms of a Creative Commons CC0 1.0
8  * License/Waiver or the Apache Public License 2.0, at your option. The terms of
9  * these licenses can be found at:
10  *
11  * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
12  * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * You should have received a copy of both of these licenses along with this
15  * software. If not, they may be obtained at the above URLs.
16  */
17 
18 #define _GNU_SOURCE 1
19 
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 
26 #include "argon2.h"
27 #include "core.h"
28 
29 #define T_COST_DEF 3
30 #define LOG_M_COST_DEF 12 /* 2^12 = 4 MiB */
31 #define LANES_DEF 1
32 #define THREADS_DEF 1
33 #define OUTLEN_DEF 32
34 #define MAX_PASS_LEN 128
35 
36 #define UNUSED_PARAMETER(x) (void)(x)
37 
38 static void usage(const char *cmd) {
39     printf("Usage:  %s [-h] salt [-i|-d|-id] [-t iterations] "
40            "[-m log2(memory in KiB) | -k memory in KiB] [-p parallelism] "
41            "[-l hash length] [-e|-r] [-v (10|13)]\n",
42            cmd);
43     printf("\tPassword is read from stdin\n");
44     printf("Parameters:\n");
45     printf("\tsalt\t\tThe salt to use, at least 8 characters\n");
46     printf("\t-i\t\tUse Argon2i (this is the default)\n");
47     printf("\t-d\t\tUse Argon2d instead of Argon2i\n");
48     printf("\t-id\t\tUse Argon2id instead of Argon2i\n");
49     printf("\t-t N\t\tSets the number of iterations to N (default = %d)\n",
50            T_COST_DEF);
51     printf("\t-m N\t\tSets the memory usage of 2^N KiB (default %d)\n",
52            LOG_M_COST_DEF);
53     printf("\t-k N\t\tSets the memory usage of N KiB (default %d)\n",
54            1 << LOG_M_COST_DEF);
55     printf("\t-p N\t\tSets parallelism to N threads (default %d)\n",
56            THREADS_DEF);
57     printf("\t-l N\t\tSets hash output length to N bytes (default %d)\n",
58            OUTLEN_DEF);
59     printf("\t-e\t\tOutput only encoded hash\n");
60     printf("\t-r\t\tOutput only the raw bytes of the hash\n");
61     printf("\t-v (10|13)\tArgon2 version (defaults to the most recent version, currently %x)\n",
62             ARGON2_VERSION_NUMBER);
63     printf("\t-h\t\tPrint %s usage\n", cmd);
64 }
65 
66 static void fatal(const char *error) {
67     fprintf(stderr, "Error: %s\n", error);
68     exit(1);
69 }
70 
71 static void print_hex(uint8_t *bytes, size_t bytes_len) {
72     size_t i;
73     for (i = 0; i < bytes_len; ++i) {
74         printf("%02x", bytes[i]);
75     }
76     printf("\n");
77 }
78 
79 /*
80 Runs Argon2 with certain inputs and parameters, inputs not cleared. Prints the
81 Base64-encoded hash string
82 @out output array with at least 32 bytes allocated
83 @pwd NULL-terminated string, presumably from argv[]
84 @salt salt array
85 @t_cost number of iterations
86 @m_cost amount of requested memory in KB
87 @lanes amount of requested parallelism
88 @threads actual parallelism
89 @type Argon2 type we want to run
90 @encoded_only display only the encoded hash
91 @raw_only display only the hexadecimal of the hash
92 @version Argon2 version
93 */
94 static void run(uint32_t outlen, char *pwd, size_t pwdlen, char *salt, uint32_t t_cost,
95                 uint32_t m_cost, uint32_t lanes, uint32_t threads,
96                 argon2_type type, int encoded_only, int raw_only, uint32_t version) {
97     clock_t start_time, stop_time;
98     size_t saltlen, encodedlen;
99     int result;
100     unsigned char * out = NULL;
101     char * encoded = NULL;
102 
103     start_time = clock();
104 
105     if (!pwd) {
106         fatal("password missing");
107     }
108 
109     if (!salt) {
110         clear_internal_memory(pwd, pwdlen);
111         fatal("salt missing");
112     }
113 
114     saltlen = strlen(salt);
115     if(UINT32_MAX < saltlen) {
116         fatal("salt is too long");
117     }
118 
119     UNUSED_PARAMETER(lanes);
120 
121     out = malloc(outlen + 1);
122     if (!out) {
123         clear_internal_memory(pwd, pwdlen);
124         fatal("could not allocate memory for output");
125     }
126 
127     encodedlen = argon2_encodedlen(t_cost, m_cost, lanes, (uint32_t)saltlen, outlen, type);
128     encoded = malloc(encodedlen + 1);
129     if (!encoded) {
130         clear_internal_memory(pwd, pwdlen);
131         fatal("could not allocate memory for hash");
132     }
133 
134     result = argon2_hash(t_cost, m_cost, threads, pwd, pwdlen, salt, saltlen,
135                          out, outlen, encoded, encodedlen, type,
136                          version);
137     if (result != ARGON2_OK)
138         fatal(argon2_error_message(result));
139 
140     stop_time = clock();
141 
142     if (encoded_only)
143         puts(encoded);
144 
145     if (raw_only)
146         print_hex(out, outlen);
147 
148     if (encoded_only || raw_only) {
149         free(out);
150         free(encoded);
151         return;
152     }
153 
154     printf("Hash:\t\t");
155     print_hex(out, outlen);
156     free(out);
157 
158     printf("Encoded:\t%s\n", encoded);
159 
160     printf("%2.3f seconds\n",
161            ((double)stop_time - start_time) / (CLOCKS_PER_SEC));
162 
163     result = argon2_verify(encoded, pwd, pwdlen, type);
164     if (result != ARGON2_OK)
165         fatal(argon2_error_message(result));
166     printf("Verification ok\n");
167     free(encoded);
168 }
169 
170 int main(int argc, char *argv[]) {
171     uint32_t outlen = OUTLEN_DEF;
172     uint32_t m_cost = 1 << LOG_M_COST_DEF;
173     uint32_t t_cost = T_COST_DEF;
174     uint32_t lanes = LANES_DEF;
175     uint32_t threads = THREADS_DEF;
176     argon2_type type = Argon2_i; /* Argon2i is the default type */
177     int types_specified = 0;
178     int m_cost_specified = 0;
179     int encoded_only = 0;
180     int raw_only = 0;
181     uint32_t version = ARGON2_VERSION_NUMBER;
182     int i;
183     size_t pwdlen;
184     char pwd[MAX_PASS_LEN], *salt;
185 
186     if (argc < 2) {
187         usage(argv[0]);
188         return ARGON2_MISSING_ARGS;
189     } else if (argc >= 2 && strcmp(argv[1], "-h") == 0) {
190         usage(argv[0]);
191         return 1;
192     }
193 
194     /* get password from stdin */
195     pwdlen = fread(pwd, 1, sizeof pwd, stdin);
196     if(pwdlen < 1) {
197         fatal("no password read");
198     }
199     if(pwdlen == MAX_PASS_LEN) {
200         fatal("Provided password longer than supported in command line utility");
201     }
202 
203     salt = argv[1];
204 
205     /* parse options */
206     for (i = 2; i < argc; i++) {
207         const char *a = argv[i];
208         unsigned long input = 0;
209         if (!strcmp(a, "-h")) {
210             usage(argv[0]);
211             return 1;
212         } else if (!strcmp(a, "-m")) {
213             if (m_cost_specified) {
214                 fatal("-m or -k can only be used once");
215             }
216             m_cost_specified = 1;
217             if (i < argc - 1) {
218                 i++;
219                 input = strtoul(argv[i], NULL, 10);
220                 if (input == 0 || input == ULONG_MAX ||
221                     input > ARGON2_MAX_MEMORY_BITS) {
222                     fatal("bad numeric input for -m");
223                 }
224                 m_cost = ARGON2_MIN(UINT64_C(1) << input, UINT32_C(0xFFFFFFFF));
225                 if (m_cost > ARGON2_MAX_MEMORY) {
226                     fatal("m_cost overflow");
227                 }
228                 continue;
229             } else {
230                 fatal("missing -m argument");
231             }
232         } else if (!strcmp(a, "-k")) {
233             if (m_cost_specified) {
234                 fatal("-m or -k can only be used once");
235             }
236             m_cost_specified = 1;
237             if (i < argc - 1) {
238                 i++;
239                 input = strtoul(argv[i], NULL, 10);
240                 if (input == 0 || input == ULONG_MAX) {
241                     fatal("bad numeric input for -k");
242                 }
243                 m_cost = ARGON2_MIN(input, UINT32_C(0xFFFFFFFF));
244                 if (m_cost > ARGON2_MAX_MEMORY) {
245                     fatal("m_cost overflow");
246                 }
247                 continue;
248             } else {
249                 fatal("missing -k argument");
250             }
251         } else if (!strcmp(a, "-t")) {
252             if (i < argc - 1) {
253                 i++;
254                 input = strtoul(argv[i], NULL, 10);
255                 if (input == 0 || input == ULONG_MAX ||
256                     input > ARGON2_MAX_TIME) {
257                     fatal("bad numeric input for -t");
258                 }
259                 t_cost = input;
260                 continue;
261             } else {
262                 fatal("missing -t argument");
263             }
264         } else if (!strcmp(a, "-p")) {
265             if (i < argc - 1) {
266                 i++;
267                 input = strtoul(argv[i], NULL, 10);
268                 if (input == 0 || input == ULONG_MAX ||
269                     input > ARGON2_MAX_THREADS || input > ARGON2_MAX_LANES) {
270                     fatal("bad numeric input for -p");
271                 }
272                 threads = input;
273                 lanes = threads;
274                 continue;
275             } else {
276                 fatal("missing -p argument");
277             }
278         } else if (!strcmp(a, "-l")) {
279             if (i < argc - 1) {
280                 i++;
281                 input = strtoul(argv[i], NULL, 10);
282                 outlen = input;
283                 continue;
284             } else {
285                 fatal("missing -l argument");
286             }
287         } else if (!strcmp(a, "-i")) {
288             type = Argon2_i;
289             ++types_specified;
290         } else if (!strcmp(a, "-d")) {
291             type = Argon2_d;
292             ++types_specified;
293         } else if (!strcmp(a, "-id")) {
294             type = Argon2_id;
295             ++types_specified;
296         } else if (!strcmp(a, "-e")) {
297             encoded_only = 1;
298         } else if (!strcmp(a, "-r")) {
299             raw_only = 1;
300         } else if (!strcmp(a, "-v")) {
301             if (i < argc - 1) {
302                 i++;
303                 if (!strcmp(argv[i], "10")) {
304                     version = ARGON2_VERSION_10;
305                 } else if (!strcmp(argv[i], "13")) {
306                     version = ARGON2_VERSION_13;
307                 } else {
308                     fatal("invalid Argon2 version");
309                 }
310             } else {
311                 fatal("missing -v argument");
312             }
313         } else {
314             fatal("unknown argument");
315         }
316     }
317 
318     if (types_specified > 1) {
319         fatal("cannot specify multiple Argon2 types");
320     }
321 
322     if(encoded_only && raw_only)
323         fatal("cannot provide both -e and -r");
324 
325     if(!encoded_only && !raw_only) {
326         printf("Type:\t\t%s\n", argon2_type2string(type, 1));
327         printf("Iterations:\t%u\n", t_cost);
328         printf("Memory:\t\t%u KiB\n", m_cost);
329         printf("Parallelism:\t%u\n", lanes);
330     }
331 
332     run(outlen, pwd, pwdlen, salt, t_cost, m_cost, lanes, threads, type,
333        encoded_only, raw_only, version);
334 
335     return ARGON2_OK;
336 }
337 
338