diff options
Diffstat (limited to 'src/couch/src/couch_passwords.erl')
-rw-r--r-- | src/couch/src/couch_passwords.erl | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/src/couch/src/couch_passwords.erl b/src/couch/src/couch_passwords.erl index 677ef6559..77e136144 100644 --- a/src/couch/src/couch_passwords.erl +++ b/src/couch/src/couch_passwords.erl @@ -12,7 +12,7 @@ -module(couch_passwords). --export([simple/2, pbkdf2/3, pbkdf2/4, verify/2]). +-export([simple/2, pbkdf2/3, pbkdf2/4, bcrypt/2, verify/2]). -export([hash_admin_password/1, get_unhashed_admins/0]). -include_lib("couch/include/couch_db.hrl"). @@ -23,7 +23,13 @@ %% legacy scheme, not used for new passwords. -spec simple(binary(), binary()) -> binary(). simple(Password, Salt) when is_binary(Password), is_binary(Salt) -> - ?l2b(couch_util:to_hex(crypto:hash(sha, <<Password/binary, Salt/binary>>))). + ?l2b(couch_util:to_hex(crypto:hash(sha, <<Password/binary, Salt/binary>>))); +simple(Password, Salt) when is_binary(Salt) -> + Msg = io_lib:format("Password value of '~p' is invalid.", [Password]), + throw({forbidden, Msg}); +simple(Password, Salt) when is_binary(Password) -> + Msg = io_lib:format("Salt value of '~p' is invalid.", [Salt]), + throw({forbidden, Msg}). %% CouchDB utility functions -spec hash_admin_password(binary() | list()) -> binary(). @@ -45,7 +51,10 @@ hash_admin_password("pbkdf2", ClearPassword) -> Salt ,list_to_integer(Iterations)), ?l2b("-pbkdf2-" ++ ?b2l(DerivedKey) ++ "," ++ ?b2l(Salt) ++ "," - ++ Iterations). + ++ Iterations); +hash_admin_password("bcrypt", ClearPassword) -> + LogRounds = list_to_integer(config:get("couch_httpd_auth", "log_rounds", "10")), + ?l2b("-bcrypt-" ++ couch_passwords:bcrypt(couch_util:to_binary(ClearPassword), LogRounds)). -spec get_unhashed_admins() -> list(). get_unhashed_admins() -> @@ -54,6 +63,8 @@ get_unhashed_admins() -> false; % already hashed ({_User, "-pbkdf2-" ++ _}) -> false; % already hashed + ({_User, "-bcrypt-" ++ _}) -> + false; % already hashed ({_User, _ClearPassword}) -> true end, @@ -66,7 +77,17 @@ pbkdf2(Password, Salt, Iterations) when is_binary(Password), is_integer(Iterations), Iterations > 0 -> {ok, Result} = pbkdf2(Password, Salt, Iterations, ?SHA1_OUTPUT_LENGTH), - Result. + Result; +pbkdf2(Password, Salt, Iterations) when is_binary(Salt), + is_integer(Iterations), + Iterations > 0 -> + Msg = io_lib:format("Password value of '~p' is invalid.", [Password]), + throw({forbidden, Msg}); +pbkdf2(Password, Salt, Iterations) when is_binary(Password), + is_integer(Iterations), + Iterations > 0 -> + Msg = io_lib:format("Salt value of '~p' is invalid.", [Salt]), + throw({forbidden, Msg}). -spec pbkdf2(binary(), binary(), integer(), integer()) -> {ok, binary()} | {error, derived_key_too_long}. @@ -107,6 +128,16 @@ pbkdf2(Password, Salt, Iterations, BlockIndex, Iteration, Prev, Acc) -> pbkdf2(Password, Salt, Iterations, BlockIndex, Iteration + 1, Next, crypto:exor(Next, Acc)). +%% Define the bcrypt functions to hash a password +-spec bcrypt(binary(), binary()) -> binary(); + (binary(), integer()) -> binary(). +bcrypt(Password, Salt) when is_binary(Salt) -> + {ok, Hash} = bcrypt:hashpw(Password, Salt), + list_to_binary(Hash); +bcrypt(Password, LogRounds) when is_integer(LogRounds) -> + {ok, Salt} = bcrypt:gen_salt(LogRounds), + bcrypt(Password, list_to_binary(Salt)). + %% verify two lists for equality without short-circuits to avoid timing attacks. -spec verify(string(), string(), integer()) -> boolean(). verify([X|RestX], [Y|RestY], Result) -> |