Blob Blame History Raw
From: Peter Lemenkov <lemenkov@gmail.com>
Date: Fri, 22 Apr 2016 16:45:41 +0300
Subject: [PATCH] Don't use pbkdf2 as application

Use pbkdf2 from basho/erlang-pbkdf2@0cabf7cc8c18e820d9149d08cb64ed6cc5aae3b4.

Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>

diff --git a/rebar.config b/rebar.config
index 64370762..5a7939bb 100644
--- a/rebar.config
+++ b/rebar.config
@@ -16,7 +16,6 @@
   {riak_sysmon, ".*", {git, "https://github.com/basho/riak_sysmon.git", {tag, "2.1.5"}}},
   {eleveldb, ".*", {git, "git://github.com/basho/eleveldb.git", {tag, "2.0.34"}}},
   {riak_ensemble, ".*", {git, "https://github.com/basho/riak_ensemble", {tag, "2.1.8"}}},
-  {pbkdf2, ".*", {git, "git://github.com/basho/erlang-pbkdf2.git", {tag, "2.0.0"}}},
   {exometer_core, ".*", {git, "git://github.com/basho/exometer_core.git", {tag, "1.0.0-basho9"}}},
   {clique, ".*", {git, "https://github.com/basho/clique.git", {tag, "0.3.9"}}}
 ]}.
diff --git a/src/pbkdf2.erl b/src/pbkdf2.erl
new file mode 100644
index 00000000..dcc66064
--- /dev/null
+++ b/src/pbkdf2.erl
@@ -0,0 +1,198 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(pbkdf2).
+
+-export([pbkdf2/4, pbkdf2/5, compare_secure/2, to_hex/1]).
+
+
+%-type(hex_char() :: $0 .. $9 | $a .. $f).
+-type(hex_char() :: 48 .. 57 | 97 .. 102).
+-type(hex_list() :: [hex_char()]).
+
+
+-type 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)).
+
+%======================================================================================================================
+% Public API
+
+-spec pbkdf2(MacFunc, Password, Salt, Iterations) -> {ok, Key} | {error, derived_key_too_long} when
+	MacFunc :: mac_func_info(),
+	Password :: binary(),
+	Salt :: binary(),
+	Iterations :: integer(),
+	Key :: binary().
+
+pbkdf2(MacFunc, Password, Salt, Iterations) ->
+	MacFunc1 = resolve_mac_func(MacFunc),
+	DerivedLength = byte_size(MacFunc1(<<"test key">>, <<"test data">>)),
+	Bin = pbkdf2(MacFunc1, Password, Salt, Iterations, DerivedLength, 1, []),
+	{ok, Bin}.
+
+%----------------------------------------------------------------------------------------------------------------------
+
+-spec pbkdf2(MacFunc, Password, Salt, Iterations, DerivedLength) -> {ok, Key} | {error, derived_key_too_long} when
+	MacFunc :: mac_func_info(),
+	Password :: binary(),
+	Salt :: binary(),
+	Iterations :: integer(),
+	DerivedLength :: integer(),
+	Key :: binary().
+
+pbkdf2(_MacFunc, _Password, _Salt, _Iterations, DerivedLength) when DerivedLength > ?MAX_DERIVED_KEY_LENGTH ->
+	{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}.
+
+%----------------------------------------------------------------------------------------------------------------------
+
+-spec to_hex(Data) -> HexData when
+	Data :: binary() | list(),
+	HexData :: binary() | hex_list().
+
+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([]) ->
+	[];
+
+to_hex([Char | Rest]) ->
+	[to_hex_digit(Char div 16), to_hex_digit(Char rem 16) | to_hex(Rest)].
+
+%======================================================================================================================
+% Internal Functions
+
+-spec pbkdf2(MacFunc, Password, Salt, Iterations, DerivedLength, BlockIndex, Acc) -> Key when
+	MacFunc :: fun((binary(), binary()) -> binary()),
+	Password :: binary(),
+	Salt :: binary(),
+	Iterations :: integer(),
+	DerivedLength :: integer(),
+	BlockIndex :: integer(),
+	Acc :: iolist(),
+	Key :: binary().
+
+pbkdf2(MacFunc, Password, Salt, Iterations, DerivedLength, BlockIndex, 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.
+
+%----------------------------------------------------------------------------------------------------------------------
+
+-spec pbkdf2(MacFunc, Password, Salt, Iterations, BlockIndex, Iteration, Prev, Acc) -> Key when
+	MacFunc :: fun((binary(), binary()) -> binary()),
+	Password :: binary(),
+	Salt :: binary(),
+	Iterations :: integer(),
+	BlockIndex :: integer(),
+	Iteration :: integer(),
+	Prev :: binary(),
+	Acc :: binary(),
+	Key :: binary().
+
+pbkdf2(_MacFunc, _Password, _Salt, Iterations, _BlockIndex, Iteration, _Prev, Acc) when Iteration > Iterations ->
+	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);
+
+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 mac_func_info() :: mac_func() | {hmac, digest_func_info()}
+%	| md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512.
+
+resolve_mac_func({hmac, DigestFunc}) ->
+	fun(Key, Data) ->
+		%crypto:hmac(DigestFunc, Key, Data)
+		HMAC = crypto:hmac_init(DigestFunc, Key),
+		HMAC1 = crypto:hmac_update(HMAC, Data),
+		crypto:hmac_final(HMAC1)
+	end;
+
+resolve_mac_func(MacFunc) when is_function(MacFunc) ->
+	MacFunc;
+
+resolve_mac_func(md4) -> resolve_mac_func({hmac, md4});
+resolve_mac_func(md5) -> resolve_mac_func({hmac, md5});
+resolve_mac_func(ripemd160) -> resolve_mac_func({hmac, ripemd160});
+resolve_mac_func(sha) -> resolve_mac_func({hmac, sha});
+resolve_mac_func(sha224) -> resolve_mac_func({hmac, sha224});
+resolve_mac_func(sha256) -> resolve_mac_func({hmac, sha256});
+resolve_mac_func(sha384) -> resolve_mac_func({hmac, sha384});
+resolve_mac_func(sha512) -> resolve_mac_func({hmac, sha512}).
+
+%----------------------------------------------------------------------------------------------------------------------
+
+%% Compare two strings or binaries for equality without short-circuits to avoid timing attacks.
+
+-spec compare_secure(First, Second) -> boolean() when
+	First :: binary() | string(),
+	Second :: binary() | string().
+
+compare_secure(<<X/binary>>, <<Y/binary>>) ->
+	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;
+
+compare_secure(_X, _Y) -> false.
+
+-spec compare_secure(First, Second, Accum) -> boolean() when
+	First :: string(),
+	Second :: string(),
+	Accum :: integer().
+
+compare_secure([X|RestX], [Y|RestY], Result) ->
+	compare_secure(RestX, RestY, (X bxor Y) bor Result);
+
+compare_secure([], [], Result) ->
+	Result == 0.
+
+%----------------------------------------------------------------------------------------------------------------------
+
+-spec to_hex_digit(Nyble) -> hex_char() when
+	Nyble :: 0 .. 15.
+
+to_hex_digit(N) when N < 10 ->
+	$0 + N;
+
+to_hex_digit(N) ->
+	$a + N - 10.
diff --git a/src/riak_core.app.src b/src/riak_core.app.src
index 4bfb03f3..c5a38371 100644
--- a/src/riak_core.app.src
+++ b/src/riak_core.app.src
@@ -17,7 +17,6 @@
                   os_mon,
                   basho_stats,
                   eleveldb,
-                  pbkdf2,
                   poolboy,
                   exometer_core,
                   clique