Commit f444d1e4 authored by Jesper Louis Andersen's avatar Jesper Louis Andersen

Fix box_seal/2 and box_seal_open/3.

* Call the functions `box_seal` and `box_seal_open` to match the libsodium names in module `enacl`.
* Fix a bug in the C NIF: We should fail if the input is `<` SEALBYTES but not on `<=` SEALBYTES. The latter made it impossible to encode empty messages.
* Add variants which run directly on the interpreter scheduler for small messages.

Also:

* Provide full EQC functions for the testing purposes. This generated around 13000 random test cases in a 5 minute run, all passing.# Please enter the commit message for your changes. Lines starting
parent 4676328e
...@@ -598,7 +598,7 @@ ERL_NIF_TERM enif_crypto_box_seal_open(ErlNifEnv *env, int argc, ERL_NIF_TERM co ...@@ -598,7 +598,7 @@ ERL_NIF_TERM enif_crypto_box_seal_open(ErlNifEnv *env, int argc, ERL_NIF_TERM co
return enif_make_badarg(env); return enif_make_badarg(env);
} }
if (ciphertext.size <= crypto_box_SEALBYTES) { if (ciphertext.size < crypto_box_SEALBYTES) {
return enif_make_badarg(env); return enif_make_badarg(env);
} }
...@@ -1027,7 +1027,10 @@ static ErlNifFunc nif_funcs[] = { ...@@ -1027,7 +1027,10 @@ static ErlNifFunc nif_funcs[] = {
{"crypto_sign_verify_detached", 3, enif_crypto_sign_verify_detached, ERL_NIF_DIRTY_JOB_CPU_BOUND}, {"crypto_sign_verify_detached", 3, enif_crypto_sign_verify_detached, ERL_NIF_DIRTY_JOB_CPU_BOUND},
{"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},
......
...@@ -129,6 +129,20 @@ box(Msg, Nonce , PK, SK) -> ...@@ -129,6 +129,20 @@ box(Msg, Nonce , PK, SK) ->
error:badarg -> badarg error:badarg -> badarg
end. end.
box_seal(Msg, PK) ->
try
enacl:box_seal(Msg, PK)
catch
error:badarg -> badarg
end.
box_seal_open(Cph, PK, SK) ->
try
enacl:box_seal_open(Cph, PK, SK)
catch
error:badarg -> badarg
end.
box_open(CphText, Nonce, PK, SK) -> box_open(CphText, Nonce, PK, SK) ->
try try
enacl:box_open(CphText, Nonce, PK, SK) enacl:box_open(CphText, Nonce, PK, SK)
...@@ -137,7 +151,8 @@ box_open(CphText, Nonce, PK, SK) -> ...@@ -137,7 +151,8 @@ box_open(CphText, Nonce, PK, SK) ->
end. end.
failure(badarg) -> true; failure(badarg) -> true;
failure(_) -> false. failure({error, failed_verification}) -> true;
failure(X) -> {failure, X}.
prop_box_correct() -> prop_box_correct() ->
?FORALL({Msg, Nonce, {PK1, SK1}, {PK2, SK2}}, ?FORALL({Msg, Nonce, {PK1, SK1}, {PK2, SK2}},
...@@ -188,6 +203,41 @@ prop_box_failure_integrity() -> ...@@ -188,6 +203,41 @@ prop_box_failure_integrity() ->
end end
end end
end). end).
prop_seal_box_failure_integrity() ->
?FORALL({Msg, {PK1, SK1}}, {fault_rate(1,40,g_iodata()), fault_rate(1,40,keypair())},
begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true ->
CT = enacl:box_seal(Msg, PK1),
Err = enacl:box_seal_open([<<"x">>, CT], PK1, SK1),
equals(Err, {error, failed_verification});
false ->
case box_seal(Msg, PK1) of
badarg -> true;
Res ->
failure(box_seal_open(Res, PK1, SK1))
end
end
end).
prop_seal_box_correct() ->
?FORALL({Msg, {PK1, SK1}},
{fault_rate(1, 40, g_iodata()),
fault_rate(1, 40, keypair())},
begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true ->
SealedCipherText = enacl:box_seal(Msg, PK1),
{ok, DecodedMsg} = enacl:box_seal_open(SealedCipherText, PK1, SK1),
equals(iolist_to_binary(Msg), DecodedMsg);
false ->
case box_seal(Msg, PK1) of
badarg -> true;
Res -> failure(box_seal_open(Res, PK1, SK1))
end
end
end).
%% PRECOMPUTATIONS %% PRECOMPUTATIONS
beforenm_key() -> beforenm_key() ->
......
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
sign_detached/2, sign_detached/2,
sign_verify_detached/3, sign_verify_detached/3,
seal_box/2, box_seal/2,
seal_box_open/3 box_seal_open/3
]). ]).
%% Secret key crypto %% Secret key crypto
...@@ -436,12 +436,17 @@ box_secret_key_bytes() -> ...@@ -436,12 +436,17 @@ box_secret_key_bytes() ->
%% keypair and then uses `box'. Ephemeral public key will sent to other party. Returns the %% keypair and then uses `box'. Ephemeral public key will sent to other party. Returns the
%% enciphered message `SealedCipherText' which includes ephemeral public key at head. %% enciphered message `SealedCipherText' which includes ephemeral public key at head.
%% @end %% @end
-spec seal_box(Msg, PK) -> SealedCipherText -spec box_seal(Msg, PK) -> SealedCipherText
when Msg :: iodata(), when Msg :: iodata(),
PK :: binary(), PK :: binary(),
SealedCipherText :: binary(). SealedCipherText :: binary().
seal_box(Msg, PK) -> box_seal(Msg, PK) ->
enacl_nif:crypto_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.
%% @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.
%% %%
...@@ -449,16 +454,25 @@ seal_box(Msg, PK) -> ...@@ -449,16 +454,25 @@ seal_box(Msg, PK) ->
%% into a `Msg' using that key and your public and secret keys, `PK' and `SK'. Returns the %% into a `Msg' using that key and your public and secret keys, `PK' and `SK'. Returns the
%% plaintext message. %% plaintext message.
%% @end %% @end
-spec seal_box_open(SealedCipherText, PK, SK) -> {ok, Msg} | {error, failed_verification} -spec box_seal_open(SealedCipherText, PK, SK) -> {ok, Msg} | {error, failed_verification}
when SealedCipherText :: iodata(), when SealedCipherText :: iodata(),
PK :: binary(), PK :: binary(),
SK :: binary(), SK :: binary(),
Msg :: binary(). Msg :: binary().
seal_box_open(SealedCipherText, PK, SK) -> box_seal_open(SealedCipherText, PK, SK) ->
case enacl_nif:crypto_box_seal_open(SealedCipherText, PK, SK) of case iolist_size(SealedCipherText) of
{error, Err} -> {error, Err}; K when K =< ?BOX_SIZE ->
Bin when is_binary(Bin) -> Bin R = case enacl_nif:crypto_box_seal_open_b(SealedCipherText, PK, SK) of
end. {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.
%% @doc secretbox/3 encrypts a message with a key %% @doc secretbox/3 encrypts a message with a key
%% %%
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
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
...@@ -160,7 +162,9 @@ crypto_sign_detached_b(_M, _SK) -> erlang:nif_error(nif_not_loaded). ...@@ -160,7 +162,9 @@ 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).
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment