From a135bce9d3dcccf40d95ff2db4a3c4cef28ed965 Mon Sep 17 00:00:00 2001 From: Jesper Louis Andersen Date: Sun, 23 Aug 2015 21:44:28 +0200 Subject: [PATCH] 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. --- c_src/enacl_nif.c | 9 ++-- src/enacl.erl | 108 ++++++++++++++++++---------------------------- src/enacl_nif.erl | 11 +---- 3 files changed, 48 insertions(+), 80 deletions(-) diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index db6b0de..d24b015 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -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}, diff --git a/src/enacl.erl b/src/enacl.erl index d7f441c..194fc5b 100644 --- a/src/enacl.erl +++ b/src/enacl.erl @@ -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 %% diff --git a/src/enacl_nif.erl b/src/enacl_nif.erl index a89c765..8f1d6b2 100644 --- a/src/enacl_nif.erl +++ b/src/enacl_nif.erl @@ -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).