summaryrefslogtreecommitdiff
path: root/src/couch/src/couch_passwords.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/couch/src/couch_passwords.erl')
-rw-r--r--src/couch/src/couch_passwords.erl153
1 files changed, 0 insertions, 153 deletions
diff --git a/src/couch/src/couch_passwords.erl b/src/couch/src/couch_passwords.erl
deleted file mode 100644
index baf78f5d5..000000000
--- a/src/couch/src/couch_passwords.erl
+++ /dev/null
@@ -1,153 +0,0 @@
-% 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(couch_passwords).
-
--export([simple/2, pbkdf2/3, pbkdf2/4, verify/2]).
--export([hash_admin_password/1, get_unhashed_admins/0]).
-
--include_lib("couch/include/couch_db.hrl").
-
--define(MAX_DERIVED_KEY_LENGTH, (1 bsl 32 - 1)).
--define(SHA1_OUTPUT_LENGTH, 20).
-
-%% 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>>)));
-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().
-hash_admin_password(ClearPassword) when is_list(ClearPassword) ->
- hash_admin_password(?l2b(ClearPassword));
-hash_admin_password(ClearPassword) when is_binary(ClearPassword) ->
- %% Support both schemes to smooth migration from legacy scheme
- Scheme = config:get("couch_httpd_auth", "password_scheme", "pbkdf2"),
- hash_admin_password(Scheme, ClearPassword).
-
-hash_admin_password("simple", ClearPassword) -> % deprecated
- Salt = couch_uuids:random(),
- Hash = crypto:hash(sha, <<ClearPassword/binary, Salt/binary>>),
- ?l2b("-hashed-" ++ couch_util:to_hex(Hash) ++ "," ++ ?b2l(Salt));
-hash_admin_password("pbkdf2", ClearPassword) ->
- Iterations = config:get("couch_httpd_auth", "iterations", "10000"),
- Salt = couch_uuids:random(),
- DerivedKey = couch_passwords:pbkdf2(couch_util:to_binary(ClearPassword),
- Salt ,list_to_integer(Iterations)),
- ?l2b("-pbkdf2-" ++ ?b2l(DerivedKey) ++ ","
- ++ ?b2l(Salt) ++ ","
- ++ Iterations).
-
--spec get_unhashed_admins() -> list().
-get_unhashed_admins() ->
- lists:filter(
- fun({_User, "-hashed-" ++ _}) ->
- false; % already hashed
- ({_User, "-pbkdf2-" ++ _}) ->
- false; % already hashed
- ({_User, _ClearPassword}) ->
- true
- end,
- config:get("admins")).
-
-%% Current scheme, much stronger.
--spec pbkdf2(binary(), binary(), integer()) -> binary().
-pbkdf2(Password, Salt, Iterations) when is_binary(Password),
- is_binary(Salt),
- is_integer(Iterations),
- Iterations > 0 ->
- {ok, Result} = pbkdf2(Password, Salt, Iterations, ?SHA1_OUTPUT_LENGTH),
- 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}.
-pbkdf2(_Password, _Salt, _Iterations, DerivedLength)
- when DerivedLength > ?MAX_DERIVED_KEY_LENGTH ->
- {error, derived_key_too_long};
-pbkdf2(Password, Salt, Iterations, DerivedLength) when is_binary(Password),
- is_binary(Salt),
- is_integer(Iterations),
- 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, ?l2b(couch_util:to_hex(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 = crypto: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 = crypto:hmac(sha, Password, Prev),
- pbkdf2(Password, Salt, Iterations, BlockIndex, Iteration + 1,
- Next, crypto:exor(Next, Acc)).
-
-%% verify two lists for equality without short-circuits to avoid timing attacks.
--spec verify(string(), string(), integer()) -> boolean().
-verify([X|RestX], [Y|RestY], Result) ->
- verify(RestX, RestY, (X bxor Y) bor Result);
-verify([], [], Result) ->
- Result == 0.
-
--spec verify(binary(), binary()) -> boolean();
- (list(), list()) -> boolean().
-verify(<<X/binary>>, <<Y/binary>>) ->
- verify(?b2l(X), ?b2l(Y));
-verify(X, Y) when is_list(X) and is_list(Y) ->
- case length(X) == length(Y) of
- true ->
- verify(X, Y, 0);
- false ->
- false
- 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.