/* See LICENSE file for copyright and license details. */ #include "common.h" #ifndef MEASURE_TIME # define MEASURE_TIME 0 #endif #ifndef MEASURE_TIME_ONLY # define MEASURE_TIME_ONLY MEASURE_TIME #endif #include #if MEASURE_TIME # include # include #endif #define MEM(S) S, sizeof(S) - 1 #define assert(TRUTH) assert_(TRUTH, #TRUTH, __LINE__) #define assert_streq(RESULT, EXPECT) assert_streq_(RESULT, EXPECT, #RESULT, __LINE__) #define assert_zueq(RESULT, EXPECT) assert_zueq_(RESULT, EXPECT, #RESULT, __LINE__) static int from_lineno = 0; #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" #endif struct context_user_data { size_t allocate_fail_in; int init_thread_pool_error; int get_ready_threads_error; int run_thread_error; int join_thread_pool_error; int destroy_thread_pool_error; }; #if defined(__clang__) # pragma clang diagnostic pop #endif static void * allocate(size_t num, size_t size, size_t alignment, struct libar2_context *ctx) { #ifndef _POSIX_C_SOURCE # define _POSIX_C_SOURCE 0 #endif #ifndef _ISOC11_SOURCE # ifdef __STDC_VERSION__ # if __STDC_VERSION__ >= 201112L # define _ISOC11_SOURCE # endif # endif #endif void *ptr; uintptr_t req_alignment = (uintptr_t)alignment; if (ctx->user_data) { struct context_user_data *user_data = ctx->user_data; if (user_data->allocate_fail_in) { if (!--user_data->allocate_fail_in) { errno = ENOMEM; return NULL; } } } if (num > SIZE_MAX / size) { /* $covered{$ */ errno = ENOMEM; fail: fprintf(stderr, "Internal test failure: %s\n", strerror(errno)); exit(2); /* $covered}$ */ } if (alignment < sizeof(void *)) alignment = sizeof(void *); #if _POSIX_C_SOURCE >= 200112L errno = posix_memalign(&ptr, alignment, num * size); if (errno) goto fail; /* $covered$ */ #elif defined(_ISOC11_SOURCE) size *= num; /* $covered{$ */ if (size % alignment) { if (size > SIZE_MAX - (alignment - size % alignment)) { errno = ENOMEM; goto fail; } size += alignment - size % alignment; } /* $covered}$ */ ptr = aligned_alloc(alignment, size); if (!ptr) goto fail; /* $covered$ */ #else # error No implementation for aligned memory allocation available #endif if ((uintptr_t)ptr % req_alignment) { /* $covered{$ */ fprintf(stderr, "Internal test failure: memory not properly aligned\n"); exit(2); /* $covered}$ */ } return ptr; } static void deallocate(void *ptr, struct libar2_context *ctx) { (void) ctx; free(ptr); } static int st_init_thread_pool(size_t desired, size_t *createdp, struct libar2_context *ctx) { (void) desired; if (ctx->user_data) { struct context_user_data *user_data = ctx->user_data; if (user_data->init_thread_pool_error) { errno = user_data->init_thread_pool_error; return -1; } } *createdp = 0; return 0; } static int pt_init_thread_pool(size_t desired, size_t *createdp, struct libar2_context *ctx) { (void) ctx; *createdp = desired; return 0; } static size_t pt_get_ready_threads(size_t *indices, size_t n, struct libar2_context *ctx) { (void) n; if (ctx->user_data) { struct context_user_data *user_data = ctx->user_data; if (user_data->get_ready_threads_error) { errno = user_data->get_ready_threads_error; return 0; } } indices[0] = 0; return 1; } static int pt_run_thread(size_t index, void (*function)(void *data), void *data, struct libar2_context *ctx) { (void) index; if (ctx->user_data) { struct context_user_data *user_data = ctx->user_data; if (user_data->run_thread_error) { errno = user_data->run_thread_error; return -1; } } function(data); return 0; } static int pt_join_thread_pool(struct libar2_context *ctx) { if (ctx->user_data) { struct context_user_data *user_data = ctx->user_data; if (user_data->join_thread_pool_error) { errno = user_data->join_thread_pool_error; return -1; } } return 0; } static int pt_destroy_thread_pool(struct libar2_context *ctx) { if (ctx->user_data) { struct context_user_data *user_data = ctx->user_data; if (user_data->destroy_thread_pool_error) { errno = user_data->destroy_thread_pool_error; return -1; } } return 0; } static struct libar2_context ctx_st = { /* st = single threaded */ .user_data = NULL, .autoerase_message = 1, .autoerase_secret = 1, .autoerase_salt = 1, .autoerase_associated_data = 1, .allocate = allocate, .deallocate = deallocate, .init_thread_pool = st_init_thread_pool, .get_ready_threads = NULL, .run_thread = NULL, .join_thread_pool = NULL, .destroy_thread_pool = NULL }; static struct libar2_context ctx_pt = { /* pt = phony threading */ .user_data = NULL, .autoerase_message = 1, .autoerase_secret = 1, .autoerase_salt = 1, .autoerase_associated_data = 1, .allocate = allocate, .deallocate = deallocate, .init_thread_pool = pt_init_thread_pool, .get_ready_threads = pt_get_ready_threads, .run_thread = pt_run_thread, .join_thread_pool = pt_join_thread_pool, .destroy_thread_pool = pt_destroy_thread_pool }; static int nulstrcmp(const char *a, const char *b) { return !a ? -!!b : !b ? +1 : strcmp(a, b); } /* $covered{$ */ static void assert_(int truth, const char *truthstr, int lineno) { if (!truth) { if (from_lineno) fprintf(stderr, "Assertion at line %i, from line %i failed: %s\n", lineno, from_lineno, truthstr); else fprintf(stderr, "Assertion at line %i failed: %s\n", lineno, truthstr); fprintf(stderr, "\terrno: %i (%s)\n", errno, strerror(errno)); exit(1); } } static void assert_streq_(const char *result, const char *expect, const char *code, int lineno) { if (nulstrcmp(result, expect)) { if (from_lineno) fprintf(stderr, "Assertion at line %i, from line %i failed:\n", lineno, from_lineno); else fprintf(stderr, "Assertion at line %i failed:\n", lineno); fprintf(stderr, "\tcode: %s\n", code); fprintf(stderr, "\tresult: %s\n", result); fprintf(stderr, "\texpected: %s\n", expect); fprintf(stderr, "\terrno: %i (%s)\n", errno, strerror(errno)); exit(1); } } static void assert_zueq_(size_t result, size_t expect, const char *code, int lineno) { if (result != expect) { if (from_lineno) fprintf(stderr, "Assertion at line %i, from line %i failed:\n", lineno, from_lineno); else fprintf(stderr, "Assertion at line %i failed:\n", lineno); fprintf(stderr, "\tcode: %s\n", code); fprintf(stderr, "\tresult: %zu\n", result); fprintf(stderr, "\texpected: %zu\n", expect); fprintf(stderr, "\terrno: %i (%s)\n", errno, strerror(errno)); exit(1); } } /* $covered}$ */ static void check_libar2_type_to_string(void) { errno = 0; assert_streq(libar2_type_to_string(LIBAR2_ARGON2D, LIBAR2_LOWER_CASE), "argon2d"); assert_streq(libar2_type_to_string(LIBAR2_ARGON2D, LIBAR2_TITLE_CASE), "Argon2d"); assert_streq(libar2_type_to_string(LIBAR2_ARGON2D, LIBAR2_UPPER_CASE), "ARGON2D"); assert(errno == 0); assert_streq(libar2_type_to_string(LIBAR2_ARGON2I, LIBAR2_LOWER_CASE), "argon2i"); assert_streq(libar2_type_to_string(LIBAR2_ARGON2I, LIBAR2_TITLE_CASE), "Argon2i"); assert_streq(libar2_type_to_string(LIBAR2_ARGON2I, LIBAR2_UPPER_CASE), "ARGON2I"); assert(errno == 0); assert_streq(libar2_type_to_string(LIBAR2_ARGON2ID, LIBAR2_LOWER_CASE), "argon2id"); assert_streq(libar2_type_to_string(LIBAR2_ARGON2ID, LIBAR2_TITLE_CASE), "Argon2id"); assert_streq(libar2_type_to_string(LIBAR2_ARGON2ID, LIBAR2_UPPER_CASE), "ARGON2ID"); assert(errno == 0); assert_streq(libar2_type_to_string(LIBAR2_ARGON2DS, LIBAR2_LOWER_CASE), "argon2ds"); assert_streq(libar2_type_to_string(LIBAR2_ARGON2DS, LIBAR2_TITLE_CASE), "Argon2ds"); assert_streq(libar2_type_to_string(LIBAR2_ARGON2DS, LIBAR2_UPPER_CASE), "ARGON2DS"); assert(errno == 0); assert_streq(libar2_type_to_string(LIBAR2_ARGON2I, (enum libar2_casing)-1), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string(LIBAR2_ARGON2I, (enum libar2_casing)3), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string((enum libar2_argon2_type)3, LIBAR2_LOWER_CASE), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string((enum libar2_argon2_type)3, LIBAR2_TITLE_CASE), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string((enum libar2_argon2_type)3, LIBAR2_UPPER_CASE), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string((enum libar2_argon2_type)-1, LIBAR2_LOWER_CASE), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string((enum libar2_argon2_type)-1, LIBAR2_TITLE_CASE), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string((enum libar2_argon2_type)-1, LIBAR2_UPPER_CASE), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string((enum libar2_argon2_type)5, LIBAR2_LOWER_CASE), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string((enum libar2_argon2_type)5, LIBAR2_TITLE_CASE), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_type_to_string((enum libar2_argon2_type)5, LIBAR2_UPPER_CASE), NULL); assert(errno == EINVAL); errno = 0; } static void check_libar2_string_to_type(void) { enum libar2_argon2_type type; errno = 0; assert(!libar2_string_to_type("argon2i", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("Argon2i", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("ARgon2i", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("ARGon2i", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("ARGOn2i", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("ARGON2i", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("ARGON2I", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("aRGON2I", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("arGON2I", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("argON2I", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("argoN2I", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("argon2I", &type) && type == LIBAR2_ARGON2I); assert(!libar2_string_to_type("argon2i$x", &type) && type == LIBAR2_ARGON2I); assert(errno == 0); assert(!libar2_string_to_type("argon2d", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("Argon2d", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("ARgon2d", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("ARGon2d", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("ARGOn2d", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("ARGON2d", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("ARGON2D", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("aRGON2D", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("arGON2D", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("argON2D", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("argoN2D", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("argon2D", &type) && type == LIBAR2_ARGON2D); assert(!libar2_string_to_type("argon2d$x", &type) && type == LIBAR2_ARGON2D); assert(errno == 0); assert(!libar2_string_to_type("argon2id", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("Argon2id", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("ARgon2id", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("ARGon2id", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("ARGOn2id", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("ARGON2id", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("ARGON2Id", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("ARGON2ID", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("aRGON2ID", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("arGON2ID", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("argON2ID", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("argoN2ID", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("argon2ID", &type) && type == LIBAR2_ARGON2ID); assert(!libar2_string_to_type("argon2id$x", &type) && type == LIBAR2_ARGON2ID); assert(errno == 0); assert(!libar2_string_to_type("argon2ds", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("Argon2ds", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("ARgon2ds", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("ARGon2ds", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("ARGOn2ds", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("ARGON2ds", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("ARGON2Ds", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("ARGON2DS", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("aRGON2DS", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("arGON2DS", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("argON2DS", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("argoN2DS", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("argon2DS", &type) && type == LIBAR2_ARGON2DS); assert(!libar2_string_to_type("argon2ds$x", &type) && type == LIBAR2_ARGON2DS); assert(errno == 0); assert(libar2_string_to_type("argon2", &type) == -1); assert(errno == EINVAL); errno = 0; assert(libar2_string_to_type("argon2x", &type) == -1); assert(errno == EINVAL); errno = 0; assert(libar2_string_to_type("ARGON2", &type) == -1); assert(errno == EINVAL); errno = 0; } static void check_libar2_version_to_string(void) { errno = 0; assert_streq(libar2_version_to_string(LIBAR2_ARGON2_VERSION_10), "10"); assert(errno == 0); assert_streq(libar2_version_to_string(LIBAR2_ARGON2_VERSION_13), "13"); assert(errno == 0); assert_streq(libar2_version_to_string(0x10), "10"); assert(errno == 0); assert_streq(libar2_version_to_string(0x13), "13"); assert(errno == 0); assert_streq(libar2_version_to_string((enum libar2_argon2_version)0x11), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_version_to_string((enum libar2_argon2_version)0x12), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_version_to_string((enum libar2_argon2_version)0), NULL); assert(errno == EINVAL); errno = 0; } static void check_libar2_version_to_string_proper(void) { errno = 0; assert_streq(libar2_version_to_string_proper(LIBAR2_ARGON2_VERSION_10), "1.0"); assert(errno == 0); assert_streq(libar2_version_to_string_proper(LIBAR2_ARGON2_VERSION_13), "1.3"); assert(errno == 0); assert_streq(libar2_version_to_string_proper(0x10), "1.0"); assert(errno == 0); assert_streq(libar2_version_to_string_proper(0x13), "1.3"); assert(errno == 0); assert_streq(libar2_version_to_string_proper((enum libar2_argon2_version)0x11), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_version_to_string_proper((enum libar2_argon2_version)0x12), NULL); assert(errno == EINVAL); errno = 0; assert_streq(libar2_version_to_string_proper((enum libar2_argon2_version)0), NULL); assert(errno == EINVAL); errno = 0; } static void check_libar2_string_to_version(void) { enum libar2_argon2_version version; errno = 0; assert(!libar2_string_to_version("10", &version) && version == LIBAR2_ARGON2_VERSION_10); assert(errno == 0); assert(!libar2_string_to_version("13", &version) && version == LIBAR2_ARGON2_VERSION_13); assert(errno == 0); assert(!libar2_string_to_version("1.0", &version) && version == LIBAR2_ARGON2_VERSION_10); assert(errno == 0); assert(!libar2_string_to_version("1.3", &version) && version == LIBAR2_ARGON2_VERSION_13); assert(errno == 0); assert(libar2_string_to_version("11", &version) == -1); assert(errno == EINVAL); errno = 0; assert(libar2_string_to_version("12", &version) == -1); assert(errno == EINVAL); errno = 0; assert(libar2_string_to_version("1.1", &version) == -1); assert(errno == EINVAL); errno = 0; assert(libar2_string_to_version("1.2", &version) == -1); assert(errno == EINVAL); errno = 0; assert(libar2_string_to_version("16", &version) == -1); assert(errno == EINVAL); errno = 0; assert(libar2_string_to_version("19", &version) == -1); assert(errno == EINVAL); errno = 0; } static void check_libar2_encode_base64(void) { char buf[128]; errno = 0; assert(libar2_encode_base64(NULL, MEM("")) == 1); assert(libar2_encode_base64(NULL, MEM("1")) == 3); assert(libar2_encode_base64(NULL, MEM("12")) == 4); assert(libar2_encode_base64(NULL, MEM("123")) == 5); assert(libar2_encode_base64(NULL, MEM("1234")) == 7); assert(libar2_encode_base64(NULL, MEM("12345")) == 8); assert(errno == 0); assert(libar2_encode_base64(buf, MEM("")) == 1); assert_streq(buf, ""); assert(errno == 0); #define ENCODE_BASE64(S) libar2_encode_base64(buf, MEM(S)) assert(ENCODE_BASE64("") == 1); assert_streq(buf, ""); assert(errno == 0); assert(ENCODE_BASE64("\x00") == 3); assert_streq(buf, "AA"); assert(errno == 0); assert(ENCODE_BASE64("\x00\x00") == 4); assert_streq(buf, "AAA"); assert(errno == 0); assert(ENCODE_BASE64("\x00\x00\x00") == 5); assert_streq(buf, "AAAA"); assert(errno == 0); assert(ENCODE_BASE64("12345678") == 12); assert_streq(buf, "MTIzNDU2Nzg"); assert(errno == 0); assert(ENCODE_BASE64("testtest") == 12); assert_streq(buf, "dGVzdHRlc3Q"); assert(errno == 0); assert(ENCODE_BASE64("zy[]y21 !") == 13); assert_streq(buf, "enlbXXkyMSAh"); assert(errno == 0); assert(ENCODE_BASE64("{~|~}~~~\x7f\x7f") == 15); assert_streq(buf, "e358fn1+fn5/fw"); assert(errno == 0); #undef ENCODE_BASE64 assert(libar2_encode_base64(buf, MEM("{~|~}~~~\x7f\x7f")) == 15); assert_streq(buf, "e358fn1+fn5/fw"); assert(errno == 0); assert(libar2_encode_base64_overlap_support(buf, MEM("{~|~}~~~\x7f\x7f")) == 15); assert_streq(buf, "e358fn1+fn5/fw"); assert(errno == 0); } static void check_libar2_decode_base64(void) { char buf[128]; size_t len; errno = 0; #define DECODE_BASE64(S) (stpcpy(buf, S), libar2_decode_base64(buf, buf, &len)) assert(libar2_decode_base64("", buf, &len) == 0); assert(len == 0); assert(errno == 0); assert(DECODE_BASE64("") == 0); assert(len == 0); assert(errno == 0); assert(DECODE_BASE64("A") == 0); assert(len == 0); assert(errno == 0); #define CHECK(S) len == sizeof(S) - 1 && !memcmp(buf, S, len) assert(DECODE_BASE64("AA") == 2); assert(CHECK("\x00")); assert(errno == 0); assert(DECODE_BASE64("AAA") == 3); assert(CHECK("\x00\x00")); assert(errno == 0); assert(DECODE_BASE64("AAAA") == 4); assert(CHECK("\x00\x00\x00")); assert(errno == 0); assert(DECODE_BASE64("AAAAA") == 4); assert(CHECK("\x00\x00\x00")); assert(errno == 0); assert(DECODE_BASE64("AAAAAA") == 6); assert(CHECK("\x00\x00\x00\x00")); assert(errno == 0); assert(DECODE_BASE64("MTIzNDU2Nzg") == 11); assert(CHECK("12345678")); assert(errno == 0); assert(DECODE_BASE64("dGVzdHRlc3Q") == 11); assert(CHECK("testtest")); assert(errno == 0); assert(DECODE_BASE64("enlbXXkyMSAh") == 12); assert(CHECK("zy[]y21 !")); assert(errno == 0); assert(DECODE_BASE64("e358fn1+fn5/fw") == 14); assert(CHECK("{~|~}~~~\x7f\x7f")); assert(errno == 0); assert(libar2_decode_base64("e358fn1+fn5/fw", buf, &len) == 14); assert(CHECK("{~|~}~~~\x7f\x7f")); assert(errno == 0); #undef CHECK #undef DECODE_BASE64 } static void check_libar2_encode_params_libar2_decode_params(void) { struct libar2_argon2_parameters params; char *sbuf = NULL; char pbuf[256]; #define DECODE(PARAMS, HASH)\ libar2_decode_params(PARAMS""HASH, ¶ms, &sbuf, &ctx_st) #define PARAMSTR "$argon2i$v=19$m=4096,t=3,p=1$fn5/f35+f38$" memset(¶ms, 0xFF, sizeof(params)); assert_zueq(DECODE(PARAMSTR, "1234"), sizeof(PARAMSTR) - 1); assert(params.type == LIBAR2_ARGON2I); assert(params.version == LIBAR2_ARGON2_VERSION_13); assert(params.t_cost == 3); assert(params.m_cost == 4096); assert(params.lanes == 1); assert(params.salt != NULL); assert(params.saltlen == 8); assert(!memcmp(params.salt, "~~\x7f\x7f~~\x7f\x7f", params.saltlen)); assert(!params.key); assert(!params.keylen); assert(!params.ad); assert(!params.adlen); assert(params.hashlen == 3); assert_zueq(libar2_encode_params(NULL, ¶ms), sizeof(PARAMSTR)); assert_zueq(libar2_encode_params(pbuf, ¶ms), sizeof(PARAMSTR)); assert_streq(pbuf, PARAMSTR); assert(sbuf != NULL); ctx_st.deallocate(sbuf, &ctx_st); sbuf = NULL; #undef PARAMSTR #define PARAMSTR "$argon2i$v=16$m=4096,t=3,p=1$fn5/f35+f38$" memset(¶ms, 0xFF, sizeof(params)); assert_zueq(DECODE(PARAMSTR, "1234"), sizeof(PARAMSTR) - 1); assert(params.type == LIBAR2_ARGON2I); assert(params.version == LIBAR2_ARGON2_VERSION_10); assert(params.t_cost == 3); assert(params.m_cost == 4096); assert(params.lanes == 1); assert(params.salt != NULL); assert(params.saltlen == 8); assert(!memcmp(params.salt, "~~\x7f\x7f~~\x7f\x7f", params.saltlen)); assert(!params.key); assert(!params.keylen); assert(!params.ad); assert(!params.adlen); assert(params.hashlen == 3); assert_zueq(libar2_encode_params(NULL, ¶ms), sizeof(PARAMSTR)); assert_zueq(libar2_encode_params(pbuf, ¶ms), sizeof(PARAMSTR)); assert_streq(pbuf, PARAMSTR); assert(sbuf != NULL); ctx_st.deallocate(sbuf, &ctx_st); sbuf = NULL; #undef PARAMSTR #define PARAMSTR "$argon2i$m=4096,t=3,p=1$fn5/f35+f38$" memset(¶ms, 0xFF, sizeof(params)); assert_zueq(DECODE(PARAMSTR, "1234"), sizeof(PARAMSTR) - 1); assert(params.type == LIBAR2_ARGON2I); assert(params.version == 0); assert(params.t_cost == 3); assert(params.m_cost == 4096); assert(params.lanes == 1); assert(params.salt != NULL); assert(params.saltlen == 8); assert(!memcmp(params.salt, "~~\x7f\x7f~~\x7f\x7f", params.saltlen)); assert(!params.key); assert(!params.keylen); assert(!params.ad); assert(!params.adlen); assert(params.hashlen == 3); assert_zueq(libar2_encode_params(NULL, ¶ms), sizeof(PARAMSTR)); assert_zueq(libar2_encode_params(pbuf, ¶ms), sizeof(PARAMSTR)); assert_streq(pbuf, PARAMSTR); assert(sbuf != NULL); ctx_st.deallocate(sbuf, &ctx_st); sbuf = NULL; #undef PARAMSTR #undef DECODE } static void check_libar2_validate_params(void) { struct libar2_argon2_parameters params; const char *errmsg = NULL; errno = 0; memset(¶ms, 0, sizeof(params)); params.type = LIBAR2_ARGON2I; params.version = LIBAR2_ARGON2_VERSION_13; params.t_cost = 3; params.m_cost = 4096; params.lanes = 1; params.saltlen = 8; params.hashlen = 4; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_OK); assert_streq(errmsg, "OK"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, &errmsg) == 0); assert_streq(errmsg, "OK"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == 0); assert(errno == 0); params.version = LIBAR2_ARGON2_VERSION_10; assert(libar2_validate_params(¶ms, NULL) == 0); assert(errno == 0); params.type = LIBAR2_ARGON2I; assert(libar2_validate_params(¶ms, NULL) == 0); assert(errno == 0); params.type = LIBAR2_ARGON2D; assert(libar2_validate_params(¶ms, NULL) == 0); assert(errno == 0); params.type = LIBAR2_ARGON2DS; assert(libar2_validate_params(¶ms, NULL) == 0); assert(errno == 0); params.hashlen = 3; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_HASH_TOO_SMALL); assert_streq(errmsg, "tag length parameter is too small"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_HASH_TOO_SMALL); assert(errno == 0); params.hashlen = 4; params.saltlen = 7; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_SALT_TOO_SMALL); assert_streq(errmsg, "salt parameter is too small"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_SALT_TOO_SMALL); assert(errno == 0); params.saltlen = 8; params.t_cost = 0; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_T_COST_TOO_SMALL); assert_streq(errmsg, "time-cost parameter is too small"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_T_COST_TOO_SMALL); assert(errno == 0); params.t_cost = 1; params.m_cost = 7; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_M_COST_TOO_SMALL); assert_streq(errmsg, "memory-cost parameter is too small"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_M_COST_TOO_SMALL); assert(errno == 0); params.m_cost = 8; params.lanes = 0; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_TOO_FEW_LANES); assert_streq(errmsg, "lane-count parameter is too small"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_TOO_FEW_LANES); assert(errno == 0); params.lanes = 1; params.lanes = 0x1000000UL; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_TOO_MANY_LANES); assert_streq(errmsg, "lane-count parameter is too large"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_TOO_MANY_LANES); assert(errno == 0); params.lanes = 1; params.type = (enum libar2_argon2_type)-1; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_INVALID_TYPE); assert_streq(errmsg, "type parameter is invalid"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_INVALID_TYPE); assert(errno == 0); params.type = 0; params.type = (enum libar2_argon2_type)3; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_INVALID_TYPE); assert_streq(errmsg, "type parameter is invalid"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_INVALID_TYPE); assert(errno == 0); params.type = 0; params.type = (enum libar2_argon2_type)5; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_INVALID_TYPE); assert_streq(errmsg, "type parameter is invalid"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_INVALID_TYPE); assert(errno == 0); params.type = 0; params.version = (enum libar2_argon2_version)0x11; assert(libar2_validate_params(¶ms, &errmsg) == LIBAR2_INVALID_VERSION); assert_streq(errmsg, "version parameter is invalid"); assert(errno == 0); errmsg = NULL; assert(libar2_validate_params(¶ms, NULL) == LIBAR2_INVALID_VERSION); assert(errno == 0); params.version = 0x10; } static void check_hash(const char *pwd_, size_t pwdlen, const char *hash, void *key, size_t keylen, void *ad, size_t adlen, struct libar2_context *ctx, int lineno) { struct libar2_argon2_parameters params; char *sbuf, output[512], pwd[512], output64[700]; size_t plen; from_lineno = lineno; errno = 0; memcpy(pwd, pwd_, pwdlen); plen = libar2_decode_params(hash, ¶ms, &sbuf, ctx); params.key = key; params.keylen = keylen; params.ad = ad; params.adlen = adlen; assert(!libar2_validate_params(¶ms, NULL)); assert(!libar2_hash(output, pwd, pwdlen, ¶ms, ctx)); libar2_encode_base64(output64, output, params.hashlen); assert_streq(output64, &hash[plen]); assert(errno == 0); if (sbuf) ctx->deallocate(sbuf, ctx); from_lineno = 0; } static int memis(char *mem, int ch, size_t n) { size_t i; int ok = 1; for (i = 0; i < n; i++) if (mem[i] != (char)ch) return 0; /* $covered$ */ return ok; } /* Typo in version 1.0 */ extern void libar2_earse(volatile void *mem, size_t size); static void check_libar2_erase(void) { char buf[1024]; memset(buf, 1, sizeof(buf)); libar2_earse(&buf[0], 512); assert(memis(&buf[512], 1, 512)); assert(memis(&buf[0], 0, 512)); /* libar2_erase has been replaced by this test, so we test this instead */ memset(buf, 1, sizeof(buf)); libar2_internal_erase__(&buf[0], 512); assert(memis(&buf[512], 1, 512)); assert(memis(&buf[0], 0, 512)); } static void check_libar2_hash(void) { char spaces[512]; char zeroes[512]; memset(spaces, ' ', sizeof(spaces)); memset(zeroes, 0, sizeof(zeroes)); #define CHECK(PWD, HASH)\ check_hash(MEM(PWD), HASH, NULL, 0, NULL, 0, &ctx_st, __LINE__) CHECK("\x00", "$argon2d$v=16$m=8,t=1,p=1$ICAgICAgICA$Eyx1BxGazSuPQoy7osaQuo20Dw9VI97dYUOgcC3cMgw"); CHECK("test", "$argon2i$v=19$m=4096,t=3,p=1$fn5/f35+f38$9tqKA4WMEsSAOEUwatjxvJLSqL1j0GQkgbsfnpresDw"); CHECK("\x00", "$argon2id$v=16$m=8,t=1,p=1$ICAgICAgICA$fXq1aUbp9yhbn+EQc4AzUUE6AKnHAkvzIXsN6J4ukvE"); CHECK("", "$argon2d$v=16$m=8,t=1,p=1$ICAgICAgICA$X54KZYxUSfMUihzebb70sKbheabHilo8gsUldrVU4IU"); CHECK("", "$argon2d$v=16$m=8,t=1,p=1$ICAgICAgICA$NjODMrWrS7zeivNNpHsuxD9c6uDmUQ6YqPRhb8H5DSNw9" "n683FUCJZ3tyxgfJpYYANI+01WT/S5zp1UVs+qNRwnkdEyLKZMg+DIOXVc9z1po9ZlZG8+Gp4g5brqfza3lvkR9vw"); CHECK("", "$argon2ds$v=16$m=8,t=1,p=1$ICAgICAgICA$zgdykk9ZjN5VyrW0LxGw8LmrJ1Z6fqSC+3jPQtn4n0s"); CHECK("password", "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ$9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ"); CHECK("password", "$argon2i$m=1048576,t=2,p=1$c29tZXNhbHQ$lpDsVdKNPtMlYvLnPqYrArAYdXZDoq5ueVKEWd6BBuk"); CHECK("password", "$argon2i$m=262144,t=2,p=1$c29tZXNhbHQ$Pmiaqj0op3zyvHKlGsUxZnYXURgvHuKS4/Z3p9pMJGc"); CHECK("password", "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ$/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY"); CHECK("password", "$argon2i$m=256,t=2,p=2$c29tZXNhbHQ$tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs"); CHECK("password", "$argon2i$m=65536,t=1,p=1$c29tZXNhbHQ$gWMFUrjzsfSM2xmSxMZ4ZD1JCytetP9sSzQ4tWIXJLI"); CHECK("password", "$argon2i$m=65536,t=4,p=1$c29tZXNhbHQ$8hLwFhXm6110c03D70Ct4tUdBSRo2MaUQKOh8sHChHs"); CHECK("differentpassword", "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ$6ckCB0tnVFMaOgvlGeW69ASzDOabPwGsO/ISKZYBCaM"); CHECK("password", "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ$eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc"); CHECK("password", "$argon2i$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ$0Vh6ygkiw7XWqD7asxvuPE667zQu1hJ6VdGbI1GtH0E"); CHECK("password", "$argon2i$v=19$m=262144,t=2,p=1$c29tZXNhbHQ$KW266AuAfNzqrUSudBtQbxTbCVkmexg7EY+bJCKbx8s"); CHECK("password", "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ$iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8"); CHECK("password", "$argon2i$v=19$m=256,t=2,p=2$c29tZXNhbHQ$T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E"); CHECK("password", "$argon2i$v=19$m=65536,t=1,p=1$c29tZXNhbHQ$0WgHXE2YXhPr6uVgz4uUw7XYoWxRkWtvSsLaOsEbvs8"); CHECK("password", "$argon2i$v=19$m=65536,t=4,p=1$c29tZXNhbHQ$qqlT1YrzcGzj3xrv1KZKhOMdf1QXUjHxKFJZ+IF0zls"); CHECK("differentpassword", "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ$FK6NoBr+qHAMI1jc73xTWNkCEoK9iGY6RWL1n7dNIu4"); CHECK("password", "$argon2i$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ$sDV8zPvvkfOGCw26RHsjSMvv7K2vmQq/6cxAcmxSEnE"); CHECK("password", "$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ$CTFhFdXPJO1aFaMaO6Mm5c8y7cJHAph8ArZWb2GRPPc"); CHECK("password", "$argon2id$v=19$m=262144,t=2,p=1$c29tZXNhbHQ$eP4eyR+zqlZX1y5xCFTkw9m5GYx0L5YWwvCFvtlbLow"); CHECK("password", "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4"); CHECK("password", "$argon2id$v=19$m=256,t=2,p=2$c29tZXNhbHQ$bQk8UB/VmZZF4Oo79iDXuL5/0ttZwg2f/5U52iv1cDc"); CHECK("password", "$argon2id$v=19$m=65536,t=1,p=1$c29tZXNhbHQ$9qWtwbpyPd3vm1rB1GThgPzZ3/ydHL92zKL+15XZypg"); CHECK("password", "$argon2id$v=19$m=65536,t=4,p=1$c29tZXNhbHQ$kCXUjmjvc5XMqQedpMTsOv+zyJEf5PhtGiUghW9jFyw"); CHECK("differentpassword", "$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ$C4TWUs9rDEvq7w3+J4umqA32aWKB1+DSiRuBfYxFj94"); CHECK("password", "$argon2id$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ$vfMrBczELrFdWP0ZsfhWsRPaHppYdP3MVEMIVlqoFBw"); CHECK("", "$argon2ds$v=16$m=8,t=1,p=2$ICAgICAgICA$+6+yBnWbuV7mLs6rKMhvi+SLbkzb5CB6Jd2pSWuC/Kw"); /* not well-known */ #undef CHECK #define CHECK(PWD, HASH)\ check_hash(MEM(PWD), HASH, NULL, 0, NULL, 0, &ctx_pt, __LINE__) CHECK("password", "$argon2i$m=256,t=2,p=2$c29tZXNhbHQ$tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs"); CHECK("", "$argon2ds$v=16$m=8,t=1,p=2$ICAgICAgICA$+6+yBnWbuV7mLs6rKMhvi+SLbkzb5CB6Jd2pSWuC/Kw"); /* verified above */ CHECK("", "$argon2d$v=16$m=8,t=1,p=1$ICAgICAgICA$X54KZYxUSfMUihzebb70sKbheabHilo8gsUldrVU4IU"); CHECK("password", "$argon2id$v=19$m=65536,t=4,p=1$c29tZXNhbHQ$kCXUjmjvc5XMqQedpMTsOv+zyJEf5PhtGiUghW9jFyw"); #undef CHECK #define CHECK(PWDLEN, KEYLEN, ADLEN, HASH)\ check_hash(spaces, PWDLEN, HASH, KEYLEN ? zeroes : NULL, KEYLEN, ADLEN ? zeroes : NULL, ADLEN, &ctx_pt, __LINE__) /* these are calculated with reference implmentation */ CHECK(1, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$MKifhakDKOM"); CHECK(8, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$n6AxIe1Ch+Y"); CHECK(16, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$n1jRvzIq/JI"); CHECK(99, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$7f1A+np6ekI"); CHECK(100, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$oQ0MP/+6pTE"); CHECK(101, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$0nF5gzoood8"); CHECK(96, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$JtutNzkqeVs"); CHECK(88, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$uq+BEaf7YGs"); CHECK(84, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$6fY3ZSyP1Yc"); CHECK(85, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$EvoR6s6ZVs0"); CHECK(83, 0, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$q46jnJcAUCY"); CHECK(1, 4, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$Mhl4o3AkJuA"); CHECK(84, 4, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$+hlEcRn+F3s"); CHECK(80, 4, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$z2d6ce8UqS0"); CHECK(80, 140, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$15FAGe1KIX8"); CHECK(80, 160, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$oH3H5atuca8"); CHECK(80, 128, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$TsimqI1YC08"); CHECK(80, 256, 0, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$mzPlVOVjVos"); CHECK(1, 0, 16, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$HrfeSHrbdxk"); CHECK(80, 0, 16, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$VRC9yoVQxGQ"); CHECK(76, 0, 16, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$i8q267O+NzU"); CHECK(76, 0, 128, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$fqP9Bhruhvs"); CHECK(76, 0, 130, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$kZ/OfiPy33c"); CHECK(76, 0, 160, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$XEdsiqJkQ4I"); CHECK(80, 0, 160, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$2aPe8XbvFv0"); CHECK(76, 0, 256, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$NlyQ7poTmcA"); CHECK(80, 0, 128, "$argon2i$v=19$m=8,t=1,p=1$ICAgICAgICA$W214JDf8nik"); #undef CHECK } #if defined(__x86_64__) && defined(LIBAR2_TARGET__) && defined(__GNUC__) static void run_check_libar2_hash_optimisations(void) { #define CHECK(PWD, HASH)\ check_hash(MEM(PWD), HASH, NULL, 0, NULL, 0, &ctx_st, __LINE__) CHECK("password", "$argon2i$m=256,t=2,p=2$c29tZXNhbHQ$tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs"); CHECK("", "$argon2ds$v=16$m=8,t=1,p=2$ICAgICAgICA$+6+yBnWbuV7mLs6rKMhvi+SLbkzb5CB6Jd2pSWuC/Kw"); CHECK("", "$argon2d$v=16$m=8,t=1,p=1$ICAgICAgICA$X54KZYxUSfMUihzebb70sKbheabHilo8gsUldrVU4IU"); CHECK("password", "$argon2i$v=19$m=256,t=2,p=2$c29tZXNhbHQ$T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E"); #undef CHECK } #endif static void check_libar2_hash_optimisations(void) { #if defined(__x86_64__) && defined(LIBAR2_TARGET__) && defined(__GNUC__) __builtin_cpu_init(); libar2_internal_use_generic__(); run_check_libar2_hash_optimisations(); libar2_internal_use_sse2__(); if (__builtin_cpu_supports("sse2")) run_check_libar2_hash_optimisations(); /* $covered$ */ libar2_internal_use_avx2__(); if (__builtin_cpu_supports("avx2")) run_check_libar2_hash_optimisations(); /* $covered$ */ libar2_internal_use_avx512f__(); if (__builtin_cpu_supports("avx512f")) run_check_libar2_hash_optimisations(); /* $covered$ */ /* $covered{$ */ else if (__builtin_cpu_supports("avx2")) libar2_internal_use_avx2__(); else if (__builtin_cpu_supports("sse2")) libar2_internal_use_sse2__(); else libar2_internal_use_generic__(); /* $covered}$ */ #endif } #ifdef LIBAR2_WEAKLY_LINKED__ void libar2_erase(volatile void *mem, size_t size) { (void) mem; (void) size; } static void check_libar2_hash_buf_size(void) { struct libar2_argon2_parameters params; char pwd[512], output[2049], *doutput; unsigned char salt[LIBAR2_MIN_SALTLEN]; size_t i, size, size0, size1; volatile char x, *avoid_code_elimination = &x; errno = 0; memset(¶ms, 0, sizeof(params)); memset(salt, 0, sizeof(salt)); params.saltlen = LIBAR2_MIN_SALTLEN; params.salt = salt; params.m_cost = LIBAR2_MIN_M_COST; params.t_cost = LIBAR2_MIN_T_COST; params.lanes = LIBAR2_MIN_LANES; params.type = LIBAR2_ARGON2I; for (params.hashlen = LIBAR2_MIN_HASHLEN; params.hashlen < sizeof(output) - 513; params.hashlen++) { memset(output, 0, sizeof(output)); assert(!libar2_hash(output, pwd, 0, ¶ms, &ctx_st)); assert(errno == 0); for (size0 = sizeof(output); size0; size0--) if (output[size0 - 1] != 0) break; memset(output, 1, sizeof(output)); assert(!libar2_hash(output, pwd, 0, ¶ms, &ctx_st)); assert(errno == 0); for (size1 = sizeof(output); size1; size1--) if (output[size1 - 1] != 1) break; size = MAX(size0, size1); if (libar2_hash_buf_size(¶ms) != size || size > params.hashlen + 63) fprintf(stderr, "At hashlen = %zu (expect %zu)\n", params.hashlen, size); /* $covered$ */ assert(size <= params.hashlen + 63); assert_zueq(libar2_hash_buf_size(¶ms), size); size = libar2_hash_buf_size(¶ms); assert(size > 0); /* Using posix_memalign because free fails under valgrind (even * when the code is isoleted into a trivial minimal example) * when the memory has been allocated with malloc when using * musl, at least if musl is not the default libc */ assert(!posix_memalign((void *)&doutput, sizeof(void *), size)); assert(!libar2_hash(doutput, pwd, 0, ¶ms, &ctx_st)); assert(errno == 0); for(i = 0; i < params.hashlen; i++) *avoid_code_elimination ^= doutput[i]; free(doutput); } } #endif static void check_failures(void) { struct context_user_data user_data; struct libar2_argon2_parameters params; char *buf, sbuf[3 * sizeof(unsigned int) + 512]; params.hashlen = SIZE_MAX; errno = 0; assert(libar2_hash_buf_size(¶ms) == 0 && errno == EOVERFLOW); buf = NULL; #define CHECKE(STR, ERR)\ do {\ errno = 0;\ assert(libar2_decode_params(STR, ¶ms, &buf, &ctx_st) == 0 && errno == (ERR));\ assert(!buf);\ } while (0) #define CHECK(STR) CHECKE(STR, EINVAL) CHECK(""); CHECK("x"); CHECK("$"); CHECK("$argon2id"); CHECK("$argon2idX"); CHECK("$argon2idX$"); CHECK("$argon2id$"); CHECK("$argon2id$$"); CHECK("$argon2id$x"); CHECK("$argon2id$v"); CHECK("$argon2id$v="); CHECK("$argon2id$v=$"); CHECK("$argon2id$v=x$"); CHECKE("$argon2id$v=9999999999999999999999999999999999999999999999999999999999999999999999999$", ERANGE); sprintf(sbuf, "$argon2id$v=%u$", (unsigned int)INT_MAX + 1U); CHECKE(sbuf, ERANGE); CHECK("$argon2id$v=-1$"); CHECK("$argon2id$v=16"); CHECK("$argon2id$v=16,"); CHECK("$argon2id$$m=128,t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=-128,t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128,t=-128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128,t=128,p=-128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=x,t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128,t=x,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128,t=128,p=x$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128,t=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128,t=128,p=128,m=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128,t=128,p=128,t=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128,t=128,p=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$m=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$t=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19$p=128$AAAABBBBCCCC$"); CHECKE("$argon2id$v=19$m=999999999999999999999999999999999999999999999999999999999999,t=128,p=128$AAAABBBBCCCC$", ERANGE); CHECKE("$argon2id$v=19$m=128,t=999999999999999999999999999999999999999999999999999999999999,p=128$AAAABBBBCCCC$", ERANGE); CHECKE("$argon2id$v=19$m=128,t=128,p=999999999999999999999999999999999999999999999999999999999999$AAAABBBBCCCC$", ERANGE); CHECK("$argon2id$m=128;t=128;p=128$AAAABBBBCCCC$"); CHECK("$argon2id$m=128t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=19,m=128,t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$m=128,t=128,p=128,v=19$AAAABBBBCCCC$"); CHECK("$argon2id$m=128,t=128,p=128,$AAAABBBBCCCC$"); CHECK("$argon2id$m=128,t=128,p=128"); CHECK("$argon2id$m=128,t=128,,p=128"); CHECK("$argon2id$m=128,t=128,p=128$"); CHECK("$argon2id$m=128,t=128,p=128,"); CHECK("$argon2id$m=128,t=128,p=128,$AAAABBBBCCCC"); CHECK("$argon2id$m=128,t=128,p=128$AAAABBBBCCCC"); CHECK("$argon2id$m=128,t=128,p=128$AAAAB-BBCCCC$"); CHECK("$argon2id$m=128,t=128,p=128$AAAABBBBC$"); CHECK("$argon2id$,m=128,t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$m=128,p=128,t=128$AAAABBBBCCCC$"); CHECK("$argon2id$t=128,m=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$t=128,p=128,m=128$AAAABBBBCCCC$"); CHECK("$argon2id$p=128,m=128,t=128$AAAABBBBCCCC$"); CHECK("$argon2id$p=128,t=128,m=128$AAAABBBBCCCC$"); CHECK("$argon2id$m=0128,t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$m=00128,t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$m=128,t=0128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$m=128,t=00128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$m=128,t=128,p=0128$AAAABBBBCCCC$"); CHECK("$argon2id$m=128,t=128,p=00128$AAAABBBBCCCC$"); CHECK("$argon2id$v=0$m=128,t=128,p=128$AAAABBBBCCCC$"); CHECK("$argon2id$v=016$m=128,t=128,p=128$AAAABBBBCCCC$"); errno = 0; ctx_st.user_data = &user_data; user_data.allocate_fail_in = 1; assert(libar2_decode_params("$argon2id$m=8,t=1,p=1$AAAABBBBCCC$", ¶ms, &buf, &ctx_st) == 0 && errno == ENOMEM); assert(!buf); ctx_st.user_data = NULL; #undef CHECK #undef CHECKE memset(¶ms, 0, sizeof(params)); errno = 0; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_st) == -1 && errno == EINVAL); params.m_cost = 32; params.t_cost = 32; params.lanes = 32; params.salt = (unsigned char []){"\0\0\0\0\0\0\0\0"}; params.saltlen = 8; params.hashlen = 32; #if SIZE_MAX >> 31 > 1 errno = 0; assert(libar2_hash(sbuf, NULL, (size_t)1 << 32, ¶ms, &ctx_st) == -1 && errno == EINVAL); #endif ctx_st.user_data = &user_data; ctx_pt.user_data = &user_data; memset(&user_data, 0, sizeof(user_data)); errno = 0; user_data.allocate_fail_in = 1; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_st) == -1 && errno == ENOMEM); errno = 0; params.type = LIBAR2_ARGON2DS; user_data.allocate_fail_in = 2; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_st) == -1 && errno == ENOMEM); errno = 0; user_data.allocate_fail_in = 3; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_pt) == -1 && errno == ENOMEM); user_data.allocate_fail_in = 0; errno = 0; user_data.init_thread_pool_error = EDOM; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_st) == -1 && errno == EDOM); user_data.init_thread_pool_error = 0; errno = 0; user_data.get_ready_threads_error = EDOM; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_pt) == -1 && errno == EDOM); user_data.get_ready_threads_error = 0; errno = 0; user_data.run_thread_error = EDOM; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_pt) == -1 && errno == EDOM); user_data.run_thread_error = 0; errno = 0; user_data.join_thread_pool_error = EDOM; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_pt) == -1 && errno == EDOM); user_data.join_thread_pool_error = 0; errno = 0; user_data.destroy_thread_pool_error = EDOM; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_pt) == -1 && errno == EDOM); errno = 0; user_data.destroy_thread_pool_error = EDOM; params.lanes = 1; assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_pt) == -1 && errno == EDOM); params.lanes = 32; user_data.destroy_thread_pool_error = 0; ctx_st.user_data = NULL; ctx_pt.user_data = NULL; errno = 0; } int main(void) { #if !MEASURE_TIME_ONLY check_libar2_type_to_string(); check_libar2_string_to_type(); check_libar2_version_to_string(); check_libar2_version_to_string_proper(); check_libar2_string_to_version(); check_libar2_encode_base64(); check_libar2_decode_base64(); check_libar2_encode_params_libar2_decode_params(); check_libar2_validate_params(); check_libar2_erase(); check_libar2_hash(); # ifdef LIBAR2_WEAKLY_LINKED__ check_libar2_hash_buf_size(); # endif check_failures(); #endif #if MEASURE_TIME { struct libar2_argon2_parameters params; char output[512]; clock_t dur; double ddur; int r; memset(¶ms, 0, sizeof(params)); params.m_cost = 8; params.t_cost = 1; params.lanes = 1; params.saltlen = 8; params.salt = (unsigned char[]){"\0\0\0\0\0\0\0\0"}; params.hashlen = 32; assert(!libar2_validate_params(¶ms, NULL)); dur = clock(); r = libar2_hash(output, NULL, 0, ¶ms, &ctx_st); dur = clock() - dur; assert(!r); ddur = (double)dur; ddur /= CLOCKS_PER_SEC; ddur *= 1000; fprintf(stderr, "Time: %lg ms\n", ddur); } #endif #if !MEASURE_TIME_ONLY check_libar2_hash_optimisations(); #endif return 0; }