diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 2119fa5..bf5c613 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -13,8 +13,8 @@ #include "pwhash.h" #include "randombytes.h" #include "secret.h" -#include "sign.h" #include "secretstream.h" +#include "sign.h" #ifdef ERL_NIF_DIRTY_JOB_CPU_BOUND #define erl_nif_dirty_job_cpu_bound_macro(a, b, c) \ @@ -288,7 +288,7 @@ static ErlNifFunc nif_funcs[] = { {"sodium_memzero", 1, enif_sodium_memzero}, {"crypto_pwhash_SALTBYTES", 0, enacl_crypto_pwhash_SALTBYTES}, - erl_nif_dirty_job_cpu_bound_macro("crypto_pwhash", 4, enacl_crypto_pwhash), + erl_nif_dirty_job_cpu_bound_macro("crypto_pwhash", 5, enacl_crypto_pwhash), erl_nif_dirty_job_cpu_bound_macro("crypto_pwhash_str", 3, enacl_crypto_pwhash_str), erl_nif_dirty_job_cpu_bound_macro("crypto_pwhash_str_verify", 2, @@ -380,22 +380,35 @@ static ErlNifFunc nif_funcs[] = { erl_nif_dirty_job_cpu_bound_macro("crypto_generichash_final", 1, enacl_crypto_generichash_final), - {"crypto_secretstream_xchacha20poly1305_ABYTES", 0, enacl_crypto_secretstream_xchacha20poly1305_ABYTES}, - {"crypto_secretstream_xchacha20poly1305_HEADERBYTES", 0, enacl_crypto_secretstream_xchacha20poly1305_HEADERBYTES}, - {"crypto_secretstream_xchacha20poly1305_KEYBYTES", 0, enacl_crypto_secretstream_xchacha20poly1305_KEYBYTES}, - {"crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX", 0, enacl_crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX}, - {"crypto_secretstream_xchacha20poly1305_TAG_MESSAGE", 0, enacl_crypto_secretstream_xchacha20poly1305_TAG_MESSAGE}, - {"crypto_secretstream_xchacha20poly1305_TAG_PUSH", 0, enacl_crypto_secretstream_xchacha20poly1305_TAG_PUSH}, - {"crypto_secretstream_xchacha20poly1305_TAG_REKEY", 0, enacl_crypto_secretstream_xchacha20poly1305_TAG_REKEY}, - {"crypto_secretstream_xchacha20poly1305_TAG_FINAL", 0, enacl_crypto_secretstream_xchacha20poly1305_TAG_FINAL}, - {"crypto_secretstream_xchacha20poly1305_keygen", 0, enacl_crypto_secretstream_xchacha20poly1305_keygen}, - {"crypto_secretstream_xchacha20poly1305_init_push", 1, enacl_crypto_secretstream_xchacha20poly1305_init_push}, - {"crypto_secretstream_xchacha20poly1305_init_pull", 2, enacl_crypto_secretstream_xchacha20poly1305_init_pull}, - {"crypto_secretstream_xchacha20poly1305_rekey", 1, enacl_crypto_secretstream_xchacha20poly1305_rekey}, - erl_nif_dirty_job_cpu_bound_macro("crypto_secretstream_xchacha20poly1305_push", 4, + {"crypto_secretstream_xchacha20poly1305_ABYTES", 0, + enacl_crypto_secretstream_xchacha20poly1305_ABYTES}, + {"crypto_secretstream_xchacha20poly1305_HEADERBYTES", 0, + enacl_crypto_secretstream_xchacha20poly1305_HEADERBYTES}, + {"crypto_secretstream_xchacha20poly1305_KEYBYTES", 0, + enacl_crypto_secretstream_xchacha20poly1305_KEYBYTES}, + {"crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX", 0, + enacl_crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX}, + {"crypto_secretstream_xchacha20poly1305_TAG_MESSAGE", 0, + enacl_crypto_secretstream_xchacha20poly1305_TAG_MESSAGE}, + {"crypto_secretstream_xchacha20poly1305_TAG_PUSH", 0, + enacl_crypto_secretstream_xchacha20poly1305_TAG_PUSH}, + {"crypto_secretstream_xchacha20poly1305_TAG_REKEY", 0, + enacl_crypto_secretstream_xchacha20poly1305_TAG_REKEY}, + {"crypto_secretstream_xchacha20poly1305_TAG_FINAL", 0, + enacl_crypto_secretstream_xchacha20poly1305_TAG_FINAL}, + {"crypto_secretstream_xchacha20poly1305_keygen", 0, + enacl_crypto_secretstream_xchacha20poly1305_keygen}, + {"crypto_secretstream_xchacha20poly1305_init_push", 1, + enacl_crypto_secretstream_xchacha20poly1305_init_push}, + {"crypto_secretstream_xchacha20poly1305_init_pull", 2, + enacl_crypto_secretstream_xchacha20poly1305_init_pull}, + {"crypto_secretstream_xchacha20poly1305_rekey", 1, + enacl_crypto_secretstream_xchacha20poly1305_rekey}, + erl_nif_dirty_job_cpu_bound_macro( + "crypto_secretstream_xchacha20poly1305_push", 4, enacl_crypto_secretstream_xchacha20poly1305_push), - erl_nif_dirty_job_cpu_bound_macro("crypto_secretstream_xchacha20poly1305_pull", 3, - enacl_crypto_secretstream_xchacha20poly1305_pull) -}; + erl_nif_dirty_job_cpu_bound_macro( + "crypto_secretstream_xchacha20poly1305_pull", 3, + enacl_crypto_secretstream_xchacha20poly1305_pull)}; ERL_NIF_INIT(enacl_nif, nif_funcs, enacl_crypto_load, NULL, NULL, NULL); diff --git a/c_src/pwhash.c b/c_src/pwhash.c index f4ae2dc..fc49c91 100644 --- a/c_src/pwhash.c +++ b/c_src/pwhash.c @@ -57,22 +57,49 @@ static size_t enacl_pwhash_memlimit(ErlNifEnv *env, ERL_NIF_TERM arg) { return 0; } - ERL_NIF_TERM enacl_crypto_pwhash_SALTBYTES(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { return enif_make_int64(env, crypto_pwhash_SALTBYTES); } +static int enacl_pwhash_alg(ErlNifEnv *env, ERL_NIF_TERM arg) { + ERL_NIF_TERM a; + int r; + + if (enif_is_atom(env, arg)) { + a = enif_make_atom(env, "default"); + if (enif_is_identical(a, arg)) { + return crypto_pwhash_ALG_DEFAULT; + } + + a = enif_make_atom(env, "argon2i13"); + if (enif_is_identical(a, arg)) { + return crypto_pwhash_ALG_ARGON2I13; + } + + a = enif_make_atom(env, "argon2id13"); + if (enif_is_identical(a, arg)) { + return crypto_pwhash_ALG_ARGON2ID13; + } + } else if (enif_get_int(env, arg, &r)) { + return r; + } + + return 0; +} + ERL_NIF_TERM enacl_crypto_pwhash(ErlNifEnv *env, int argc, ERL_NIF_TERM const argv[]) { ErlNifBinary h, p, s; size_t o, m; + int alg; // Validate the arguments - if ((argc != 4) || (!enif_inspect_iolist_as_binary(env, argv[0], &p)) || + if ((argc != 5) || (!enif_inspect_iolist_as_binary(env, argv[0], &p)) || (!enif_inspect_binary(env, argv[1], &s)) || !(o = enacl_pwhash_opslimit(env, argv[2])) || - !(m = enacl_pwhash_memlimit(env, argv[3]))) { + !(m = enacl_pwhash_memlimit(env, argv[3])) || + !(alg = enacl_pwhash_alg(env, argv[4]))) { return enif_make_badarg(env); } @@ -93,7 +120,7 @@ ERL_NIF_TERM enacl_crypto_pwhash(ErlNifEnv *env, int argc, } if (crypto_pwhash(h.data, h.size, (char *)p.data, p.size, s.data, o, m, - crypto_pwhash_ALG_DEFAULT) != 0) { + alg) != 0) { /* out of memory */ enif_release_binary(&h); return enacl_internal_error(env); diff --git a/src/enacl.erl b/src/enacl.erl index 91c29fd..504d9cb 100644 --- a/src/enacl.erl +++ b/src/enacl.erl @@ -117,11 +117,11 @@ shorthash/2, pwhash_SALTBYTES/0, - pwhash/4, - pwhash_str/3, - pwhash/2, + pwhash/4, + pwhash/5, pwhash_str/1, + pwhash_str/3, pwhash_str_verify/2 ]). @@ -403,6 +403,7 @@ generichash_final(State) -> pwhash_SALTBYTES() -> enacl_nif:crypto_pwhash_SALTBYTES(). +-type pwhash_alg() :: default | argon2i13 | argon2id13 | pos_integer(). %% @doc pwhash/2 hash a password %% %% This function generates a fixed size salted hash of a user defined password. @@ -424,7 +425,22 @@ pwhash(Password, Salt) -> Ops :: pwhash_limit(), Mem :: pwhash_limit(). pwhash(Password, Salt, Ops, Mem) -> - enacl_nif:crypto_pwhash(Password, Salt, Ops, Mem). + enacl_nif:crypto_pwhash(Password, Salt, Ops, Mem, default). + +%% @doc pwhash/5 hash a password +%% +%% This function generates a fixed size salted hash of a user defined password given Ops and Mem +%% limits. +%% @end +-spec pwhash(Password, Salt, Ops, Mem, Alg) -> binary() + when + Password :: iodata(), + Salt :: binary(), + Ops :: pwhash_limit(), + Mem :: pwhash_limit(), + Alg :: pwhash_alg(). +pwhash(Password, Salt, Ops, Mem, Alg) -> + enacl_nif:crypto_pwhash(Password, Salt, Ops, Mem, Alg). %% @doc pwhash_str/1 generates a ASCII encoded hash of a password %% diff --git a/src/enacl_nif.erl b/src/enacl_nif.erl index 417ab25..7ec9c91 100644 --- a/src/enacl_nif.erl +++ b/src/enacl_nif.erl @@ -148,7 +148,7 @@ %% Password Hashing - Argon2 Algorithm -export([ crypto_pwhash_SALTBYTES/0, - crypto_pwhash/4, + crypto_pwhash/5, crypto_pwhash_str/3, crypto_pwhash_str_verify/2 ]). @@ -240,7 +240,7 @@ crypto_secretstream_xchacha20poly1305_pull(_Ref, _CipherText, _AD) -> erlang:nif crypto_secretstream_xchacha20poly1305_rekey(_Ref) -> erlang:nif_error(nif_not_loaded). crypto_pwhash_SALTBYTES() -> erlang:nif_error(nif_not_loaded). -crypto_pwhash(_Password, _Salt, _Ops, _Mem) -> erlang:nif_error(nif_not_loaded). +crypto_pwhash(_Password, _Salt, _Ops, _Mem, _Alg) -> erlang:nif_error(nif_not_loaded). crypto_pwhash_str(_Password, _Ops, _Mem) -> erlang:nif_error(nif_not_loaded). crypto_pwhash_str_verify(_HashedPassword, _Password) -> erlang:nif_error(nif_not_loaded).