Current section

Files

Jump to
argon2_elixir lib argon2 stats.ex
Raw

lib/argon2/stats.ex

defmodule Argon2.Stats do
@moduledoc """
Module to provide statistics for the Argon2 password hashing function.
The default parameters are:
* t_cost: 6
* m_cost: 16 (64 MiB of memory)
* parallelism: 1
However, the parameters you use depend a lot on the hardware you are
using, and so it is important to measure the function's running time
and adjust the parameters accordingly.
Below is a guide on how to choose the parameters and what kind of
running time is recommended.
## Choosing parameters
1. Decide how much memory the function should use
2. Decide how many threads to use
3. Set the t_cost to 3 and measure the time it takes to hash a password
* If the function is too slow, reduce memory usage, but keep t_cost at 3
* If the function is too fast, increase the t_cost
For online use - for example, logging in on a website - the function should
take anything between 250 milliseconds and one second. For a desktop
application, the function could take longer, anything from several seconds
to 5 seconds, as long as the user only has to log in once per session.
These numbers are based on the [libsodium documentation for
Argon2i](https://download.libsodium.org/doc/password_hashing/the_argon2i_function.html)
and the previous
[NIST recommendations](http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf).
"""
alias Argon2.Base
@doc """
Hash a password with Argon2 and print out a report.
This function hashes the password and salt with Argon2.Base.hash_password/3
and prints out statistics which can help you choose how to configure Argon2.
## Options
In addition to the options for Argon2.Base.hash_password/3, there are
also the following options:
* `:password` - the password used
* the default is "password"
* `:salt` - the salt used
* the default is "somesaltSOMESALT"
"""
def report(opts \\ []) do
password = Keyword.get(opts, :password, "password")
salt = Keyword.get(opts, :salt, "somesaltSOMESALT")
{exec_time, result} =
:timer.tc(Base, :hash_password, [password, salt, [format: :report] ++ opts])
{raw, encoded, {t, m, p, _, argon2_type}} = result
Argon2.verify_pass(password, encoded)
|> format_result(argon2_type, t, m, p, raw, encoded, exec_time)
end
defp format_result(check, argon2_type, t, m, p, raw, encoded, exec_time) do
IO.puts("""
Type:\t\t#{format_type(argon2_type)}
Iterations:\t#{t}
Memory:\t\t#{trunc(:math.pow(2, m - 10))} MiB
Parallelism:\t#{p}
Hash:\t\t#{raw}
Encoded:\t#{encoded}
Time taken:\t#{format_time(exec_time)} seconds
Verification #{if check, do: "OK", else: "FAILED"}
""")
end
defp format_type(0), do: "Argon2d"
defp format_type(1), do: "Argon2i"
defp format_type(2), do: "Argon2id"
defp format_time(time) do
Float.round(time / 1_000_000, 2)
end
end