Comeonin v4.0.2 Comeonin.Argon2 View Source
Password hashing module using the Argon2 algorithm.
For more information about the Argon2 algorithm, see the Choosing
an algorithm
section in the Comeonin docs.
For a lower-level API, see Argon2.Base
.
Link to this section Summary
Functions
Hash a password and return it in a map, with the password set to nil
Check the password by comparing its hash with the password hash found in a user struct, or map
Check the password by comparing it with the stored hash
Run a dummy check, which always returns false, to make user enumeration more difficult
Hash the password with a randomly-generated salt
Print out a report to help you configure the hash function
Link to this section Functions
Hash a password and return it in a map, with the password set to nil.
Options
This function uses Argon2.hash_pwd_salt
as the hashing function.
In addition to the options for hash_pwd_salt, there is also the following
option:
hash_key - the name of the key for the password hash
- the default is :password_hash
Example with Ecto
In this example, the create_changeset
function below shows how a new
user can be created:
def create_changeset(%User{} = user, attrs) do
user
|> changeset(attrs)
|> validate_password(:password)
|> put_pass_hash()
end
The validating the password
section will then look at writing
a custom validator (validate_password), and the adding the password hash
section will cover the use of the add_hash
function (in put_pass_hash).
Validating the password
This section can be skipped if you are using a frontend solution to validating the password.
The following is a basic example of the validate_password
function:
def validate_password(changeset, field, options \ []) do
validate_change(changeset, field, fn _, password ->
case valid_password?(password) do
{:ok, _} -> []
{:error, msg} -> [{field, options[:message] || msg}]
end
end)
end
In the example below, the valid_password?
function checks that
the password is at least 8 characters long.
defp valid_password?(password) when byte_size(password) > 7 do
{:ok, password}
end
defp valid_password?(_), do: {:error, "The password is too short"}
Alternatively, you could use a dedicated password strength checker,
such as not_qwerty123
.
For more information about password strength rules, see the latest NIST guidelines.
Adding the password hash
In the following example, add_hash
is used in the put_pass_hash
function:
defp put_pass_hash(%Ecto.Changeset{valid?: true, changes:
%{password: password}} = changeset) do
change(changeset, Comeonin.Argon2.add_hash(password))
end
defp put_pass_hash(changeset), do: changeset
Check the password by comparing its hash with the password hash found in a user struct, or map.
The password hash’s key needs to be either :password_hash
or
:encrypted_password
.
After finding the password hash in the user struct, the password is checked by comparing it with the hash. Then the function returns {:ok, user} or {:error, message}. Note that the error message is meant to be used for logging purposes only; it should not be passed on to the end user.
If the first argument is nil, meaning that there is no user with that
name, a dummy verify function is run to make user enumeration, using
timing information, more difficult. This can be disabled by adding
hide_user: false
to the opts.
Examples
The following is a simple example using Phoenix 1.3:
def verify(attrs) do
MyApp.Accounts.get_by(attrs)
|> Comeonin.Argon2.check_pass(password)
end
Check the password by comparing it with the stored hash.
For more details, see the documentation for Argon2.verify_pass
.
Run a dummy check, which always returns false, to make user enumeration more difficult.
For more details, see the documentation for Argon2.no_user_verify
.
Hash the password with a randomly-generated salt.
For more details, see the documentation for Argon2.hash_pwd_salt
and Argon2.Base.hash_password
.
Print out a report to help you configure the hash function.
For more details, see the documentation for Argon2.Stats.report
.