switch to fast_pbkdf2 for hashing
diff --git a/.gitignore b/.gitignore
index 30aed77..fe9341b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,6 +69,7 @@
 src/proper/
 src/rebar/
 src/recon/
+src/fast_pbkdf2/
 src/snappy/
 src/ssl_verify_fun/
 src/triq/
diff --git a/rebar.config.script b/rebar.config.script
index 9098e6d..ad8787b 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -157,7 +157,8 @@
 {jiffy,            "jiffy",            {tag, "CouchDB-1.0.9-2"}},
 {mochiweb,         "mochiweb",         {tag, "v3.1.1"}},
 {meck,             "meck",             {tag, "0.9.2"}},
-{recon,            "recon",            {tag, "2.5.3"}}
+{recon,            "recon",            {tag, "2.5.3"}},
+{fast_pbkdf2,      {url, "https://github.com/esl/fast_pbkdf2"}, {tag, "1.0.2"}}
 ].
 
 WithProper = lists:keyfind(with_proper, 1, CouchConfig) == {with_proper, true}.
diff --git a/rel/reltool.config b/rel/reltool.config
index 1dca6ff..392d5c6 100644
--- a/rel/reltool.config
+++ b/rel/reltool.config
@@ -66,7 +66,8 @@
 
         %% extra
         nouveau,
-        recon
+        recon,
+        fast_pbkdf2
     ]},
     {rel, "start_clean", "", [kernel, stdlib]},
     {boot_rel, "couchdb"},
@@ -129,7 +130,8 @@
 
     %% extra
     {app, nouveau, [{incl_cond, include}]},
-    {app, recon, [{incl_cond, include}]}
+    {app, recon, [{incl_cond, include}]},
+    {app, fast_pbkdf2, [{incl_cond, include}]}
 ]}.
 
 {overlay_vars, "couchdb.config"}.
diff --git a/src/couch/src/couch.app.src b/src/couch/src/couch.app.src
index 6fc293a..bf58a7c 100644
--- a/src/couch/src/couch.app.src
+++ b/src/couch/src/couch.app.src
@@ -49,7 +49,8 @@
         ioq,
         couch_stats,
         hyper,
-        couch_dist
+        couch_dist,
+        fast_pbkdf2
     ]},
     {env, [
         {httpd_global_handlers, [
diff --git a/src/couch/src/couch_passwords.erl b/src/couch/src/couch_passwords.erl
index b891046..0f3083c 100644
--- a/src/couch/src/couch_passwords.erl
+++ b/src/couch/src/couch_passwords.erl
@@ -83,8 +83,8 @@
     is_integer(Iterations),
     Iterations > 0
 ->
-    {ok, Result} = pbkdf2(Password, Salt, Iterations, ?SHA1_OUTPUT_LENGTH),
-    Result;
+    DerivedKey = fast_pbkdf2:pbkdf2(sha, Password, Salt, Iterations),
+    couch_util:to_hex_bin(DerivedKey);
 pbkdf2(Password, Salt, Iterations) when
     is_binary(Salt),
     is_integer(Iterations),
@@ -113,60 +113,8 @@
     Iterations > 0,
     is_integer(DerivedLength)
 ->
-    L = ceiling(DerivedLength / ?SHA1_OUTPUT_LENGTH),
-    <<Bin:DerivedLength/binary, _/binary>> =
-        iolist_to_binary(pbkdf2(Password, Salt, Iterations, L, 1, [])),
-    {ok, couch_util:to_hex_bin(Bin)}.
-
--spec pbkdf2(binary(), binary(), integer(), integer(), integer(), iolist()) ->
-    iolist().
-pbkdf2(_Password, _Salt, _Iterations, BlockCount, BlockIndex, Acc) when
-    BlockIndex > BlockCount
-->
-    lists:reverse(Acc);
-pbkdf2(Password, Salt, Iterations, BlockCount, BlockIndex, Acc) ->
-    Block = pbkdf2(Password, Salt, Iterations, BlockIndex, 1, <<>>, <<>>),
-    pbkdf2(Password, Salt, Iterations, BlockCount, BlockIndex + 1, [Block | Acc]).
-
--spec pbkdf2(
-    binary(),
-    binary(),
-    integer(),
-    integer(),
-    integer(),
-    binary(),
-    binary()
-) -> binary().
-pbkdf2(_Password, _Salt, Iterations, _BlockIndex, Iteration, _Prev, Acc) when
-    Iteration > Iterations
-->
-    Acc;
-pbkdf2(Password, Salt, Iterations, BlockIndex, 1, _Prev, _Acc) ->
-    InitialBlock = couch_util:hmac(
-        sha,
-        Password,
-        <<Salt/binary, BlockIndex:32/integer>>
-    ),
-    pbkdf2(
-        Password,
-        Salt,
-        Iterations,
-        BlockIndex,
-        2,
-        InitialBlock,
-        InitialBlock
-    );
-pbkdf2(Password, Salt, Iterations, BlockIndex, Iteration, Prev, Acc) ->
-    Next = couch_util:hmac(sha, Password, Prev),
-    pbkdf2(
-        Password,
-        Salt,
-        Iterations,
-        BlockIndex,
-        Iteration + 1,
-        Next,
-        crypto:exor(Next, Acc)
-    ).
+    DerivedKey = fast_pbkdf2:pbkdf2(sha, Password, Salt, Iterations, DerivedLength),
+    {ok, couch_util:to_hex_bin(DerivedKey)}.
 
 %% verify two lists for equality without short-circuits to avoid timing attacks.
 -spec verify(string(), string(), integer()) -> boolean().
@@ -189,12 +137,3 @@
     end;
 verify(_X, _Y) ->
     false.
-
--spec ceiling(number()) -> integer().
-ceiling(X) ->
-    T = erlang:trunc(X),
-    case (X - T) of
-        Neg when Neg < 0 -> T;
-        Pos when Pos > 0 -> T + 1;
-        _ -> T
-    end.