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