Current section
Files
Jump to
Current section
Files
lib/secrets.ex
defmodule TwoFactorInACan.Secrets do
@moduledoc """
Functions for generating cryptographic secrets.
"""
@type secret_generation_opts :: keyword(atom() | integer())
@default_totp_secret_byte_size 20
@doc """
Generates a secret suitable for use in time based one time password (TOTP)
two factor authentication.
Generates a 160-bit key which is the size recommended by RFC4226
(https://www.ietf.org/rfc/rfc4226.txt).
By default, outputs a raw binary key with no encoding. The `:format` key can
be used to specify alternate output formats. Valid formats include:
- `:binary` (default)
- `:base32`
- `:base64`
# Examples
iex> TwoFactorInACan.Secrets.generate_totp_secret()
<<195, 110, 253, 36, 185, 138, 174, 16, 54, 176, 135, 67, 97, 11, 159, 63, 75, 80, 65, 6>>
iex> TwoFactorInACan.Secrets.generate_totp_secret(format: :base32)
"F2EJJEYSJA67QHI6DEAI2I6AGCEG7G5E"
iex> TwoFactorInACan.Secrets.generate_totp_secret(format: :base64)
"xKXOSYcRVlHfnazLMlRinpb252U="
"""
@spec generate_totp_secret(secret_generation_opts) :: binary()
def generate_totp_secret(opts \\ []) do
@default_totp_secret_byte_size
|> :crypto.strong_rand_bytes()
|> format_secret(opts)
end
@spec format_secret(binary(), secret_generation_opts) :: binary()
defp format_secret(secret, opts) do
format = Keyword.get(opts, :format, :binary)
case format do
:binary -> secret
:base32 -> Base.encode32(secret)
:base64 -> Base.encode64(secret)
_ -> raise ArgumentError, """
Invalid format supplied when generating secret:
format: #{format}
Valid options include:
- :binary
- :base32
- :base64
"""
end
end
end