Packages

Gleam bindings to fast_pbkdf2 NIF of PBKDF2 (Password-Based Key Derivation Function 2) for Erlang.

Current section

Files

Jump to
pinkdf2 src pinkdf2.erl
Raw

src/pinkdf2.erl

-module(pinkdf2).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([get_salt/0, with_defaults/2, with_config/5]).
-export_type([pbkdf2_keys/0, pbkdf2_algorithm/0, pbkdf2_error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(" Gleam bindings to fast_pbkdf2 NIF of PBKDF2 (Password-Based Key Derivation Function 2) for Erlang.\n").
-type pbkdf2_keys() :: {pbkdf2_keys, bitstring(), binary()}.
-type pbkdf2_algorithm() :: sha224 | sha256 | sha384 | sha512.
-type pbkdf2_error() :: iterations_value_not_positive |
derived_key_length_value_not_positive.
-file("src/pinkdf2.gleam", 67).
?DOC(
" Generates a base64-encoded salt with a minimum size of 64 bytes.\n"
" It is provided here for convenience, but it is based on the same underlying Erlang function as `crypto.strong_rand_bytes`.\n"
).
-spec get_salt() -> binary().
get_salt() ->
extern:get_salt().
-file("src/pinkdf2.gleam", 69).
-spec map_algorithm(pbkdf2_algorithm()) -> gleam@crypto:hash_algorithm().
map_algorithm(Alg) ->
case Alg of
sha224 ->
sha224;
sha256 ->
sha256;
sha384 ->
sha384;
sha512 ->
sha512
end.
-file("src/pinkdf2.gleam", 78).
-spec is_positive(integer()) -> boolean().
is_positive(Num) ->
Num > 0.
-file("src/pinkdf2.gleam", 24).
?DOC(
" Derives a key from a password and salt with default settings based on the\n"
" (OWASP recommendations)[https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2].\n"
).
-spec with_defaults(binary(), binary()) -> {ok, pbkdf2_keys()} |
{error, pbkdf2_error()}.
with_defaults(Password, Salt) ->
Raw = extern:fp_with_defaults(Password, Salt),
{ok, {pbkdf2_keys, Raw, gleam_stdlib:bit_array_base64_encode(Raw, false)}}.
-file("src/pinkdf2.gleam", 45).
?DOC(
" Derives a key using the provided configuration.\n"
"\n"
" `iterations` is the number of times to run the algorithm. Must be a positive integer.\n"
" `d_len` is the target derived key length in bytes. Must be a positive integer.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" import pinkdf2.{Sha512}\n"
"\n"
" let salt = pinkdf2.get_salt()\n"
" let assert Ok(key) = pinkdf2.with_config(Sha512, \"password\", salt, 210_000, 32)\n"
" ```\n"
).
-spec with_config(pbkdf2_algorithm(), binary(), binary(), integer(), integer()) -> {ok,
pbkdf2_keys()} |
{error, pbkdf2_error()}.
with_config(Alg, Password, Salt, Iterations, D_len) ->
case {is_positive(Iterations), is_positive(D_len)} of
{false, _} ->
{error, iterations_value_not_positive};
{_, false} ->
{error, derived_key_length_value_not_positive};
{_, _} ->
Raw = begin
_pipe = map_algorithm(Alg),
fast_pbkdf2:pbkdf2(_pipe, Password, Salt, Iterations, D_len)
end,
{ok,
{pbkdf2_keys,
Raw,
gleam_stdlib:bit_array_base64_encode(Raw, false)}}
end.