Home | History | Annotate | Line # | Download | only in src
      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