Simplify the code base, first round:

* Introduce enacl:verify/0 to verify the integrity of the library.
* Always run keypair functions on the dirty schedulers.
* Do not call NIFs when creating zerobytes. Avoid constructing new binary data, but reuse a constant.
* The box/box_open and box_seal/box_seal_open API is so expensive to call there is little overhead in
  running it on the DS always.
This commit is contained in:
Jesper Louis Andersen 2015-08-23 21:44:28 +02:00
parent ce5f69f9f7
commit a135bce9d3
3 changed files with 48 additions and 80 deletions

View File

@ -1001,11 +1001,12 @@ static ErlNifFunc nif_funcs[] = {
{"crypto_box_PUBLICKEYBYTES", 0, enif_crypto_box_PUBLICKEYBYTES}, {"crypto_box_PUBLICKEYBYTES", 0, enif_crypto_box_PUBLICKEYBYTES},
{"crypto_box_SECRETKEYBYTES", 0, enif_crypto_box_SECRETKEYBYTES}, {"crypto_box_SECRETKEYBYTES", 0, enif_crypto_box_SECRETKEYBYTES},
{"crypto_box_BEFORENMBYTES", 0, enif_crypto_box_BEFORENMBYTES}, {"crypto_box_BEFORENMBYTES", 0, enif_crypto_box_BEFORENMBYTES},
{"crypto_box_keypair", 0, enif_crypto_box_keypair},
{"crypto_box_b", 4, enif_crypto_box}, {"crypto_box_keypair", 0, enif_crypto_box_keypair, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"crypto_box", 4, enif_crypto_box, ERL_NIF_DIRTY_JOB_CPU_BOUND}, {"crypto_box", 4, enif_crypto_box, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"crypto_box_open_b", 4, enif_crypto_box_open},
{"crypto_box_open", 4, enif_crypto_box_open, ERL_NIF_DIRTY_JOB_CPU_BOUND}, {"crypto_box_open", 4, enif_crypto_box_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"crypto_box_beforenm", 2, enif_crypto_box_beforenm}, {"crypto_box_beforenm", 2, enif_crypto_box_beforenm},
{"crypto_box_afternm_b", 3, enif_crypto_box_afternm}, {"crypto_box_afternm_b", 3, enif_crypto_box_afternm},
{"crypto_box_afternm", 3, enif_crypto_box_afternm, ERL_NIF_DIRTY_JOB_CPU_BOUND}, {"crypto_box_afternm", 3, enif_crypto_box_afternm, ERL_NIF_DIRTY_JOB_CPU_BOUND},
@ -1028,9 +1029,7 @@ static ErlNifFunc nif_funcs[] = {
{"crypto_box_SEALBYTES", 0, enif_crypto_box_SEALBYTES}, {"crypto_box_SEALBYTES", 0, enif_crypto_box_SEALBYTES},
{"crypto_box_seal_b", 2, enif_crypto_box_seal},
{"crypto_box_seal", 2, enif_crypto_box_seal, ERL_NIF_DIRTY_JOB_CPU_BOUND}, {"crypto_box_seal", 2, enif_crypto_box_seal, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"crypto_box_seal_open_b", 3, enif_crypto_box_seal_open},
{"crypto_box_seal_open", 3, enif_crypto_box_seal_open, ERL_NIF_DIRTY_JOB_CPU_BOUND}, {"crypto_box_seal_open", 3, enif_crypto_box_seal_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"crypto_secretbox_NONCEBYTES", 0, enif_crypto_secretbox_NONCEBYTES}, {"crypto_secretbox_NONCEBYTES", 0, enif_crypto_secretbox_NONCEBYTES},

View File

@ -91,18 +91,15 @@
randombytes/1 randombytes/1
]). ]).
%% Other helper functions
-export([ -export([
reds/1 verify/0
]). ]).
%% Definitions of system budgets %% Definitions of system budgets
%% To get a grip for these, call `enacl_timing:all/0' on your system. The numbers here are %% To get a grip for these, call `enacl_timing:all/0' on your system. The numbers here are
%% described in the README.md file. %% described in the README.md file.
-define(HASH_SIZE, 32 * 1024). -define(HASH_SIZE, 4 * 1024).
-define(HASH_REDUCTIONS, 104 * 2). -define(HASH_REDUCTIONS, 66).
-define(BOX_SIZE, 32 * 1024).
-define(BOX_REDUCTIONS, 115 * 2).
-define(BOX_BEFORENM_REDUCTIONS, 60). -define(BOX_BEFORENM_REDUCTIONS, 60).
-define(BOX_AFTERNM_SIZE, 64 * 1024). -define(BOX_AFTERNM_SIZE, 64 * 1024).
-define(BOX_AFTERNM_REDUCTIONS, 110 * 2). -define(BOX_AFTERNM_REDUCTIONS, 110 * 2).
@ -118,30 +115,38 @@
-define(ONETIME_AUTH_SIZE, 128 * 1024). -define(ONETIME_AUTH_SIZE, 128 * 1024).
-define(ONETIME_AUTH_REDUCTIONS, 105 * 2). -define(ONETIME_AUTH_REDUCTIONS, 105 * 2).
-define(RANDOMBYTES_SIZE, 1024). -define(RANDOMBYTES_SIZE, 1024).
-define(RANDOMBYTES_REDUCTIONS, 200). -define(RANDOMBYTES_REDUCTIONS, 66).
%% @doc reds/1 counts the number of reductions and scheduler yields for a thunk %% Constants used throughout the code base
%% -define(CRYPTO_BOX_ZEROBYTES, 32).
%% Count reductions and number of scheduler yields for Fun. Fun is assumed -define(P_ZEROBYTES, <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>). %% 32 bytes of 0
%% to be one of the above exor variants. -define(CRYPTO_BOX_BOXZEROBYTES, 16).
%% @end -define(P_BOXZEROBYTES, <<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>).
-spec reds(fun (() -> any())) -> #{ atom() => any() }.
reds(Fun) -> -define(CRYPTO_STREAM_KEYBYTES, 32).
Parent = self(), -define(CRYPTO_STREAM_NONCEBYTES, 24).
Pid = spawn(fun() ->
Self = self(), %% @doc Verify makes sure the constants defined in libsodium matches ours
Start = os:timestamp(), verify() ->
R0 = process_info(Self, reductions), true = equals(binary:copy(<<0>>, enacl_nif:crypto_box_ZEROBYTES()), ?P_ZEROBYTES),
Fun(), true = equals(binary:copy(<<0>>, enacl_nif:crypto_box_BOXZEROBYTES()), ?P_BOXZEROBYTES),
R1 = process_info(Self, reductions), Verifiers = [
T = timer:now_diff(os:timestamp(), Start), {crypto_stream_KEYBYTES, ?CRYPTO_STREAM_KEYBYTES},
Parent ! {Self,#{ time_diff => T, after_reductions => R1, before_reductions => R0}} {crypto_stream_NONCEBYTES, ?CRYPTO_STREAM_NONCEBYTES},
end), {crypto_box_ZEROBYTES, ?CRYPTO_BOX_ZEROBYTES},
receive {crypto_box_BOXZEROBYTES, ?CRYPTO_BOX_BOXZEROBYTES}],
{Pid,Result} -> run_verifiers(Verifiers).
Result
run_verifiers([]) -> ok;
run_verifiers([{V, R} | Vs]) ->
case enacl_nif:V() of
R -> run_verifiers(Vs);
Other -> {error, {verifier, V, {R, '/=', Other}}}
end. end.
equals(X,X) -> true;
equals(X,Y) -> {X, '/=', Y}.
%% Low level helper functions %% Low level helper functions
%% ----------------- %% -----------------
@ -212,12 +217,7 @@ box_keypair() ->
SK :: binary(), SK :: binary(),
CipherText :: binary(). CipherText :: binary().
box(Msg, Nonce, PK, SK) -> box(Msg, Nonce, PK, SK) ->
case iolist_size(Msg) of enacl_nif:crypto_box([?P_ZEROBYTES, Msg], Nonce, PK, SK).
K when K =< ?BOX_SIZE ->
bump(enacl_nif:crypto_box_b([p_zerobytes(), Msg], Nonce, PK, SK), ?BOX_REDUCTIONS, ?BOX_SIZE, K);
_ ->
enacl_nif:crypto_box([p_zerobytes(), Msg], Nonce, PK, SK)
end.
%% @doc box_open/4 decrypts+verifies a message from another party. %% @doc box_open/4 decrypts+verifies a message from another party.
%% %%
@ -232,19 +232,9 @@ box(Msg, Nonce, PK, SK) ->
SK :: binary(), SK :: binary(),
Msg :: binary(). Msg :: binary().
box_open(CipherText, Nonce, PK, SK) -> box_open(CipherText, Nonce, PK, SK) ->
case iolist_size(CipherText) of case enacl_nif:crypto_box_open([?P_BOXZEROBYTES, CipherText], Nonce, PK, SK) of
K when K =< ?BOX_SIZE -> {error, Err} -> {error, Err};
R = Bin when is_binary(Bin) -> {ok, Bin}
case enacl_nif:crypto_box_open_b([p_box_zerobytes(), CipherText], Nonce, PK, SK) of
{error, Err} -> {error, Err};
Bin when is_binary(Bin) -> {ok, Bin}
end,
bump(R, ?BOX_REDUCTIONS, ?BOX_SIZE, K);
_ ->
case enacl_nif:crypto_box_open([p_box_zerobytes(), CipherText], Nonce, PK, SK) of
{error, Err} -> {error, Err};
Bin when is_binary(Bin) -> {ok, Bin}
end
end. end.
%% @doc box_beforenm/2 precomputes a box shared key for a PK/SK keypair %% @doc box_beforenm/2 precomputes a box shared key for a PK/SK keypair
@ -441,12 +431,7 @@ box_secret_key_bytes() ->
PK :: binary(), PK :: binary(),
SealedCipherText :: binary(). SealedCipherText :: binary().
box_seal(Msg, PK) -> box_seal(Msg, PK) ->
case iolist_size(Msg) of enacl_nif:crypto_box_seal(Msg, PK).
K when K =< ?BOX_SIZE ->
bump(enacl_nif:crypto_box_seal_b(Msg, PK), ?BOX_REDUCTIONS, ?BOX_SIZE, K);
_ ->
enacl_nif:crypto_box_seal(Msg, PK)
end.
%% @doc seal_box_open/3 decrypts+check message integrity from an unknown sender. %% @doc seal_box_open/3 decrypts+check message integrity from an unknown sender.
%% %%
@ -460,18 +445,9 @@ box_seal(Msg, PK) ->
SK :: binary(), SK :: binary(),
Msg :: binary(). Msg :: binary().
box_seal_open(SealedCipherText, PK, SK) -> box_seal_open(SealedCipherText, PK, SK) ->
case iolist_size(SealedCipherText) of case enacl_nif:crypto_box_seal_open(SealedCipherText, PK, SK) of
K when K =< ?BOX_SIZE -> {error, Err} -> {error, Err};
R = case enacl_nif:crypto_box_seal_open_b(SealedCipherText, PK, SK) of Bin when is_binary(Bin) -> {ok, Bin}
{error, Err} -> {error, Err};
Bin when is_binary(Bin) -> {ok, Bin}
end,
bump(R, ?BOX_REDUCTIONS, ?BOX_SIZE, K);
_ ->
case enacl_nif:crypto_box_seal_open(SealedCipherText, PK, SK) of
{error, Err} -> {error, Err};
Bin when is_binary(Bin) -> {ok, Bin}
end
end. end.
%% @doc secretbox/3 encrypts a message with a key %% @doc secretbox/3 encrypts a message with a key
@ -540,12 +516,12 @@ secretbox_key_size() ->
%% @doc stream_nonce_size/0 returns the byte size of the nonce for streams %% @doc stream_nonce_size/0 returns the byte size of the nonce for streams
%% @end %% @end
-spec stream_nonce_size() -> pos_integer(). -spec stream_nonce_size() -> pos_integer().
stream_nonce_size() -> enacl_nif:crypto_stream_NONCEBYTES(). stream_nonce_size() -> ?CRYPTO_STREAM_NONCEBYTES.
%% @doc stream_key_size/0 returns the byte size of the key for streams %% @doc stream_key_size/0 returns the byte size of the key for streams
%% @end %% @end
-spec stream_key_size() -> pos_integer(). -spec stream_key_size() -> pos_integer().
stream_key_size() -> enacl_nif:crypto_stream_KEYBYTES(). stream_key_size() -> ?CRYPTO_STREAM_KEYBYTES.
%% @doc stream/3 produces a cryptographic stream suitable for secret-key encryption %% @doc stream/3 produces a cryptographic stream suitable for secret-key encryption
%% %%

View File

@ -12,11 +12,10 @@
crypto_box_ZEROBYTES/0, crypto_box_ZEROBYTES/0,
crypto_box_BEFORENMBYTES/0, crypto_box_BEFORENMBYTES/0,
crypto_box/4,
crypto_box_b/4,
crypto_box_keypair/0, crypto_box_keypair/0,
crypto_box/4,
crypto_box_open/4, crypto_box_open/4,
crypto_box_open_b/4,
crypto_box_beforenm/2, crypto_box_beforenm/2,
crypto_box_afternm/3, crypto_box_afternm/3,
@ -39,8 +38,6 @@
crypto_sign_verify_detached_b/3, crypto_sign_verify_detached_b/3,
crypto_box_seal/2, crypto_box_seal/2,
crypto_box_seal_b/2,
crypto_box_seal_open_b/3,
crypto_box_seal_open/3, crypto_box_seal_open/3,
crypto_box_SEALBYTES/0 crypto_box_SEALBYTES/0
@ -137,9 +134,7 @@ crypto_box_BEFORENMBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_box_keypair() -> erlang:nif_error(nif_not_loaded). crypto_box_keypair() -> erlang:nif_error(nif_not_loaded).
crypto_box(_PaddedMsg, _Nonce, _PK, _SK) -> erlang:nif_error(nif_not_loaded). crypto_box(_PaddedMsg, _Nonce, _PK, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_box_b(_PaddedMsg, _Nonce, _PK, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_box_open(_CipherText, _Nonce, _PK, _SK) -> erlang:nif_error(nif_not_loaded). crypto_box_open(_CipherText, _Nonce, _PK, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_box_open_b(_CipherText, _Nonce, _PK, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_box_beforenm(_PK, _SK) -> erlang:nif_error(nif_not_loaded). crypto_box_beforenm(_PK, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_box_afternm(_M, _Nonce, _K) -> erlang:nif_error(nif_not_loaded). crypto_box_afternm(_M, _Nonce, _K) -> erlang:nif_error(nif_not_loaded).
@ -162,9 +157,7 @@ crypto_sign_detached_b(_M, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_sign_verify_detached(_Sig, _M, _PK) -> erlang:nif_error(nif_not_loaded). crypto_sign_verify_detached(_Sig, _M, _PK) -> erlang:nif_error(nif_not_loaded).
crypto_sign_verify_detached_b(_Sig, _M, _PK) -> erlang:nif_error(nif_not_loaded). crypto_sign_verify_detached_b(_Sig, _M, _PK) -> erlang:nif_error(nif_not_loaded).
crypto_box_seal_b(_Msg, _PK) -> erlang:nif_error(nif_not_loaded).
crypto_box_seal(_Msg, _PK) -> erlang:nif_error(nif_not_loaded). crypto_box_seal(_Msg, _PK) -> erlang:nif_error(nif_not_loaded).
crypto_box_seal_open_b(_CipherText, _PK, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_box_seal_open(_CipherText, _PK, _SK) -> erlang:nif_error(nif_not_loaded). crypto_box_seal_open(_CipherText, _PK, _SK) -> erlang:nif_error(nif_not_loaded).
crypto_box_SEALBYTES() -> erlang:nif_error(nif_not_loaded). crypto_box_SEALBYTES() -> erlang:nif_error(nif_not_loaded).