diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index 2333c18..5fa1ff0 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -287,7 +287,7 @@ static ErlNifFunc nif_funcs[] = { {"crypto_verify_32", 2, enacl_crypto_verify_32}, {"sodium_memzero", 1, enif_sodium_memzero}, - 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, diff --git a/c_src/pwhash.c b/c_src/pwhash.c index be74851..9f2c5f5 100644 --- a/c_src/pwhash.c +++ b/c_src/pwhash.c @@ -57,16 +57,44 @@ static size_t enacl_pwhash_memlimit(ErlNifEnv *env, ERL_NIF_TERM arg) { return 0; } +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); } @@ -87,7 +115,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 d2a4fff..4e87286 100644 --- a/src/enacl.erl +++ b/src/enacl.erl @@ -116,6 +116,8 @@ shorthash_size/0, shorthash/2, + pwhash/5, + pwhash/4, pwhash_str/3, @@ -395,6 +397,7 @@ generichash_final(State) -> enacl_nif:crypto_generichash_final(State). -type pwhash_limit() :: interactive | moderate | sensitive | pos_integer(). +-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. @@ -416,7 +419,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 f2255f8..04dbb9a 100644 --- a/src/enacl_nif.erl +++ b/src/enacl_nif.erl @@ -147,7 +147,7 @@ %% Password Hashing - Argon2 Algorithm -export([ - crypto_pwhash/4, + crypto_pwhash/5, crypto_pwhash_str/3, crypto_pwhash_str_verify/2 ]). @@ -238,7 +238,7 @@ crypto_secretstream_xchacha20poly1305_init_pull(_Header, _Key) -> erlang:nif_err crypto_secretstream_xchacha20poly1305_pull(_Ref, _CipherText, _AD) -> erlang:nif_error(nif_not_loaded). crypto_secretstream_xchacha20poly1305_rekey(_Ref) -> 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).