Skip to content

Commit

Permalink
Fixed to_hex to return binary if it gets a binary, and removed the ab…
Browse files Browse the repository at this point in the history
…ility to pass arbitrary digest functions, since crypto:hmac doesn't support it.
  • Loading branch information
whitelynx committed Mar 3, 2013
1 parent 9d9946e commit 267eb2c
Showing 1 changed file with 45 additions and 66 deletions.
111 changes: 45 additions & 66 deletions src/pbkdf2.erl
Expand Up @@ -19,20 +19,10 @@
-type(hex_char() :: 48 .. 57 | 97 .. 102).
-type(hex_list() :: [hex_char()]).

-type digest_func() :: fun((Data :: binary()) -> Hash :: binary()).

%-type mac_func() :: fun((Key :: binary(), Data :: binary(), MacLength :: integer()) -> Mac :: binary()).
-type mac_func() :: fun((Key :: binary(), Data :: binary()) -> Mac :: binary()).
-type digest_func_info() :: md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512.

-type(digest_func_info() ::
digest_func() | {digest_func(), DigestLength :: integer()}
| md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512
).

-type(mac_func_info() ::
mac_func() | {hmac, digest_func_info()}
| md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512
).
-type mac_func_info() :: {hmac, digest_func_info()} | digest_func_info().


-define(MAX_DERIVED_KEY_LENGTH, (1 bsl 32 - 1)).
Expand All @@ -50,7 +40,7 @@
pbkdf2(MacFunc, Password, Salt, Iterations) ->
MacFunc1 = resolve_mac_func(MacFunc),
DerivedLength = byte_size(MacFunc1(<<"test key">>, <<"test data">>)),
pbkdf2(MacFunc1, Password, Salt, Iterations, DerivedLength, 1, []).
pbkdf2(MacFunc1, Password, Salt, Iterations, DerivedLength, 1, []).

%----------------------------------------------------------------------------------------------------------------------

Expand All @@ -63,12 +53,12 @@ pbkdf2(MacFunc, Password, Salt, Iterations) ->
Key :: binary().

pbkdf2(_MacFunc, _Password, _Salt, _Iterations, DerivedLength) when DerivedLength > ?MAX_DERIVED_KEY_LENGTH ->
{error, derived_key_too_long};
{error, derived_key_too_long};

pbkdf2(MacFunc, Password, Salt, Iterations, DerivedLength) ->
MacFunc1 = resolve_mac_func(MacFunc),
Bin = pbkdf2(MacFunc1, Password, Salt, Iterations, DerivedLength, 1, []),
{ok, Bin}.
Bin = pbkdf2(MacFunc1, Password, Salt, Iterations, DerivedLength, 1, []),
{ok, Bin}.

%======================================================================================================================
% Internal Functions
Expand All @@ -83,13 +73,15 @@ pbkdf2(MacFunc, Password, Salt, Iterations, DerivedLength) ->
Acc :: iolist(),
Key :: binary().

pbkdf2(_MacFunc, _Password, _Salt, _Iterations, DerivedLength, _BlockIndex, Acc) when length(Acc) > DerivedLength ->
<<Bin:DerivedLength/binary, _/binary>> = iolist_to_binary(lists:reverse(Acc)),
Bin;

pbkdf2(MacFunc, Password, Salt, Iterations, DerivedLength, BlockIndex, Acc) ->
Block = pbkdf2(MacFunc, Password, Salt, Iterations, BlockIndex, 1, <<>>, <<>>),
pbkdf2(MacFunc, Password, Salt, Iterations, DerivedLength, BlockIndex + 1, [Block | Acc]).
case iolist_size(Acc) > DerivedLength of
true ->
<<Bin:DerivedLength/binary, _/binary>> = iolist_to_binary(lists:reverse(Acc)),
Bin;
false ->
Block = pbkdf2(MacFunc, Password, Salt, Iterations, BlockIndex, 1, <<>>, <<>>),
pbkdf2(MacFunc, Password, Salt, Iterations, DerivedLength, BlockIndex + 1, [Block | Acc])
end.

%----------------------------------------------------------------------------------------------------------------------

Expand All @@ -105,48 +97,29 @@ pbkdf2(MacFunc, Password, Salt, Iterations, DerivedLength, BlockIndex, Acc) ->
Key :: binary().

pbkdf2(_MacFunc, _Password, _Salt, Iterations, _BlockIndex, Iteration, _Prev, Acc) when Iteration > Iterations ->
Acc;
Acc;

pbkdf2(MacFunc, Password, Salt, Iterations, BlockIndex, 1, _Prev, _Acc) ->
InitialBlock = MacFunc(Password, <<Salt/binary, BlockIndex:32/integer>>),
pbkdf2(MacFunc, Password, Salt, Iterations, BlockIndex, 2, InitialBlock, InitialBlock);
InitialBlock = MacFunc(Password, <<Salt/binary, BlockIndex:32/integer>>),
pbkdf2(MacFunc, Password, Salt, Iterations, BlockIndex, 2, InitialBlock, InitialBlock);

pbkdf2(MacFunc, Password, Salt, Iterations, BlockIndex, Iteration, Prev, Acc) ->
Next = MacFunc(Password, Prev),
pbkdf2(MacFunc, Password, Salt, Iterations, BlockIndex, Iteration + 1, Next, crypto:exor(Next, Acc)).

%----------------------------------------------------------------------------------------------------------------------

%-type digest_func_info() :: digest_func() | {digest_func(), DigestLength}
% | md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512.

resolve_digest_func({DigestFunc, DigestLength}) when is_function(DigestFunc) ->
{DigestFunc, DigestLength};

resolve_digest_func(md4) -> {crypto, md4};
resolve_digest_func(md5) -> {crypto, md5};
resolve_digest_func(ripemd160) -> {crypto, ripemd160};
resolve_digest_func(sha) -> {crypto, sha};
resolve_digest_func(sha224) -> {crypto, sha224};
resolve_digest_func(sha256) -> {crypto, sha256};
resolve_digest_func(sha384) -> {crypto, sha384};
resolve_digest_func(sha512) -> {crypto, sha512}.
Next = MacFunc(Password, Prev),
pbkdf2(MacFunc, Password, Salt, Iterations, BlockIndex, Iteration + 1, Next, crypto:exor(Next, Acc)).

%----------------------------------------------------------------------------------------------------------------------

%-type mac_func_info() :: mac_func() | {hmac, digest_func_info()}
% | md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512.

resolve_mac_func({hmac, DigestFunc}) ->
DigestFunc1 = resolve_digest_func(DigestFunc),
fun(Key, Data) ->
crypto:hmac(DigestFunc1, Key, Data)
%crypto:hmac(DigestFunc, Key, Data)
HMAC = crypto:hmac_init(DigestFunc, Key),
HMAC1 = crypto:hmac_update(HMAC, Data),
crypto:hmac_final(HMAC1)
end;

% fun(Key, Data, MacLength) ->
% crypto:hmac(DigestFunc1, Key, Data, MacLength)
% end;

resolve_mac_func(MacFunc) when is_function(MacFunc) ->
MacFunc;

Expand All @@ -168,15 +141,15 @@ resolve_mac_func(sha512) -> resolve_mac_func({hmac, sha512}).
Second :: binary() | string().

compare_secure(<<X/binary>>, <<Y/binary>>) ->
compare_secure(binary_to_list(X), binary_to_list(Y));
compare_secure(binary_to_list(X), binary_to_list(Y));

compare_secure(X, Y) when is_list(X) and is_list(Y) ->
case length(X) == length(Y) of
true ->
compare_secure(X, Y, 0);
false ->
false
end;
case length(X) == length(Y) of
true ->
compare_secure(X, Y, 0);
false ->
false
end;

compare_secure(_X, _Y) -> false.

Expand All @@ -186,25 +159,31 @@ compare_secure(_X, _Y) -> false.
Accum :: integer().

compare_secure([X|RestX], [Y|RestY], Result) ->
compare_secure(RestX, RestY, (X bxor Y) bor Result);
compare_secure(RestX, RestY, (X bxor Y) bor Result);

compare_secure([], [], Result) ->
Result == 0.
Result == 0.

%----------------------------------------------------------------------------------------------------------------------

-spec to_hex(Data) -> HexData when
Data :: binary() | list(),
HexData :: hex_list().
HexData :: binary() | hex_list().

to_hex([]) ->
[];
to_hex(<<>>) ->
<<>>;

to_hex(<<Char:8/integer, Rest/binary>>) ->
CharHex1 = to_hex_digit(Char div 16),
CharHex2 = to_hex_digit(Char rem 16),
RestHex = to_hex(Rest),
<<CharHex1, CharHex2, RestHex/binary>>;

to_hex(Bin) when is_binary(Bin) ->
to_hex(binary_to_list(Bin));
to_hex([]) ->
[];

to_hex([H|T]) ->
[to_hex_digit(H div 16), to_hex_digit(H rem 16) | to_hex(T)].
to_hex([Char | Rest]) ->
[to_hex_digit(Char div 16), to_hex_digit(Char rem 16) | to_hex(Rest)].

%----------------------------------------------------------------------------------------------------------------------

Expand Down

0 comments on commit 267eb2c

Please sign in to comment.