This commit is contained in:
Paul Driver 2020-08-10 15:19:32 -07:00
parent fe1375ef6b
commit 6fdc65dea6
6 changed files with 239 additions and 80 deletions

View File

@ -16,7 +16,7 @@ let
urcrypt = import ./urcrypt {
inherit pkgs ge-additions;
inherit (deps) ed25519;
inherit (deps) ed25519 argon2;
};
libaes_siv = import ./libaes_siv {

View File

@ -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 ];
}

View File

@ -2,104 +2,124 @@
**
*/
#include "all.h"
#include <argon2.h>
#include <urcrypt.h>
/* 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);

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -12,6 +12,8 @@
#include <openssl/crypto.h>
#include <openssl/aes.h>
#include <argon2.h>
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