Current section

Files

Jump to
fast_pbkdf2 src fast_pbkdf2.erl
Raw

src/fast_pbkdf2.erl

-module(fast_pbkdf2).
-on_load(load/0).
-nifs([pbkdf2_block/5]).
%% Taken from unexported crypto:sha3().
-type sha3() :: sha3_224 | sha3_256 | sha3_384 | sha3_512.
-type sha_type() :: crypto:sha1() | crypto:sha2() | sha3().
-export([pbkdf2/4, pbkdf2/5]).
%%% @doc
%%% This function calculates the pbkdf2 algorithm where dkLen is simply assumed to be that
%%% of the underlying hash function, a sane default.
-spec pbkdf2(sha_type(), binary(), binary(), non_neg_integer()) -> binary() | {error, atom()}.
pbkdf2(Hash, Password, Salt, IterationCount) ->
pbkdf2_block(Hash, Password, Salt, IterationCount, 1).
%%% @doc
%%% This function allows to customise the desired dkLen parameter for pbkdf2.
-spec pbkdf2(sha_type(), binary(), binary(), non_neg_integer(), non_neg_integer()) ->
binary() | {error, atom()}.
pbkdf2(Hash, Password, Salt, IterationCount, DkLen) ->
pbkdf2(Hash, Password, Salt, IterationCount, DkLen, 1, [], 0).
%%%===================================================================
%%% Helper function
%%%===================================================================
pbkdf2(_Hash, _Password, _Salt, _IterationCount, DkLen, _BlockIndex, Acc, Len) when Len >= DkLen ->
Bin = iolist_to_binary(lists:reverse(Acc)),
binary:part(Bin, 0, DkLen);
pbkdf2(Hash, Password, Salt, IterationCount, DkLen, BlockIndex, Acc, Len) ->
case pbkdf2_block(Hash, Password, Salt, IterationCount, BlockIndex) of
{error, Reason} -> {error, Reason};
Block ->
pbkdf2(Hash, Password, Salt, IterationCount, DkLen, BlockIndex + 1,
[Block | Acc],
byte_size(Block) + Len)
end.
%%%===================================================================
%%% NIF
%%%===================================================================
-spec pbkdf2_block(sha_type(), binary(), binary(), non_neg_integer(), non_neg_integer()) ->
binary() | {error, atom()}.
pbkdf2_block(_Hash, _Password, _Salt, _IterationCount, _BlockSize) ->
erlang:nif_error(not_loaded).
-spec load() -> any().
load() ->
code:ensure_loaded(crypto),
PrivDir = case code:priv_dir(?MODULE) of
{error, _} ->
EbinDir = filename:dirname(code:which(?MODULE)),
AppPath = filename:dirname(EbinDir),
filename:join(AppPath, "priv");
Path ->
Path
end,
erlang:load_nif(filename:join(PrivDir, ?MODULE_STRING), none).