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:
parent
ce5f69f9f7
commit
a135bce9d3
@ -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},
|
||||||
|
108
src/enacl.erl
108
src/enacl.erl
@ -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
|
||||||
%%
|
%%
|
||||||
|
@ -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).
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user