diff options
Diffstat (limited to 'server/_build/default/lib/bcrypt/src')
10 files changed, 772 insertions, 0 deletions
diff --git a/server/_build/default/lib/bcrypt/src/bcrypt.app.src b/server/_build/default/lib/bcrypt/src/bcrypt.app.src new file mode 100644 index 0000000..d834377 --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt.app.src @@ -0,0 +1,15 @@ +{application,bcrypt, + [{description,"An Erlang wrapper (NIF or port program) for the OpenBSD password scheme, bcrypt."}, + {vsn,"1.2.0"}, + {registered,[bcrypt_sup,bcrypt_port_sup,bcrypt_pool]}, + {mod,{bcrypt_app,[]}}, + {applications,[kernel,stdlib,crypto,poolboy]}, + {env,[{default_log_rounds,12}, + {mechanism,nif}, + {pool_size,4}, + {nif_pool_size,4}, + {nif_pool_max_overflow,10}]}, + {exclude_files,["priv/bcrypt"]}, + {maintainers,["Hunter Morris","Mrinal Wadhwa","ErlangPack"]}, + {licenses,["MIT"]}, + {links,[{"Github","https://github.com/erlangpack/bcrypt"}]}]}. diff --git a/server/_build/default/lib/bcrypt/src/bcrypt.erl b/server/_build/default/lib/bcrypt/src/bcrypt.erl new file mode 100644 index 0000000..f1997c2 --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt.erl @@ -0,0 +1,91 @@ +%% Copyright (c) 2011 Hunter Morris +%% Distributed under the MIT license; see LICENSE for details. +%% @doc The OpenBSD Blowfish password hashing algorithm wrapper module. +-module(bcrypt). +-author('Hunter Morris <hunter.morris@smarkets.com>'). + +%% API +-export([start/0, stop/0]). +-export([mechanism/0]). +-export([gen_salt/0, gen_salt/1, hashpw/2]). + +-type mechanism() :: nif | port. +-type rounds() :: 4..31. +-type pwerr() :: invalid_salt | invalid_salt_length | invalid_rounds. + +-export_type([ mechanism/0, rounds/0, pwerr/0 ]). + +%% @doc Starts `Application' `bcrypt'. +%% <b>See also:</b> +%% [http://erlang.org/doc/man/application.html#start-1 application:start/1]. + +start() -> application:start(bcrypt). + +%% @doc Stops `Application' `bcrypt'. +%% <b>See also:</b> +%% [http://erlang.org/doc/man/application.html#stop-1 application:stop/1]. + +stop() -> application:stop(bcrypt). + +%% @doc Get environment setting of hash generation. + +-spec mechanism() -> mechanism(). +mechanism() -> + {ok, M} = application:get_env(bcrypt, mechanism), + M. + +%% @doc Returns a random string data. + +-spec gen_salt() -> Result when + Result :: {ok, Salt}, + Salt :: [byte()]. +gen_salt() -> + do_gen_salt(mechanism()). + +%% @doc Generate a random string data. + +-spec gen_salt( Rounds ) -> Result when + Rounds :: rounds(), + Result :: {ok, Salt}, + Salt :: [byte()]. +gen_salt(Rounds) when is_integer(Rounds), Rounds < 32, Rounds > 3 -> + do_gen_salt(mechanism(), Rounds). + +%% @doc Make hash string based on `Password' and `Salt'. + +-spec hashpw( Password, Salt ) -> Result when + Password :: [byte()] | binary(), + Salt :: [byte()] | binary(), + Result :: {ok, Hash} | {error, ErrorDescription}, + Hash :: [byte()], + ErrorDescription :: pwerr(). +hashpw(Password, Salt) -> + do_hashpw(mechanism(), Password, Salt). + +%% @private + +-spec do_gen_salt(nif | port) -> Result when + Result :: {ok, Salt}, + Salt :: [byte()]. +do_gen_salt(nif) -> bcrypt_nif_worker:gen_salt(); +do_gen_salt(port) -> bcrypt_pool:gen_salt(). + +%% @private + +-spec do_gen_salt(nif | port, Rounds) -> Result when + Rounds :: rounds(), + Result :: {ok, Salt}, + Salt :: [byte()]. +do_gen_salt(nif, Rounds) -> bcrypt_nif_worker:gen_salt(Rounds); +do_gen_salt(port, Rounds) -> bcrypt_pool:gen_salt(Rounds). + +%% @private + +-spec do_hashpw(nif | port, Password, Salt) -> Result when + Password :: [byte()] | binary(), + Salt :: [byte()], + Result :: {ok, Hash} | {error, ErrorDescription}, + Hash :: [byte()], + ErrorDescription :: pwerr(). +do_hashpw(nif, Password, Salt) -> bcrypt_nif_worker:hashpw(Password, Salt); +do_hashpw(port, Password, Salt) -> bcrypt_pool:hashpw(Password, Salt). diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_app.erl b/server/_build/default/lib/bcrypt/src/bcrypt_app.erl new file mode 100644 index 0000000..d83db7d --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt_app.erl @@ -0,0 +1,27 @@ +%% @copyright 2011 Hunter Morris +%% @doc Implementation of `application' behaviour. +%% @private +%% @end +%% Distributed under the MIT license; see LICENSE for details. +-module(bcrypt_app). +-author('Hunter Morris <hunter.morris@smarkets.com>'). + +-behaviour(application). + +-export([start/2, stop/1]). + +-spec start(StartType, StartArgs) -> Result when + StartType :: normal, + StartArgs :: term(), + Result :: {ok, pid()} | {error, Reason}, + Reason :: term(). +start(normal, _Args) -> + case bcrypt_sup:start_link() of + {ok, Pid} -> {ok, Pid}; + {error, _} = Error -> Error + end. + +-spec stop(State) -> Result when + State :: term(), + Result :: ok. +stop(_State) -> ok. diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_nif.erl b/server/_build/default/lib/bcrypt/src/bcrypt_nif.erl new file mode 100644 index 0000000..348d8df --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt_nif.erl @@ -0,0 +1,99 @@ +%% @author Hunter Morris <hunter.morris@smarkets.com> +%% @copyright 2011 Hunter Morris +%% +%% @doc Bcrypt Erlang wrapper. <div>The wrapper around the OpenBSD Blowfish password hashing algorithm, as +%% described in: [http://www.openbsd.org/papers/bcrypt-paper.ps "A Future-Adaptable Password Scheme"] +%% by Niels Provos and David Mazieres.</div> +%% @end +%% +%% Permission to use, copy, modify, and distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. + +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-module(bcrypt_nif). +-author('Hunter Morris <hunter.morris@smarkets.com>'). + +%% API +-export([init/0]). +-export([gen_salt/1, hashpw/5, create_ctx/0]). + +-on_load(init/0). + +%%-------------------------------------------------------------------- +%% @doc Load the bcrypt NIFs +%% @private +%% @end +%%-------------------------------------------------------------------- + +-spec init() -> Result when + Result :: ok | Error, + Error :: {error, {Reason, ErrorText}}, + Reason :: load_failed | bad_lib | load | reload | upgrade | old_code, + ErrorText :: string(). +init() -> + Dir = case code:priv_dir(bcrypt) of + {error, bad_name} -> + case code:which(bcrypt) of + Filename when is_list(Filename) -> + filename:join( + [filename:dirname(Filename), "../priv"]); + _ -> + "../priv" + end; + Priv -> Priv + end, + erlang:load_nif(filename:join(Dir, "bcrypt_nif"), 0). + +%%-------------------------------------------------------------------- +%% @doc Generate a random text salt for use with hashpw/3. LogRounds +%% defines the complexity of the hashing, increasing the cost as +%% 2^log_rounds. +%% @end +%%-------------------------------------------------------------------- + +-spec gen_salt(LogRounds) -> Result when + LogRounds :: integer(), + Result :: [byte()]. +gen_salt(LogRounds) + when is_integer(LogRounds), LogRounds < 32, LogRounds > 3 -> + R = crypto:strong_rand_bytes(16), + encode_salt(R, LogRounds). + +encode_salt(_R, _LogRounds) -> + nif_stub_error(?LINE). + +%%-------------------------------------------------------------------- +%% @doc Create a context which hashes passwords in a separate thread. +%% @end +%%-------------------------------------------------------------------- + +-spec create_ctx() -> Context when + Context :: term(). +create_ctx() -> + nif_stub_error(?LINE). + +%%-------------------------------------------------------------------- +%% @doc Hash the specified password and the salt using the OpenBSD +%% Blowfish password hashing algorithm. Returns the hashed password. +%% @end +%%-------------------------------------------------------------------- + +-spec hashpw(Ctx, Ref, Pid, Password, Salt) -> Result when + Ctx :: term(), + Ref :: reference(), + Pid :: pid(), + Password :: [byte()], + Salt :: [byte()], + Result :: ok. +hashpw(_Ctx, _Ref, _Pid, _Password, _Salt) -> + nif_stub_error(?LINE). + +nif_stub_error(Line) -> + erlang:nif_error({nif_not_loaded, module, ?MODULE, line, Line}). diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_nif_pool_sup.erl b/server/_build/default/lib/bcrypt/src/bcrypt_nif_pool_sup.erl new file mode 100644 index 0000000..dbd5868 --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt_nif_pool_sup.erl @@ -0,0 +1,50 @@ +%% @copyright 2011 Hunter Morris +%% @doc Implementation of `supervisor' behaviour. +%% @private +%% @end +%% Distributed under the MIT license; see LICENSE for details. +-module(bcrypt_nif_pool_sup). + +-behaviour(supervisor). + +-export([start_link/0, start_child/0, init/1]). + +%% @doc Creates a supervisor process as part of a supervision tree. + + +-spec start_link() -> Result when + Result :: {ok, pid()} | ignore | {error, StartlinkError}, + StartlinkError :: {already_started, pid()} | {shutdown, term()} | term(). +start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +%% @doc Dynamically adds a child specification to supervisor, +%% which starts the corresponding child process. + +-spec start_child() -> Result when + Info :: term(), + Child :: undefined | pid(), + Result :: {ok, Child} | {ok, Child, Info} | {error, StartChildError}, + StartChildError :: already_present | {already_started, Child} | term(). +start_child() -> supervisor:start_child(?MODULE, []). + +-spec init(Args) -> Result when + Args :: list(), + Result :: {ok,{SupFlags, ChildSpec}} | ignore, + SupFlags :: {one_for_one, 10, 10}, + ChildSpec :: [supervisor:child_spec()]. +init([]) -> + {ok, PoolSize} = application:get_env(bcrypt, nif_pool_size), + {ok, MaxOverFlow} = application:get_env(bcrypt, nif_pool_max_overflow), + + PoolArgs = [ + {name, {local, bcrypt_nif_pool}}, + {size, PoolSize}, + {max_overflow, MaxOverFlow}, + {worker_module, bcrypt_nif_worker} + ], + + PoolSpecs = [ + poolboy:child_spec(bcrypt_nif_pool, PoolArgs, []) + ], + + {ok, {{one_for_one, 10, 10}, PoolSpecs}}.
\ No newline at end of file diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_nif_worker.erl b/server/_build/default/lib/bcrypt/src/bcrypt_nif_worker.erl new file mode 100644 index 0000000..70b8eed --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt_nif_worker.erl @@ -0,0 +1,144 @@ +%% @copyright 2011 Hunter Morris. +%% @doc Implementation of `gen_server' behaviour. +%% @end +%% Distributed under the MIT license; see LICENSE for details. +-module(bcrypt_nif_worker). +-author('Hunter Morris <huntermorris@gmail.com>'). + +-behaviour(gen_server). + +-export([start_link/1]). +-export([gen_salt/0, gen_salt/1]). +-export([hashpw/2]). + +%% gen_server +-export([init/1, code_change/3, terminate/2, + handle_call/3, handle_cast/2, handle_info/2]). + +-record(state, { + default_log_rounds :: integer(), + context :: term() + }). + +-type state() :: #state{default_log_rounds :: integer(), context :: term()}. + +%% @doc Creates a `gen_server' process as part of a supervision tree. + +-spec start_link(Args) -> Result when + Args :: term(), + Result :: {ok,Pid} | ignore | {error,Error}, + Pid :: pid(), + Error :: {already_started,Pid} | term(). +start_link(Args) -> gen_server:start_link(?MODULE, Args, []). + +%% @doc Returns bcrypt salt. + +-spec gen_salt() -> Result when + Result :: [byte()]. +gen_salt() -> + poolboy:transaction(bcrypt_nif_pool, fun(Worker) -> + gen_server:call(Worker, gen_salt, infinity) + end). + +%% @doc Returns bcrypt salt. + +-spec gen_salt(Rounds) -> Result when + Rounds :: bcrypt:rounds(), + Result :: [byte()]. +gen_salt(Rounds) -> + poolboy:transaction(bcrypt_nif_pool, fun(Worker) -> + gen_server:call(Worker, {gen_salt, Rounds}, infinity) + end). + +%% @doc Make hash string based on `Password' and `Salt'. + +-spec hashpw( Password, Salt ) -> Result when + Password :: [byte()] | binary(), + Salt :: [byte()] | binary(), + Result :: {ok, Hash} | {error, ErrorDescription}, + Hash :: [byte()], + ErrorDescription :: bcrypt:pwerr(). +hashpw(Password, Salt) -> + poolboy:transaction(bcrypt_nif_pool, fun(Worker) -> + gen_server:call(Worker, {hashpw, Password, Salt}, infinity) + end). + +%% @private + +-spec init(Args) -> Result when + Args :: list(), + Result :: {ok, state()}. +init([]) -> + process_flag(trap_exit, true), + {ok, Default} = application:get_env(bcrypt, default_log_rounds), + Ctx = bcrypt_nif:create_ctx(), + {ok, #state{default_log_rounds = Default, context = Ctx}}. + +%% @private + +terminate(shutdown, _) -> ok. + +%% @private + +-spec handle_call(Request, From, State) -> Result when + Request :: gen_salt, + From :: {pid(), atom()}, + State :: state(), + Result :: {reply, Reply, State}, + Reply :: {ok, Salt}, + Salt :: integer(); +(Request, From, State) -> Result when + Request :: {gen_salt, Rounds}, + From :: {pid(), atom()}, + State :: state(), + Rounds :: bcrypt:rounds(), + Result :: {reply, Reply, State}, + Reply :: {ok, Salt}, + Salt :: integer(); +(Request, From, State) -> Result when + Request :: {hashpw, Password, Salt}, + From :: {pid(), atom()}, + State :: state(), + Password :: [byte()], + Salt :: integer(), + Result :: {reply, Reply, State} | {reply, Reply, State}, + Reply :: {ok, ResultInfo} | {error, ResultInfo}, + ResultInfo :: term(). + +handle_call(gen_salt, _From, #state{default_log_rounds = R} = State) -> + Salt = bcrypt_nif:gen_salt(R), + {reply, {ok, Salt}, State}; +handle_call({gen_salt, R}, _From, State) -> + Salt = bcrypt_nif:gen_salt(R), + {reply, {ok, Salt}, State}; +handle_call({hashpw, Password, Salt}, _From, #state{context=Ctx}=State) -> + Ref = make_ref(), + ok = bcrypt_nif:hashpw(Ctx, Ref, self(), to_list(Password), to_list(Salt)), + receive + {ok, Ref, Result} -> + {reply, {ok, Result}, State}; + {error, Ref, Result} -> + {reply, {error, Result}, State} + end; +handle_call(Msg, _, _) -> exit({unknown_call, Msg}). + +%% @private + +handle_cast(Msg, _) -> exit({unknown_cast, Msg}). + +%% @private + +handle_info(Msg, _) -> exit({unknown_info, Msg}). + +%% @private + +code_change(_OldVsn, State, _Extra) -> {ok, State}. + +-spec to_list(List) -> Result when + List :: [byte()], + Result :: [byte()]; +(Binary) -> Result when + Binary :: binary(), + Result :: [byte()]. +to_list(L) when is_list(L) -> L; +to_list(B) when is_binary(B) -> binary_to_list(B). diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_pool.erl b/server/_build/default/lib/bcrypt/src/bcrypt_pool.erl new file mode 100644 index 0000000..7b6ea91 --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt_pool.erl @@ -0,0 +1,140 @@ +%% @copyright 2011 Hunter Morris +%% @doc Implementation of `gen_server' behaviour. +%% @end +%% Distributed under the MIT license; see LICENSE for details. +-module(bcrypt_pool). +-author('Hunter Morris <huntermorris@gmail.com>'). + +-behaviour(gen_server). + +-export([start_link/0, available/1]). +-export([gen_salt/0, gen_salt/1]). +-export([hashpw/2]). + +%% gen_server +-export([init/1, code_change/3, terminate/2, + handle_call/3, handle_cast/2, handle_info/2]). + +-record(state, { + size = 0, + busy = 0, + requests = queue:new(), + ports = queue:new() + }). + +-record(req, {mon :: reference(), from :: {pid(), atom()}}). + +-type state() :: #state{size :: 0, busy :: 0, requests :: queue:queue(), ports :: queue:queue()}. + +%% @doc Creates a `gen_server' process as part of a supervision tree. + +-spec start_link() -> Result when + Result :: {ok,Pid} | ignore | {error,Error}, + Pid :: pid(), + Error :: {already_started,Pid} | term(). +start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +%% @doc Asynchronosly check if `Pid' in `#state:requests' queue or not. + +-spec available(Pid) -> Result when + Pid :: pid(), + Result :: ok. +available(Pid) -> gen_server:cast(?MODULE, {available, Pid}). + +%% @doc Generate a random text salt. + +-spec gen_salt() -> Result when + Result :: {ok, Salt}, + Salt :: [byte()]. +gen_salt() -> do_call(fun bcrypt_port:gen_salt/1, []). + +%% @doc Generate a random text salt. Rounds defines the complexity of +%% the hashing, increasing the cost as 2^log_rounds. + +-spec gen_salt(Rounds) -> Result when + Rounds :: bcrypt:rounds(), + Result :: {ok, Salt}, + Salt :: [byte()]. +gen_salt(Rounds) -> do_call(fun bcrypt_port:gen_salt/2, [Rounds]). + +%% @doc Hash the specified password and the salt. + +hashpw(Password, Salt) -> do_call(fun bcrypt_port:hashpw/3, [Password, Salt]). + +%% @private + +-spec init([]) -> Result when + Result :: {ok, state()}. +init([]) -> + {ok, Size} = application:get_env(bcrypt, pool_size), + {ok, #state{size = Size}}. + +%% @private + +terminate(shutdown, _) -> ok. + +%% @private + +-spec handle_call(Request, From, State) -> Result when + Request :: request, + From :: {RPid, atom()}, + RPid :: pid(), + State :: state(), + Result :: {noreply, state()} | {reply, {ok, pid()}, state()}. +handle_call(request, {RPid, _} = From, #state{ports = P} = State) -> + case queue:out(P) of + {empty, P} -> + #state{size = Size, busy = B, requests = R} = State, + B1 = + if Size > B -> + {ok, _} = bcrypt_port_sup:start_child(), + B + 1; + true -> + B + end, + RRef = erlang:monitor(process, RPid), + R1 = queue:in(#req{mon = RRef, from = From}, R), + {noreply, State#state{requests = R1, + busy = B1}}; + {{value, PPid}, P1} -> + #state{busy = B} = State, + {reply, {ok, PPid}, State#state{busy = B + 1, ports = P1}} + end; +handle_call(Msg, _, _) -> exit({unknown_call, Msg}). + +%% @private + +-spec handle_cast({available, Pid}, state()) -> Result when + Pid :: pid(), + Result :: {noreply, state()}. +handle_cast( + {available, Pid}, + #state{requests = R, ports = P, busy = B} = S) -> + case queue:out(R) of + {empty, R} -> + {noreply, S#state{ports = queue:in(Pid, P), busy = B - 1}}; + {{value, #req{mon = Mon, from = F}}, R1} -> + true = erlang:demonitor(Mon, [flush]), + gen_server:reply(F, {ok, Pid}), + {noreply, S#state{requests = R1}} + end; +handle_cast(Msg, _) -> exit({unknown_cast, Msg}). + +%% @private + +handle_info({'DOWN', Ref, process, _Pid, _Reason}, #state{requests = R} = State) -> + R1 = queue:from_list(lists:keydelete(Ref, #req.mon, queue:to_list(R))), + {noreply, State#state{requests = R1}}; + +%% @private + +handle_info(Msg, _) -> exit({unknown_info, Msg}). + +%% @private + +code_change(_OldVsn, State, _Extra) -> {ok, State}. + +do_call(F, Args0) -> + {ok, Pid} = gen_server:call(?MODULE, request, infinity), + Args = [Pid|Args0], + apply(F, Args). diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_port.erl b/server/_build/default/lib/bcrypt/src/bcrypt_port.erl new file mode 100644 index 0000000..6365de6 --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt_port.erl @@ -0,0 +1,157 @@ +%% @copyright 2011 Hunter Morris +%% @doc Implementation of `gen_server' behaviour. +%% @end +%% Distributed under the MIT license; see LICENSE for details. +-module(bcrypt_port). +-author('Hunter Morris <hunter.morris@smarkets.com>'). + +-behaviour(gen_server). + +%% API +-export([start_link/0, stop/0]). +-export([gen_salt/1, gen_salt/2]). +-export([hashpw/3]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). + +-record(state, { + port :: port(), + default_log_rounds :: non_neg_integer(), + cmd_from :: {pid(), term()} | undefined + }). + +-type state() :: #state{port :: port(), + default_log_rounds :: non_neg_integer(), + cmd_from :: {pid(), term()} | undefined}. + +-define(CMD_SALT, 0). +-define(CMD_HASH, 1). +-define(BCRYPT_ERROR(F, D), error_logger:error_msg(F, D)). +-define(BCRYPT_WARNING(F, D), error_logger:warning_msg(F, D)). + +-spec start_link() -> Result when + Result :: {ok,Pid} | ignore | {error,Error}, + Pid :: pid(), + Error :: {already_started,Pid} | term(), + Pid :: pid(). +start_link() -> + Dir = case code:priv_dir(bcrypt) of + {error, bad_name} -> + case code:which(bcrypt) of + Filename when is_list(Filename) -> + filename:join( + [filename:dirname(Filename), "../priv"]); + _ -> + "../priv" + end; + Priv -> Priv + end, + Port = filename:join(Dir, "bcrypt"), + gen_server:start_link(?MODULE, [Port], []). + +-spec stop() -> Result when + Result :: {stop, normal, ok, state()}. +stop() -> gen_server:call(?MODULE, stop). + +-spec gen_salt(Pid) -> Result when + Pid :: pid(), + Result :: {ok, Salt}, + Salt :: [byte()]. +gen_salt(Pid) -> + R = crypto:strong_rand_bytes(16), + gen_server:call(Pid, {encode_salt, R}, infinity). + +-spec gen_salt(Pid, LogRounds) -> Result when + Pid :: pid(), + LogRounds :: bcrypt:rounds(), + Result :: {ok, Salt}, + Salt :: [byte()]. +gen_salt(Pid, LogRounds) -> + R = crypto:strong_rand_bytes(16), + gen_server:call(Pid, {encode_salt, R, LogRounds}, infinity). + +-spec hashpw(Pid, Password, Salt) -> Result when + Pid :: pid(), + Password :: [byte()], + Salt :: [byte()], + Result :: [byte()]. +hashpw(Pid, Password, Salt) -> + gen_server:call(Pid, {hashpw, Password, Salt}, infinity). + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== +%% @private + +init([Filename]) -> + case file:read_file_info(Filename) of + {ok, _Info} -> + Port = open_port( + {spawn, Filename}, [{packet, 2}, binary, exit_status]), + ok = bcrypt_pool:available(self()), + {ok, Rounds} = application:get_env(bcrypt, default_log_rounds), + {ok, #state{port = Port, default_log_rounds = Rounds}}; + {error, Reason} -> + ?BCRYPT_ERROR("Can't open file ~p: ~p", [Filename, Reason]), + {stop, error_opening_bcrypt_file} + end. + +%% @private + +terminate(_Reason, #state{port=Port}) -> + catch port_close(Port), + ok. + +%% @private + +handle_call({encode_salt, R}, From, #state{default_log_rounds = LogRounds} = State) -> + handle_call({encode_salt, R, LogRounds}, From, State); +handle_call({encode_salt, R, LogRounds}, From, #state{ cmd_from = undefined } = State) -> + Port = State#state.port, + Data = term_to_binary({?CMD_SALT, {iolist_to_binary(R), LogRounds}}), + erlang:port_command(Port, Data), + {noreply, State#state{ cmd_from = From }}; +handle_call({encode_salt, _R, _Rounds}, From, #state{ cmd_from = CmdFrom } = State) -> + ?BCRYPT_ERROR("bcrypt: Salt request from ~p whilst busy for ~p", [ From, CmdFrom ]), + {reply, {error, {busy, From}}, State}; +handle_call({hashpw, Password, Salt}, From, #state{ cmd_from = undefined } = State) -> + Port = State#state.port, + Data = term_to_binary({?CMD_HASH, {iolist_to_binary(Password), iolist_to_binary(Salt)}}), + erlang:port_command(Port, Data), + {noreply, State#state{ cmd_from = From }}; +handle_call({hashpw, _Password, _Salt}, From, #state{ cmd_from = CmdFrom } = State) -> + ?BCRYPT_ERROR("bcrypt: Hash request from ~p whilst busy for ~p", [ From, CmdFrom ]), + {reply, {error, {busy, From}}, State}; +handle_call(stop, _From, State) -> + {stop, normal, ok, State}; +handle_call(Msg, _, State) -> + {stop, {unknown_call, Msg}, State}. + +handle_cast(Msg, State) -> + {stop, {unknown_cast, Msg}, State}. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info({Port, {data, Data}}, #state{ port = Port, cmd_from = From } = State) -> + Reply = + case binary_to_term(Data) of + {_, Error} when is_atom(Error) -> + {error, Error}; + {?CMD_SALT, Result} when is_binary(Result) -> + {ok, binary_to_list(Result)}; + {?CMD_HASH, Result} when is_binary(Result) -> + {ok, binary_to_list(Result)} + end, + gen_server:reply(From, Reply), + ok = bcrypt_pool:available(self()), + {noreply, State#state{ cmd_from = undefined }}; +handle_info({Port, {exit_status, Status}}, #state{port=Port}=State) -> + %% Rely on whomever is supervising this process to restart. + ?BCRYPT_WARNING("Port died: ~p", [Status]), + {stop, port_died, State}; +handle_info(Msg, _) -> + exit({unknown_info, Msg}). + diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_port_sup.erl b/server/_build/default/lib/bcrypt/src/bcrypt_port_sup.erl new file mode 100644 index 0000000..89fe33d --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt_port_sup.erl @@ -0,0 +1,21 @@ +%% @copyright 2011 Hunter Morris +%% @doc Implementation of `supervisor' behaviour. +%% @private +%% @end +%% Distributed under the MIT license; see LICENSE for details. +-module(bcrypt_port_sup). +-author('Hunter Morris <huntermorris@gmail.com>'). + +-behaviour(supervisor). + +-export([start_link/0, start_child/0, init/1]). + +start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +start_child() -> supervisor:start_child(?MODULE, []). + +init([]) -> + {ok, {{simple_one_for_one, 1, 1}, + [{undefined, + {bcrypt_port, start_link, []}, + transient, brutal_kill, worker, [bcrypt_port]}]}}. diff --git a/server/_build/default/lib/bcrypt/src/bcrypt_sup.erl b/server/_build/default/lib/bcrypt/src/bcrypt_sup.erl new file mode 100644 index 0000000..502a6a3 --- /dev/null +++ b/server/_build/default/lib/bcrypt/src/bcrypt_sup.erl @@ -0,0 +1,28 @@ +%% @copyright 2011 Hunter Morris +%% @doc Implementation of `supervisor' behaviour. +%% @private +%% @end +%% Distributed under the MIT license; see LICENSE for details. +-module(bcrypt_sup). +-author('Hunter Morris <huntermorris@gmail.com>'). + +-behaviour(supervisor). + +-export([start_link/0, init/1]). + +start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + PortChildren + = [{bcrypt_port_sup, {bcrypt_port_sup, start_link, []}, permanent, + 16#ffffffff, supervisor, [bcrypt_port_sup]}, + {bcrypt_pool, {bcrypt_pool, start_link, []}, permanent, + 16#ffffffff, worker, [bcrypt_pool]}], + NifChildren + = [{bcrypt_nif_pool_sup, {bcrypt_nif_pool_sup, start_link, []}, permanent, + 16#ffffffff, supervisor, [bcrypt_nif_pool_sup]}], + case application:get_env(bcrypt, mechanism) of + undefined -> {stop, no_mechanism_defined}; + {ok, nif} -> {ok, {{one_for_all, 15, 60}, NifChildren}}; + {ok, port} -> {ok, {{one_for_all, 15, 60}, PortChildren}} + end. |