2
0
Fork 0
mirror of https://git.sr.ht/~sircmpwn/mkproof synced 2024-06-03 11:36:12 +02:00
mkproof/src/main.c

394 lines
11 KiB
C
Raw Normal View History

2015-10-16 10:52:09 +02:00
/*
* Argon2 source code package
2015-10-16 19:05:50 +02:00
*
2015-10-16 10:52:09 +02:00
* Written by Daniel Dinu and Dmitry Khovratovich, 2015
2015-10-16 19:05:50 +02:00
*
2015-10-16 10:52:09 +02:00
* This work is licensed under a Creative Commons CC0 1.0 License/Waiver.
2015-10-16 19:05:50 +02:00
*
2015-10-20 22:46:17 +02:00
* You should have received a copy of the CC0 Public Domain Dedication along
* with
* this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
2015-10-16 10:52:09 +02:00
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
2015-10-19 10:07:13 +02:00
#include <time.h>
2015-10-16 10:52:09 +02:00
#include "argon2.h"
2015-10-19 10:07:13 +02:00
#include "encoding.h"
2015-10-16 10:52:09 +02:00
#ifdef _MSC_VER
2015-10-19 10:17:11 +02:00
#include <intrin.h>
2015-10-16 19:05:50 +02:00
#endif
2015-10-21 13:00:22 +02:00
2015-10-16 10:52:09 +02:00
2015-10-16 16:07:06 +02:00
#define T_COST_DEF 3
2015-10-20 22:46:17 +02:00
#define LOG_M_COST_DEF 12 /*4 MB*/
2015-10-16 16:07:06 +02:00
#define LANES_DEF 4
#define THREADS_DEF 4
2015-10-21 10:08:17 +02:00
#define SALTLEN_DEF 16
2015-10-16 16:07:06 +02:00
2015-10-16 18:41:54 +02:00
#define UNUSED_PARAMETER(x) (void)(x)
2015-10-16 16:07:06 +02:00
2015-10-20 22:46:17 +02:00
static __inline uint64_t rdtsc(void) {
2015-10-16 10:52:09 +02:00
#ifdef _MSC_VER
return __rdtsc();
2015-10-16 10:52:09 +02:00
#else
2015-10-20 22:46:17 +02:00
#if defined(__amd64__) || defined(__x86_64__)
uint64_t rax, rdx;
__asm__ __volatile__("rdtsc" : "=a"(rax), "=d"(rdx) : :);
return (rdx << 32) | rax;
2015-10-20 22:46:17 +02:00
#elif defined(__i386__) || defined(__i386) || defined(__X86__)
uint64_t rax;
__asm__ __volatile__("rdtsc" : "=A"(rax) : :);
return rax;
2015-10-20 22:46:17 +02:00
#else
#error "Not implemented!"
#endif
2015-10-16 10:52:09 +02:00
#endif
}
/*
* Custom allocate memory
*/
2015-10-20 22:46:17 +02:00
int CustomAllocateMemory(uint8_t **memory, size_t length) {
*memory = (uint8_t *)malloc(length);
2015-10-16 19:05:50 +02:00
if (!*memory) {
return ARGON2_MEMORY_ALLOCATION_ERROR;
}
2015-10-16 19:05:50 +02:00
return ARGON2_OK;
2015-10-16 10:52:09 +02:00
}
/*
* Custom free memory
*/
2015-10-20 22:46:17 +02:00
void CustomFreeMemory(uint8_t *memory, size_t length) {
UNUSED_PARAMETER(length);
2015-10-16 19:05:50 +02:00
if (memory) {
free(memory);
}
2015-10-16 10:52:09 +02:00
}
2015-10-20 22:46:17 +02:00
void usage(const char *cmd) {
printf("Usage: %s pwd salt [-y version] [-t t_cost] [-m m_cost] [-l "
2015-10-21 10:08:17 +02:00
"#lanes] [-p #threads]\n",
cmd);
printf("Options:\n");
2015-10-21 10:08:17 +02:00
printf("\tpwd\t\tThe password to hash (required)\n");
printf("\tsalt\t\tThe salt to use, at most 16 characters (required)\n");
printf("\t-y version\tArgon2 version, either d or i (default)\n");
printf("\t-t t_cost\tNumber of rounds to t_cost between 1 and 2^24, "
"default %d\n",
T_COST_DEF);
printf("\t-m m_cost\tMemory usage of 2^t_cost kibibytes, default %d]\n",
LOG_M_COST_DEF);
printf("\t-p N\t\tParallelism, default %d\n", THREADS_DEF);
2015-10-16 20:13:31 +02:00
}
2015-10-20 22:46:17 +02:00
void fatal(const char *error) {
fprintf(stderr, "Error: %s\n", error);
exit(1);
2015-10-16 20:13:31 +02:00
}
2015-10-20 22:46:17 +02:00
void print_bytes(const void *s, size_t len) {
for (size_t i = 0; i < len; i++) {
printf("%02x", ((const unsigned char *)s)[i] & 0xff);
}
2015-10-17 13:27:39 +02:00
printf("\n");
2015-10-16 20:13:31 +02:00
}
2015-10-16 10:52:09 +02:00
/*
2015-10-17 13:51:35 +02:00
* Benchmarks Argon2 with salt length 16, password length 16, t_cost 1,
2015-10-18 08:25:32 +02:00
and different m_cost and threads
2015-10-16 10:52:09 +02:00
*/
2015-10-20 22:46:17 +02:00
void benchmark() {
#define BENCH_OUTLEN 16
#define BENCH_INLEN 16
const uint32_t inlen = BENCH_INLEN;
const unsigned outlen = BENCH_OUTLEN;
unsigned char out[BENCH_OUTLEN];
unsigned char pwd_array[BENCH_INLEN];
unsigned char salt_array[BENCH_INLEN];
#undef BENCH_INLEN
#undef BENCH_OUTLEN
2015-10-16 10:52:09 +02:00
uint32_t t_cost = 1;
memset(pwd_array, 0, inlen);
memset(salt_array, 1, inlen);
uint32_t thread_test[6] = {1, 2, 4, 6, 8, 16};
uint32_t m_cost;
for (m_cost = (uint32_t)1 << 10; m_cost <= (uint32_t)1 << 22; m_cost *= 2) {
for (uint32_t i = 0; i < 6; ++i) {
uint32_t thread_n = thread_test[i];
uint64_t start_cycles, stop_cycles, stop_cycles_i;
clock_t start_time = clock();
start_cycles = rdtsc();
Argon2_Context context = {
out, outlen, pwd_array, inlen, salt_array, inlen, NULL,
0, NULL, 0, t_cost, m_cost, thread_n, thread_n,
NULL, NULL, false, false, false, false};
argon2d(&context);
stop_cycles = rdtsc();
argon2i(&context);
stop_cycles_i = rdtsc();
clock_t stop_time = clock();
uint64_t delta_d = (stop_cycles - start_cycles) / (m_cost);
uint64_t delta_i = (stop_cycles_i - stop_cycles) / (m_cost);
float mcycles_d = (float)(stop_cycles - start_cycles) / (1 << 20);
float mcycles_i = (float)(stop_cycles_i - stop_cycles) / (1 << 20);
printf(
"Argon2d %d pass(es) %d Mbytes %d threads: %2.2f cpb %2.2f "
"Mcycles \n",
t_cost, m_cost >> 10, thread_n, (float)delta_d / 1024,
mcycles_d);
printf(
"Argon2i %d pass(es) %d Mbytes %d threads: %2.2f cpb %2.2f "
"Mcycles \n",
t_cost, m_cost >> 10, thread_n, (float)delta_i / 1024,
mcycles_i);
float run_time = ((float)stop_time - start_time) / (CLOCKS_PER_SEC);
printf("%2.4f seconds\n\n", run_time);
}
2015-10-16 10:52:09 +02:00
}
}
2015-10-21 12:54:59 +02:00
/*
Runs Argon2 with certain inputs and parameters, inputs not cleared. Prints the Base64-encoded hash string
@out output array with at least 32 bytes allocated
@pwd NULL-terminated string, presumably from argv[]
@salt salt array with at least SALTLEN_DEF bytes allocated
@t_cost number of iterations
@m_cost amount of requested memory in KB
@lanes amount of requested parallelism
@threads actual parallelism
@type String, only "d" and "i" are accepted
*/
2015-10-21 10:08:17 +02:00
void run(uint8_t *out, char *pwd, uint8_t *salt, uint32_t t_cost,
uint32_t m_cost, uint32_t lanes, uint32_t threads, const char *type) {
uint64_t start_cycles, stop_cycles;
2015-10-16 10:52:09 +02:00
clock_t start_time = clock();
start_cycles = rdtsc();
2015-10-16 10:52:09 +02:00
/*Fixed parameters*/
const unsigned out_length = 32;
2015-10-21 10:08:17 +02:00
const unsigned salt_length = SALTLEN_DEF;
bool clear_memory = false;
bool clear_secret = false;
2015-10-23 18:08:48 +02:00
bool clear_password = true;
uint8_t *in = NULL;
2015-10-21 10:08:17 +02:00
if (!pwd)
fatal("password missing");
2015-10-23 18:08:48 +02:00
if (!salt)
{
secure_wipe_memory(pwd, strlen(pwd));
fatal("salt missing");
}
2015-10-21 10:08:17 +02:00
in = malloc(strlen(pwd) + 1);
if(!in)
{
2015-10-23 18:08:48 +02:00
secure_wipe_memory(pwd, strlen(pwd));
fatal("Memory allocation error in the initialization phase");
}
2015-10-21 10:08:17 +02:00
strcpy((char *)in, pwd);
2015-10-23 18:08:48 +02:00
secure_wipe_memory(pwd, strlen(pwd));
const unsigned in_length = strlen((char *)in);
UNUSED_PARAMETER(threads);
Argon2_Context context = {
out, out_length, in, in_length, salt, salt_length,
NULL, 0, NULL, 0, t_cost, m_cost,
lanes, lanes, NULL, NULL, clear_password, clear_secret,
2015-10-21 10:08:17 +02:00
clear_memory, false};
if (!strcmp(type, "d"))
argon2d(&context);
else if (!strcmp(type, "i"))
argon2i(&context);
else
{
free(in);
fatal("wrong Argon2 type");
}
stop_cycles = rdtsc();
clock_t finish_time = clock();
// show string encoding
char string[300];
encode_string(string, sizeof string, &context);
printf("%s\n", string);
2015-10-21 11:52:43 +02:00
float run_time = ((float)finish_time - start_time) / (CLOCKS_PER_SEC);
float mcycles = (float)(stop_cycles - start_cycles) / (1 << 20);
printf("%2.3f seconds ", run_time);
printf("(%.3f mebicycles)\n", mcycles);
free(in);
2015-10-16 10:52:09 +02:00
}
2015-10-20 22:46:17 +02:00
void generate_testvectors(const char *type) {
#define TEST_OUTLEN 32
#define TEST_PWDLEN 32
#define TEST_SALTLEN 16
#define TEST_SECRETLEN 8
#define TEST_ADLEN 12
bool clear_memory = false;
bool clear_secret = false;
bool clear_password = false;
bool print_internals = true;
unsigned char out[TEST_OUTLEN];
unsigned char pwd[TEST_PWDLEN];
unsigned char salt[TEST_SALTLEN];
unsigned char secret[TEST_SECRETLEN];
unsigned char ad[TEST_ADLEN];
const AllocateMemoryCallback myown_allocator = NULL;
const FreeMemoryCallback myown_deallocator = NULL;
unsigned t_cost = 3;
unsigned m_cost = 16;
unsigned lanes = 4;
memset(pwd, 1, TEST_OUTLEN);
memset(salt, 2, TEST_SALTLEN);
memset(secret, 3, TEST_SECRETLEN);
memset(ad, 4, TEST_ADLEN);
printf("Generating test vectors for Argon2%s in file \"%s\".\n", type,
ARGON2_KAT_FILENAME);
Argon2_Context context = {out,
TEST_OUTLEN,
pwd,
TEST_PWDLEN,
salt,
TEST_SALTLEN,
secret,
TEST_SECRETLEN,
ad,
TEST_ADLEN,
t_cost,
m_cost,
lanes,
lanes,
myown_allocator,
myown_deallocator,
clear_password,
clear_secret,
clear_memory,
print_internals};
2015-10-20 22:46:17 +02:00
#undef TEST_OUTLEN
#undef TEST_PWDLEN
#undef TEST_SALTLEN
#undef TEST_SECRETLEN
#undef TEST_ADLEN
2015-10-21 12:44:41 +02:00
if (!strcmp(type, "d")){
2015-10-21 12:43:10 +02:00
printf("Generating test vectors for Argon2d in file \"%s\".\n", ARGON2_KAT_FILENAME);
argon2d(&context);
2015-10-21 12:43:10 +02:00
}
else if (!strcmp(type, "i"))
2015-10-21 12:43:10 +02:00
{
2015-10-21 12:44:41 +02:00
printf("Generating test vectors for Argon2i in file \"%s\".\n", ARGON2_KAT_FILENAME);
argon2i(&context);
2015-10-21 12:44:41 +02:00
}
else
fatal("wrong Argon2 type");
2015-10-16 16:07:06 +02:00
}
2015-10-20 22:46:17 +02:00
int main(int argc, char *argv[]) {
unsigned char out[32];
uint32_t m_cost = 1 << LOG_M_COST_DEF;
uint32_t t_cost = T_COST_DEF;
uint32_t lanes = LANES_DEF;
uint32_t threads = THREADS_DEF;
char *pwd = NULL;
2015-10-21 10:08:17 +02:00
uint8_t salt[SALTLEN_DEF];
const char *type = "i";
remove(ARGON2_KAT_FILENAME);
#ifdef BENCH
benchmark();
2015-10-21 11:59:39 +02:00
return ARGON2_OK;
#endif
#ifdef GENKAT
2015-10-21 12:14:51 +02:00
if(argc>1)
{
type[0] = argv[1][0];
}
2015-10-20 22:46:17 +02:00
generate_testvectors(type);
2015-10-21 11:59:39 +02:00
return ARGON2_OK;
#endif
2015-10-16 19:05:50 +02:00
2015-10-21 10:08:17 +02:00
if (argc < 3) {
usage(argv[0]);
2015-10-21 11:59:39 +02:00
return ARGON2_MISSING_ARGS;
}
2015-10-16 10:52:09 +02:00
2015-10-21 10:08:17 +02:00
// get password and salt from command line
pwd = argv[1];
if (strlen(argv[2]) > SALTLEN_DEF)
fatal("salt too long");
memset(salt, 0x00, SALTLEN_DEF); // padding
memcpy(salt, (uint8_t *)argv[2], strlen(argv[2]));
2015-10-21 10:08:17 +02:00
for (int i = 3; i < argc; i++) {
char *a = argv[i];
if (!strcmp(a, "-m")) {
if (i < argc - 1) {
i++;
m_cost = (uint8_t)1 << ((uint8_t)atoi(argv[i]) % 22);
continue;
} else
fatal("missing -m argument");
} else if (!strcmp(a, "-t")) {
if (i < argc - 1) {
i++;
t_cost = atoi(argv[i]) & 0xffffff;
continue;
} else
fatal("missing -t argument");
} else if (!strcmp(a, "-p")) {
if (i < argc - 1) {
i++;
threads = atoi(argv[i]) % ARGON2_MAX_THREADS;
lanes = threads;
continue;
} else
fatal("missing -p argument");
} else if (!strcmp(a, "-y")) {
if (i < argc - 1) {
i++;
type = argv[i];
continue;
} else
fatal("missing type argument");
} else
fatal("unknown argument");
}
2015-10-21 10:08:17 +02:00
run(out, pwd, salt, t_cost, m_cost, lanes, threads, type);
2015-10-21 11:59:39 +02:00
return ARGON2_OK;
2015-10-16 10:52:09 +02:00
}