diff --git a/lib/salty/nif.ex b/lib/salty/nif.ex index dce4a24..315e9d6 100644 --- a/lib/salty/nif.ex +++ b/lib/salty/nif.ex @@ -117,6 +117,49 @@ defmodule Salty.Nif do def core_hchacha20(_,_,_), do: :erlang.exit(:salty_nif_not_loaded) def core_hsalsa20(_,_,_), do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_PASSWD_MIN, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_PASSWD_MAX, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_PASSWD_MIN, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_PASSWD_MAX, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_SALTBYTES, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_SALTBYTES, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_STRBYTES, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_STRBYTES, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_OPSLIMIT_MIN, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_OPSLIMIT_MAX, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_OPSLIMIT_MIN, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_OPSLIMIT_MAX, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_MEMLIMIT_MIN, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_MEMLIMIT_MAX, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_MEMLIMIT_MIN, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_MEMLIMIT_MAX, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_OPSLIMIT_INTERACTIVE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_MEMLIMIT_INTERACTIVE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_OPSLIMIT_INTERACTIVE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_MEMLIMIT_INTERACTIVE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_OPSLIMIT_MODERATE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_MEMLIMIT_MODERATE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_OPSLIMIT_MODERATE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_MEMLIMIT_MODERATE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_OPSLIMIT_SENSITIVE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_MEMLIMIT_SENSITIVE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_OPSLIMIT_SENSITIVE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_MEMLIMIT_SENSITIVE, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_ALG_ARGON2I13, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_ALG_ARGON2ID13, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_ALG_ARGON2ID13, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_ALG_ARGON2I13, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_BYTES_MIN, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id_BYTES_MAX, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_BYTES_MIN, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i_BYTES_MAX, do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2id(_,_,_,_,_,_), do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_argon2i(_,_,_,_,_,_), do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_str(_,_,_), do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_str_alg(_,_,_,_), do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_str_verify(_,_), do: :erlang.exit(:salty_nif_not_loaded) + def pwhash_str_needs_rehash(_,_), do: :erlang.exit(:salty_nif_not_loaded) + def generichash_blake2b_BYTES_MIN, do: :erlang.exit(:salty_nif_not_loaded) def generichash_blake2b_BYTES_MAX, do: :erlang.exit(:salty_nif_not_loaded) def generichash_blake2b_BYTES, do: :erlang.exit(:salty_nif_not_loaded) diff --git a/lib/salty/pw_hash.ex b/lib/salty/pw_hash.ex new file mode 100644 index 0000000..8c117e4 --- /dev/null +++ b/lib/salty/pw_hash.ex @@ -0,0 +1,53 @@ +defmodule Salty.PwHash do + defmacro __using__(opts) do + quote do + @behaviour Salty.PwHash + alias Salty.Nif, as: C + end + end + + def primitive do + Salty.PwHash.Argon2id + end + + @callback alg() :: non_neg_integer() + + @callback bytes_min() :: non_neg_integer() + + @callback bytes_max() :: non_neg_integer() + + @callback passwd_min() :: non_neg_integer() + + @callback passwd_max() :: non_neg_integer() + + @callback saltbytes() :: non_neg_integer() + + @callback strbytes() :: non_neg_integer() + + @callback opslimit_min() :: non_neg_integer() + + @callback opslimit_max() :: non_neg_integer() + + @callback memlimit_min() :: non_neg_integer() + + @callback memlimit_max() :: non_neg_integer() + + @callback opslimit_interactive() :: non_neg_integer() + + @callback memlimit_interactive() :: non_neg_integer() + + @callback opslimit_moderate() :: non_neg_integer() + + @callback memlimit_moderate() :: non_neg_integer() + + @callback opslimit_sensitive() :: non_neg_integer() + + @callback memlimit_sensitive() :: non_neg_integer() + + @callback pwhash(non_neg_integer(), binary(), binary(), non_neg_integer(), non_neg_integer(), non_neg_integer()) :: {:ok, binary()} | {:error, atom()} + + # @callback pwhash_str() :: {:ok, binary()} | {:error, atom()} + + # @callback pwhash_str() + +end diff --git a/lib/salty/pw_hash_argon2i.ex b/lib/salty/pw_hash_argon2i.ex new file mode 100644 index 0000000..c40784e --- /dev/null +++ b/lib/salty/pw_hash_argon2i.ex @@ -0,0 +1,75 @@ +defmodule Salty.PwHash.Argon2i do + use Salty.PwHash + + def alg() do + C.pwhash_argon2i_ALG_ARGON2I13() + end + + def bytes_min() do + C.pwhash_argon2i_BYTES_MIN() + end + + def bytes_max() do + C.pwhash_argon2i_BYTES_MAX() + end + + def passwd_min() do + C.pwhash_argon2i_PASSWD_MIN() + end + + def passwd_max() do + C.pwhash_argon2i_PASSWD_MAX() + end + + def saltbytes() do + C.pwhash_argon2i_SALTBYTES() + end + + def strbytes() do + C.pwhash_argon2i_STRBYTES() + end + + def opslimit_min() do + C.pwhash_argon2i_OPSLIMIT_MIN() + end + + def opslimit_max() do + C.pwhash_argon2i_OPSLIMIT_MAX() + end + + def memlimit_min() do + C.pwhash_argon2i_MEMLIMIT_MIN() + end + + def memlimit_max() do + C.pwhash_argon2i_MEMLIMIT_MAX() + end + + def opslimit_interactive() do + C.pwhash_argon2i_OPSLIMIT_INTERACTIVE() + end + + def memlimit_interactive() do + C.pwhash_argon2i_MEMLIMIT_INTERACTIVE() + end + + def opslimit_moderate() do + C.pwhash_argon2i_OPSLIMIT_MODERATE() + end + + def memlimit_moderate() do + C.pwhash_argon2i_MEMLIMIT_MODERATE() + end + + def opslimit_sensitive() do + C.pwhash_argon2i_OPSLIMIT_SENSITIVE() + end + + def memlimit_sensitive() do + C.pwhash_argon2i_MEMLIMIT_SENSITIVE() + end + + def pwhash(outlen, password, salt, opslimit, memlimit, alg \\ alg()) do + C.pwhash_argon2i(outlen, password, salt, opslimit, memlimit, alg) + end +end diff --git a/lib/salty/pw_hash_argon2id.ex b/lib/salty/pw_hash_argon2id.ex new file mode 100644 index 0000000..495894c --- /dev/null +++ b/lib/salty/pw_hash_argon2id.ex @@ -0,0 +1,75 @@ +defmodule Salty.PwHash.Argon2id do + use Salty.PwHash + + def alg() do + C.pwhash_argon2id_ALG_ARGON2ID13() + end + + def bytes_min() do + C.pwhash_argon2id_BYTES_MIN() + end + + def bytes_max() do + C.pwhash_argon2id_BYTES_MAX() + end + + def passwd_min() do + C.pwhash_argon2id_PASSWD_MIN() + end + + def passwd_max() do + C.pwhash_argon2id_PASSWD_MAX() + end + + def saltbytes() do + C.pwhash_argon2id_SALTBYTES() + end + + def strbytes() do + C.pwhash_argon2id_STRBYTES() + end + + def opslimit_min() do + C.pwhash_argon2id_OPSLIMIT_MIN() + end + + def opslimit_max() do + C.pwhash_argon2id_OPSLIMIT_MAX() + end + + def memlimit_min() do + C.pwhash_argon2id_MEMLIMIT_MIN() + end + + def memlimit_max() do + C.pwhash_argon2id_MEMLIMIT_MAX() + end + + def opslimit_interactive() do + C.pwhash_argon2id_OPSLIMIT_INTERACTIVE() + end + + def memlimit_interactive() do + C.pwhash_argon2id_MEMLIMIT_INTERACTIVE() + end + + def opslimit_moderate() do + C.pwhash_argon2id_OPSLIMIT_MODERATE() + end + + def memlimit_moderate() do + C.pwhash_argon2id_MEMLIMIT_MODERATE() + end + + def opslimit_sensitive() do + C.pwhash_argon2id_OPSLIMIT_SENSITIVE() + end + + def memlimit_sensitive() do + C.pwhash_argon2id_MEMLIMIT_SENSITIVE() + end + + def pwhash(outlen, password, salt, opslimit, memlimit, alg \\ alg()) do + C.pwhash_argon2id(outlen, password, salt, opslimit, memlimit, alg) + end +end diff --git a/src/salty_nif.c b/src/salty_nif.c index 30a97f2..3fc6d53 100644 --- a/src/salty_nif.c +++ b/src/salty_nif.c @@ -379,6 +379,26 @@ crypto_onetimeauth_poly1305_final_verify(crypto_onetimeauth_poly1305_state *stat return crypto_verify_16(h, correct); } +int crypto_pwhash_argon2i(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, + unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, size_t memlimit, + int alg) { + return crypto_pwhash(out, outlen, passwd, passwdlen, salt, opslimit, memlimit, alg); +} + +int crypto_pwhash_argon2id(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, + unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, size_t memlimit, + int alg) { + return crypto_pwhash(out, outlen, passwd, passwdlen, salt, opslimit, memlimit, alg); +} + int crypto_secretbox_xsalsa20poly1305_easy(unsigned char *c, const unsigned char *m, @@ -428,7 +448,7 @@ ERL_NIF_TERM atom_primitive_sign;*/ static int salty_onload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { /* register the safe resource types for keys and private data */ - + /* cache atom values */ atom_ok = enif_make_atom(env, "ok"); atom_error = enif_make_atom(env, "error"); @@ -1174,6 +1194,122 @@ SALTY_FUNC(core_hsalsa20, 3) DO SALTY_CALL(crypto_core_hsalsa20(out.data, in.data, key.data, con.data), out); END_OK_WITH(out); +/** + * PWHASH Argon2id + */ +SALTY_CONST_INT64(pwhash_argon2id_ALG_ARGON2ID13); +SALTY_CONST_INT64(pwhash_argon2i_ALG_ARGON2I13); +SALTY_CONST_INT64(pwhash_ALG_ARGON2ID13); +SALTY_CONST_INT64(pwhash_ALG_ARGON2I13); +SALTY_CONST_INT64(pwhash_argon2id_BYTES_MIN); +SALTY_CONST_INT64(pwhash_argon2id_BYTES_MAX); +SALTY_CONST_INT64(pwhash_argon2i_BYTES_MIN); +SALTY_CONST_INT64(pwhash_argon2i_BYTES_MAX); +SALTY_CONST_INT64(pwhash_argon2id_PASSWD_MIN); +SALTY_CONST_INT64(pwhash_argon2id_PASSWD_MAX); +SALTY_CONST_INT64(pwhash_argon2i_PASSWD_MIN); +SALTY_CONST_INT64(pwhash_argon2i_PASSWD_MAX); +SALTY_CONST_INT64(pwhash_argon2id_SALTBYTES); +SALTY_CONST_INT64(pwhash_argon2i_SALTBYTES); +SALTY_CONST_INT64(pwhash_argon2id_STRBYTES); +SALTY_CONST_INT64(pwhash_argon2i_STRBYTES); +SALTY_CONST_INT64(pwhash_argon2id_OPSLIMIT_MIN); +SALTY_CONST_INT64(pwhash_argon2id_OPSLIMIT_MAX); +SALTY_CONST_INT64(pwhash_argon2i_OPSLIMIT_MIN); +SALTY_CONST_INT64(pwhash_argon2i_OPSLIMIT_MAX); +SALTY_CONST_INT64(pwhash_argon2id_OPSLIMIT_INTERACTIVE); +SALTY_CONST_INT64(pwhash_argon2id_MEMLIMIT_INTERACTIVE); +SALTY_CONST_INT64(pwhash_argon2i_OPSLIMIT_INTERACTIVE); +SALTY_CONST_INT64(pwhash_argon2i_MEMLIMIT_INTERACTIVE); +SALTY_CONST_INT64(pwhash_argon2id_OPSLIMIT_MODERATE); +SALTY_CONST_INT64(pwhash_argon2id_MEMLIMIT_MODERATE); +SALTY_CONST_INT64(pwhash_argon2i_OPSLIMIT_MODERATE); +SALTY_CONST_INT64(pwhash_argon2i_MEMLIMIT_MODERATE); +SALTY_CONST_INT64(pwhash_argon2id_OPSLIMIT_SENSITIVE); +SALTY_CONST_INT64(pwhash_argon2id_MEMLIMIT_SENSITIVE); +SALTY_CONST_INT64(pwhash_argon2i_OPSLIMIT_SENSITIVE); +SALTY_CONST_INT64(pwhash_argon2i_MEMLIMIT_SENSITIVE); + +SALTY_FUNC(pwhash_argon2id, 6) DO + SALTY_INPUT_UINT64(0, outlen); + SALTY_INPUT_BIN(1, password, crypto_pwhash_argon2id_PASSWD_MIN); + SALTY_INPUT_BIN(2, salt, crypto_pwhash_argon2id_SALTBYTES); + SALTY_INPUT_UINT64(3, opslimit); + SALTY_INPUT_UINT64(4, memlimit); + SALTY_INPUT_UINT64(5, alg); + + SALTY_OUTPUT_BIN(hash, outlen); + + SALTY_CALL(crypto_pwhash_argon2id( + hash.data, outlen, (const char *) password.data, password.size, salt.data, opslimit, memlimit, alg), + hash); +END_OK_WITH(hash); + +/** + * PWHASH Argon2i + */ +SALTY_FUNC(pwhash_argon2i, 6) DO + SALTY_INPUT_UINT64(0, outlen); + SALTY_INPUT_BIN(1, password, crypto_pwhash_argon2i_PASSWD_MIN); + SALTY_INPUT_BIN(2, salt, crypto_pwhash_argon2i_SALTBYTES); + SALTY_INPUT_UINT64(3, opslimit); + SALTY_INPUT_UINT64(4, memlimit); + SALTY_INPUT_UINT64(5, alg); + + SALTY_OUTPUT_BIN(hash, outlen); + + SALTY_CALL(crypto_pwhash_argon2i( + hash.data, outlen, (const char *) password.data, password.size, salt.data, opslimit, memlimit, alg), + hash); +END_OK_WITH(hash); + +SALTY_FUNC(pwhash_str, 3) DO + SALTY_INPUT_BIN(0, password, crypto_pwhash_argon2id_PASSWD_MIN); + SALTY_INPUT_UINT64(1, opslimit); + SALTY_INPUT_UINT64(2, memlimit); + + SALTY_OUTPUT_BIN(hash, crypto_pwhash_argon2id_STRBYTES); + + SALTY_CALL(crypto_pwhash_str( + (char *) hash.data, (const char *) password.data, password.size, + opslimit, memlimit), + hash); +END_OK_WITH(hash); + +SALTY_FUNC(pwhash_str_alg, 4) DO + SALTY_INPUT_BIN(0, password, crypto_pwhash_argon2id_PASSWD_MIN); + SALTY_INPUT_UINT64(1, opslimit); + SALTY_INPUT_UINT64(2, memlimit); + SALTY_INPUT_UINT64(3, alg); + + SALTY_OUTPUT_BIN(hash, crypto_pwhash_argon2i_STRBYTES); + + SALTY_CALL(crypto_pwhash_str_alg( + (char *) hash.data, (const char *) password.data, password.size, + opslimit, memlimit, alg), + hash); +END_OK_WITH(hash); + +SALTY_FUNC(pwhash_str_verify, 2) DO + SALTY_INPUT_BIN(0, str, crypto_pwhash_argon2id_PASSWD_MIN); + SALTY_INPUT_BIN(1, password, crypto_pwhash_argon2id_PASSWD_MIN); + + SALTY_OUTPUT_BIN(hash, crypto_pwhash_argon2i_STRBYTES); + + SALTY_CALL(crypto_pwhash_str_verify( + (char *) str.data, (const char *) password.data, password.size), + hash); +END_OK_WITH(hash); + +SALTY_FUNC(pwhash_str_needs_rehash, 2) DO + SALTY_INPUT_UINT64(1, opslimit); + SALTY_INPUT_UINT64(2, memlimit); + + SALTY_OUTPUT_BIN(hash, crypto_pwhash_argon2i_STRBYTES); + + SALTY_CALL(crypto_pwhash_str_needs_rehash((char *) hash.data, opslimit, memlimit), hash); +END_OK_WITH(hash); + /** * GENERICHASH Blake2b */ @@ -2030,7 +2166,7 @@ salty_exports[] = { SALTY_EXPORT_FUNC(aead_chacha20poly1305_encrypt, 5), SALTY_EXPORT_FUNC(aead_chacha20poly1305_encrypt_detached, 5), SALTY_EXPORT_FUNC(aead_chacha20poly1305_decrypt_detached, 6), - + SALTY_EXPORT_CONS(aead_chacha20poly1305_ietf_KEYBYTES, 0), SALTY_EXPORT_CONS(aead_chacha20poly1305_ietf_NSECBYTES, 0), SALTY_EXPORT_CONS(aead_chacha20poly1305_ietf_NPUBBYTES, 0), @@ -2170,6 +2306,45 @@ salty_exports[] = { SALTY_EXPORT_FUNC(onetimeauth_poly1305_final, 1), SALTY_EXPORT_FUNC(onetimeauth_poly1305_final_verify, 2), + SALTY_EXPORT_CONS(pwhash_argon2id_PASSWD_MIN, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_PASSWD_MAX, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_PASSWD_MIN, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_PASSWD_MAX, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_SALTBYTES, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_SALTBYTES, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_OPSLIMIT_MIN, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_OPSLIMIT_MAX, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_OPSLIMIT_MIN, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_OPSLIMIT_MAX, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_OPSLIMIT_INTERACTIVE, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_MEMLIMIT_INTERACTIVE, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_OPSLIMIT_INTERACTIVE, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_MEMLIMIT_INTERACTIVE, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_OPSLIMIT_MODERATE, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_MEMLIMIT_MODERATE, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_OPSLIMIT_MODERATE, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_MEMLIMIT_MODERATE, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_OPSLIMIT_SENSITIVE, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_MEMLIMIT_SENSITIVE, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_OPSLIMIT_SENSITIVE, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_MEMLIMIT_SENSITIVE, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_STRBYTES, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_STRBYTES, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_ALG_ARGON2I13, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_ALG_ARGON2ID13, 0), + SALTY_EXPORT_CONS(pwhash_ALG_ARGON2ID13, 0), + SALTY_EXPORT_CONS(pwhash_ALG_ARGON2I13, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_BYTES_MIN, 0), + SALTY_EXPORT_CONS(pwhash_argon2id_BYTES_MAX, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_BYTES_MIN, 0), + SALTY_EXPORT_CONS(pwhash_argon2i_BYTES_MAX, 0), + SALTY_EXPORT_FUNC(pwhash_argon2id, 6), + SALTY_EXPORT_FUNC(pwhash_argon2i, 6), + SALTY_EXPORT_FUNC(pwhash_str, 3), + SALTY_EXPORT_FUNC(pwhash_str_alg, 4), + SALTY_EXPORT_FUNC(pwhash_str_verify, 2), + SALTY_EXPORT_FUNC(pwhash_str_needs_rehash, 2), + SALTY_EXPORT_CONS(scalarmult_curve25519_BYTES, 0), SALTY_EXPORT_CONS(scalarmult_curve25519_SCALARBYTES, 0), SALTY_EXPORT_FUNC(scalarmult_curve25519_base, 1),