From 6fdc65dea61edb79ba3c05b7bcebc679b51731e1 Mon Sep 17 00:00:00 2001 From: Paul Driver Date: Mon, 10 Aug 2020 15:19:32 -0700 Subject: [PATCH] argon2 --- nix/pkgs/default.nix | 2 +- nix/pkgs/urcrypt/default.nix | 4 +- pkg/urbit/jets/e/argon2.c | 172 +++++++++++++++++++---------------- pkg/urcrypt/Makefile | 2 +- pkg/urcrypt/urcrypt.c | 114 +++++++++++++++++++++++ pkg/urcrypt/urcrypt.h | 25 +++++ 6 files changed, 239 insertions(+), 80 deletions(-) diff --git a/nix/pkgs/default.nix b/nix/pkgs/default.nix index 9404cbd9ee..db5120376a 100644 --- a/nix/pkgs/default.nix +++ b/nix/pkgs/default.nix @@ -16,7 +16,7 @@ let urcrypt = import ./urcrypt { inherit pkgs ge-additions; - inherit (deps) ed25519; + inherit (deps) ed25519 argon2; }; libaes_siv = import ./libaes_siv { diff --git a/nix/pkgs/urcrypt/default.nix b/nix/pkgs/urcrypt/default.nix index 592e46cfe3..e81413ca00 100644 --- a/nix/pkgs/urcrypt/default.nix +++ b/nix/pkgs/urcrypt/default.nix @@ -1,9 +1,9 @@ -{ pkgs, ge-additions, ed25519 }: +{ pkgs, ed25519, ge-additions, argon2 }: pkgs.stdenv.mkDerivation rec { name = "urcrypt"; builder = ./builder.sh; src = ../../../pkg/urcrypt; - buildInputs = [ pkgs.openssl ed25519 ge-additions ]; + buildInputs = [ pkgs.openssl ed25519 ge-additions argon2 ]; } diff --git a/pkg/urbit/jets/e/argon2.c b/pkg/urbit/jets/e/argon2.c index 0663304b71..55764b9f60 100644 --- a/pkg/urbit/jets/e/argon2.c +++ b/pkg/urbit/jets/e/argon2.c @@ -2,104 +2,124 @@ ** */ #include "all.h" - -#include +#include /* helpers */ - int argon2_alloc(uint8_t** output, size_t bytes) + static c3_t + _cqear_unpack_word(c3_w *out, u3_atom in) { - *output = u3a_malloc(bytes); - return (NULL != output); + if ( u3r_met(5, in) > 1 ) { + return 0; + } + else { + *out = u3r_word(0, in); + return 1; + } } - void argon2_free(uint8_t* memory, size_t bytes) + static c3_t + _cqear_unpack_size(size_t *out, u3_atom in) { - u3a_free(memory); + c3_w out_w; + if ( _cqear_unpack_word(&out_w, in) ) { + *out = out_w; + return 1; + } + else { + return 0; + } + } + + static c3_t + _cqear_unpack_type(urcrypt_argon2_type *out, u3_atom in) + { + switch ( in ) { + default: + return 0; + case c3__d: + *out = urcrypt_argon2_d; + return 1; + case c3__i: + *out = urcrypt_argon2_i; + return 1; + case c3__id: + *out = urcrypt_argon2_id; + return 1; + case c3__u: + *out = urcrypt_argon2_u; + return 1; + } + } + + static c3_y* + _cqear_unpack_bytes(size_t size, u3_atom in) + { + c3_y* out = u3a_malloc(size); + u3r_bytes(0, (c3_w) size, out, in); + return out; } /* functions */ - u3_noun - u3qe_argon2( // configuration params, + static u3_atom + _cqe_argon2( // configuration params, u3_atom out, u3_atom type, u3_atom version, u3_atom threads, u3_atom mem_cost, u3_atom time_cost, u3_atom wik, u3_atom key, u3_atom wix, u3_atom extra, // input params u3_atom wid, u3_atom dat, u3_atom wis, u3_atom sat ) { - c3_assert( _(u3a_is_cat(out)) && _(u3a_is_cat(type)) && - _(u3a_is_cat(version)) && _(u3a_is_cat(threads)) && - _(u3a_is_cat(mem_cost)) && _(u3a_is_cat(time_cost)) && - _(u3a_is_cat(wik)) && _(u3a_is_cat(wix)) && - _(u3a_is_cat(wid)) && _(u3a_is_cat(wis)) ); + size_t out_sz, key_sz, ex_sz, dat_sz, sat_sz; + c3_w ver_w, ted_w, mem_w, tim_w; + urcrypt_argon2_type typ_u; - // flip endianness for argon2 - key = u3qc_rev(3, wik, key); - extra = u3qc_rev(3, wix, extra); - dat = u3qc_rev(3, wid, dat); - sat = u3qc_rev(3, wis, sat); - - // atoms to byte arrays - c3_y bytes_key[wik]; - u3r_bytes(0, wik, bytes_key, key); - c3_y bytes_extra[wix]; - u3r_bytes(0, wix, bytes_extra, extra); - c3_y bytes_dat[wid]; - u3r_bytes(0, wid, bytes_dat, dat); - c3_y bytes_sat[wis]; - u3r_bytes(0, wis, bytes_sat, sat); - - c3_y outhash[out]; - argon2_context context = { - outhash, // output array, at least [digest length] in size - out, // digest length - bytes_dat, // password array - wid, // password length - bytes_sat, // salt array - wis, // salt length - bytes_key, wik, // optional secret data - bytes_extra, wix, // optional associated data - time_cost, mem_cost, threads, threads, // performance cost configuration - version, // algorithm version - argon2_alloc, // custom memory allocation function - argon2_free, // custom memory deallocation function - ARGON2_DEFAULT_FLAGS // by default only internal memory is cleared - }; - - int argon_res; - switch ( type ) { - default: - u3l_log("\nunjetted argon2 variant %i\n", type); - u3m_bail(c3__exit); - break; - // - case c3__d: - argon_res = argon2d_ctx(&context); - break; - // - case c3__i: - argon_res = argon2i_ctx(&context); - break; - // - case c3__id: - argon_res = argon2id_ctx(&context); - break; - // - case c3__u: - argon_res = argon2u_ctx(&context); - break; + if ( !(_cqear_unpack_size(&out_sz, out) && + _cqear_unpack_type(&typ_u, type) && + _cqear_unpack_word(&ver_w, version) && + _cqear_unpack_word(&ted_w, threads) && + _cqear_unpack_word(&mem_w, mem_cost) && + _cqear_unpack_word(&tim_w, time_cost) && + _cqear_unpack_size(&key_sz, wik) && + _cqear_unpack_size(&ex_sz, wix) && + _cqear_unpack_size(&dat_sz, wid) && + _cqear_unpack_size(&sat_sz, wis)) ) { + u3l_log("%s\r\n", "argon2-punt"); + return u3_none; } + else { + u3_atom ret; + c3_y *key_y = _cqear_unpack_bytes(key_sz, key), + *ex_y = _cqear_unpack_bytes(ex_sz, extra), + *dat_y = _cqear_unpack_bytes(dat_sz, dat), + *sat_y = _cqear_unpack_bytes(sat_sz, sat), + *out_y = u3a_malloc(out_sz); + const c3_c* err_c = urcrypt_argon2( + typ_u, ver_w, ted_w, mem_w, tim_w, + key_sz, key_y, + ex_sz, ex_y, + dat_sz, dat_y, + sat_sz, sat_y, + out_sz, out_y); - if ( ARGON2_OK != argon_res ) { - u3l_log("\nargon2 error: %s\n", argon2_error_message(argon_res)); - u3m_bail(c3__exit); + u3a_free(key_y); + u3a_free(ex_y); + u3a_free(dat_y); + u3a_free(sat_y); + + if ( NULL == err_c ) { + ret = u3i_bytes(out_sz, out_y); + } + else { + ret = u3_none; + u3l_log("argon2-punt: %s\r\n", err_c); + } + + u3a_free(out_y); + return ret; } - - u3z(key); u3z(extra); u3z(dat); u3z(sat); - return u3kc_rev(3, out, u3i_bytes(out, outhash)); } u3_noun @@ -138,7 +158,7 @@ return u3m_bail(c3__exit); } else { - return u3qe_argon2(out, type, version, + return _cqe_argon2(out, type, version, threads, mem_cost, time_cost, wik, key, wix, extra, wid, dat, wis, sat); diff --git a/pkg/urcrypt/Makefile b/pkg/urcrypt/Makefile index 7b2a0ecc30..045b85416e 100644 --- a/pkg/urcrypt/Makefile +++ b/pkg/urcrypt/Makefile @@ -16,7 +16,7 @@ liburcrypt.a: $(SOURCES) liburcrypt.so: $(SOURCES) $(CC) $(CFLAGS) -fPIC -c urcrypt.c -o urcrypt-shared.o $(CC) -shared urcrypt-shared.o -o liburcrypt.so \ - -led25519 -lge-additions -lssl \ + -led25519 -lge-additions -lssl -largon2 \ -Wl,--no-undefined all: liburcrypt.a liburcrypt.so diff --git a/pkg/urcrypt/urcrypt.c b/pkg/urcrypt/urcrypt.c index ff1c72135e..5f1b12d810 100644 --- a/pkg/urcrypt/urcrypt.c +++ b/pkg/urcrypt/urcrypt.c @@ -249,6 +249,14 @@ _urcrypt_reverse_copy(size_t size, const uint8_t *in, uint8_t *out) { } } +static uint8_t* +_urcrypt_reverse_alloc(size_t size, const uint8_t *in) +{ + uint8_t *out = urcrypt_malloc(size); + _urcrypt_reverse_copy(size, in, out); + return out; +} + static void _urcrypt_reverse_inplace(size_t size, uint8_t *ptr) { size_t i, j; @@ -572,3 +580,109 @@ urcrypt_aes_cbcc_de(const uint8_t *message, out_length); } } + +static int +_urcrypt_argon2_alloc(uint8_t** output, size_t bytes) +{ + *output = urcrypt_malloc(bytes); + return (NULL != output); +} + +static void +_urcrypt_argon2_free(uint8_t* memory, size_t bytes) +{ + urcrypt_free(memory); +} + +// library convention is to have sizes in size_t, but argon2 wants them +// in uint32_t, so here's a helper macro for ensuring equivalence. +#define SZ_32(s) ( sizeof(size_t) <= sizeof(uint32_t) || s <= 0xFFFFFFFF ) + +// returns a constant error message string or NULL for success +// (so user doesn't have to call argon2_error_message) +const char* +urcrypt_argon2(urcrypt_argon2_type type, + uint32_t version, + uint32_t threads, + uint32_t memory_cost, + uint32_t time_cost, + size_t secret_length, + const uint8_t *secret, + size_t associated_length, + const uint8_t *associated, + size_t password_length, + const uint8_t *password, + size_t salt_length, + const uint8_t *salt, + size_t out_length, + uint8_t *out) +{ + if ( !( SZ_32(secret_length) && + SZ_32(associated_length) && + SZ_32(password_length) && + SZ_32(salt_length) && + SZ_32(out_length) ) ) { + return "length > 32 bits"; + } + else { + int (*f)(argon2_context*); + int result; + uint8_t *rsecret, *rassoc, *rpassword, *rsalt; + + switch ( type ) { + default: + return "unknown type"; + case urcrypt_argon2_d: + f = &argon2d_ctx; + break; + case urcrypt_argon2_i: + f = &argon2i_ctx; + break; + case urcrypt_argon2_id: + f = &argon2id_ctx; + break; + case urcrypt_argon2_u: + f = &argon2u_ctx; + break; + } + + rsecret = _urcrypt_reverse_alloc(secret_length, secret); + rassoc = _urcrypt_reverse_alloc(associated_length, associated); + rpassword = _urcrypt_reverse_alloc(password_length, password); + rsalt = _urcrypt_reverse_alloc(salt_length, salt); + argon2_context context = { + out, // output array, at least [digest length] in size + out_length, // digest length + rpassword, // password array + password_length, // password length + rsalt, // salt array + salt_length, // salt length + rsecret, // optional secret data + secret_length, + rassoc, // optional associated data + associated_length, + time_cost, // performance cost configuration + memory_cost, + threads, + threads, + version, // algorithm version + &_urcrypt_argon2_alloc,// custom memory allocation function + &_urcrypt_argon2_free, // custom memory deallocation function + ARGON2_DEFAULT_FLAGS // by default only internal memory is cleared + }; + + result = (*f)(&context); + urcrypt_free(rsecret); + urcrypt_free(rassoc); + urcrypt_free(rpassword); + urcrypt_free(rsalt); + + if ( ARGON2_OK != result ) { + return argon2_error_message(result); + } + else { + _urcrypt_reverse_inplace(out_length, out); + return NULL; + } + } +} diff --git a/pkg/urcrypt/urcrypt.h b/pkg/urcrypt/urcrypt.h index 89699d6b0f..da0b2beb35 100644 --- a/pkg/urcrypt/urcrypt.h +++ b/pkg/urcrypt/urcrypt.h @@ -12,6 +12,8 @@ #include #include +#include + typedef void *(*urcrypt_malloc_t)(size_t); typedef void *(*urcrypt_realloc_t)(void*, size_t); typedef void (*urcrypt_free_t)(void*); @@ -104,4 +106,27 @@ uint8_t* urcrypt_aes_cbcc_de(const uint8_t *message, const uint8_t ivec[16], size_t *out_length); +typedef enum urcrypt_argon2_type { + urcrypt_argon2_d = 0, + urcrypt_argon2_i = 1, + urcrypt_argon2_id = 2, + urcrypt_argon2_u = 10, +} urcrypt_argon2_type; + +const char* urcrypt_argon2(urcrypt_argon2_type type, + uint32_t version, + uint32_t threads, + uint32_t memory_cost, + uint32_t time_cost, + size_t secret_length, + const uint8_t *secret, + size_t associated_length, + const uint8_t *associated, + size_t password_length, + const uint8_t *password, + size_t salt_length, + const uint8_t *salt, + size_t out_length, + uint8_t *out); + #endif