Current section

Files

Jump to
argon2_elixir lib argon2.ex
Raw

lib/argon2.ex

defmodule Argon2 do
@moduledoc """
Elixir wrapper for the Argon2 password hashing algorithm.
"""
@compile {:autoload, false}
@on_load {:init, 0}
def init do
path = :filename.join(:code.priv_dir(:argon2_elixir), 'argon2_nif')
:erlang.load_nif(path, 0)
end
@doc """
Generate a random salt.
"""
def gen_salt(salt_len \\ 16), do: :crypto.strong_rand_bytes(salt_len)
def argon2_hash_nif(t_cost, m_cost, parallelism, password, salt, hashlen, encoded, argon2_type)
def argon2_hash_nif(_, _, _, _, _, _, _, _), do: exit(:nif_library_not_loaded)
def argon2_verify_nif(stored_hash, password, argon2_type)
def argon2_verify_nif(_, _, _), do: exit(:nif_library_not_loaded)
@doc """
Hash a password using Argon2.
"""
def hash_password(password, salt, opts \\ [])
def hash_password(_, salt, _) when byte_size(salt) < 8 do
raise ArgumentError, "The salt is too short - it should be 8 characters or longer"
end
def hash_password(password, salt, opts) do
argon2_hash_nif(Keyword.get(opts, :t_cost, 3),
Keyword.get(opts, :m_cost, 12),
Keyword.get(opts, :parallelism, 1),
password,
salt,
Keyword.get(opts, :hashlen, 32),
Keyword.get(opts, :encoded, 1),
Keyword.get(opts, :argon2_type, 1))
|> :binary.list_to_bin
end
@doc """
Generate a random salt and hash a password using Argon2.
"""
def hash_pwd_salt(password, opts \\ []) do
salt = Keyword.get(opts, :salt_len, 16) |> gen_salt
hash_password(password, salt, opts)
end
@doc """
Verify an encoded Argon2 hash.
"""
def verify_hash(stored_hash, password, opts \\ []) do
hash = :binary.bin_to_list(stored_hash)
case argon2_verify_nif(hash, password, Keyword.get(opts, :argon2_type, 1)) do
0 -> true
_ -> false
end
end
end