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_SECRETKEYBYTES", 0, enif_crypto_box_SECRETKEYBYTES},
{"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_open_b", 4, enif_crypto_box_open},
{"crypto_box_open", 4, enif_crypto_box_open, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"crypto_box_beforenm", 2, enif_crypto_box_beforenm},
{"crypto_box_afternm_b", 3, enif_crypto_box_afternm},
{"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_seal_b", 2, enif_crypto_box_seal},
{"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_secretbox_NONCEBYTES", 0, enif_crypto_secretbox_NONCEBYTES},

View File

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

View File

@ -12,11 +12,10 @@
crypto_box_ZEROBYTES/0,
crypto_box_BEFORENMBYTES/0,
crypto_box/4,
crypto_box_b/4,
crypto_box_keypair/0,
crypto_box/4,
crypto_box_open/4,
crypto_box_open_b/4,
crypto_box_beforenm/2,
crypto_box_afternm/3,
@ -39,8 +38,6 @@
crypto_sign_verify_detached_b/3,
crypto_box_seal/2,
crypto_box_seal_b/2,
crypto_box_seal_open_b/3,
crypto_box_seal_open/3,
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(_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_b(_CipherText, _Nonce, _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).
@ -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_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_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_SEALBYTES() -> erlang:nif_error(nif_not_loaded).