Add access to secretbox_easy/easy_open functions

They are just a simplification of the secretbox API, thus it does
not provide any new functionality. But it helps mapping function
names to libsodium documentation.
This commit is contained in:
Hans Svensson 2022-01-06 18:26:21 +01:00
parent 67fceef42c
commit fa94eaf6f6
6 changed files with 162 additions and 0 deletions

View File

@ -256,6 +256,12 @@ static ErlNifFunc nif_funcs[] = {
{"crypto_secretbox_open_b", 3, enacl_crypto_secretbox_open},
erl_nif_dirty_job_cpu_bound_macro("crypto_secretbox_open", 3,
enacl_crypto_secretbox_open),
{"crypto_secretbox_easy_b", 3, enacl_crypto_secretbox_easy},
erl_nif_dirty_job_cpu_bound_macro("crypto_secretbox_easy", 3,
enacl_crypto_secretbox_easy),
{"crypto_secretbox_open_easy_b", 3, enacl_crypto_secretbox_open_easy},
erl_nif_dirty_job_cpu_bound_macro("crypto_secretbox_open_easy", 3,
enacl_crypto_secretbox_open_easy),
{"crypto_stream_chacha20_KEYBYTES", 0,
enacl_crypto_stream_chacha20_KEYBYTES},

View File

@ -137,6 +137,64 @@ ERL_NIF_TERM enacl_crypto_secretbox_open(ErlNifEnv *env, int argc,
return enif_make_tuple2(env, ret_ok, ret_bin);
}
ERL_NIF_TERM enacl_crypto_secretbox_easy(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key, nonce, msg, cipherbox;
if ((argc != 3) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &msg)) ||
(!enif_inspect_binary(env, argv[1], &nonce)) ||
(!enif_inspect_binary(env, argv[2], &key))) {
return enif_make_badarg(env);
}
if ((key.size != crypto_secretbox_KEYBYTES) ||
(nonce.size != crypto_secretbox_NONCEBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(msg.size + crypto_secretbox_MACBYTES, &cipherbox)) {
return enacl_internal_error(env);
}
crypto_secretbox_easy(cipherbox.data, msg.data, msg.size,
nonce.data, key.data);
return enif_make_binary(env, &cipherbox);
}
ERL_NIF_TERM enacl_crypto_secretbox_open_easy(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary key, nonce, cipherbox, msg;
if ((argc != 3) ||
(!enif_inspect_iolist_as_binary(env, argv[0], &cipherbox)) ||
(!enif_inspect_binary(env, argv[1], &nonce)) ||
(!enif_inspect_binary(env, argv[2], &key))) {
return enif_make_badarg(env);
}
if ((key.size != crypto_secretbox_KEYBYTES) ||
(nonce.size != crypto_secretbox_NONCEBYTES) ||
(cipherbox.size < crypto_secretbox_MACBYTES)) {
return enif_make_badarg(env);
}
if (!enif_alloc_binary(cipherbox.size - crypto_secretbox_MACBYTES, &msg)) {
return enacl_internal_error(env);
}
if (crypto_secretbox_open_easy(msg.data, cipherbox.data, cipherbox.size,
nonce.data, key.data) != 0) {
enif_release_binary(&msg);
return enacl_error_tuple(env, "failed_verification");
}
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin = enif_make_binary(env, &msg);
return enif_make_tuple2(env, ret_ok, ret_bin);
}
ERL_NIF_TERM enacl_crypto_stream_chacha20(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ErlNifBinary c, n, k;

View File

@ -43,6 +43,12 @@ ERL_NIF_TERM enacl_crypto_secretbox(ErlNifEnv *env, int argc,
ERL_NIF_TERM enacl_crypto_secretbox_open(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_secretbox_easy(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_secretbox_open_easy(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM enacl_crypto_stream_chacha20(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);

View File

@ -550,6 +550,44 @@ prop_secretbox_failure_integrity() ->
equals(Err, {error, failed_verification})
end).
secretbox_easy(Msg, Nonce, Key) ->
try enacl:secretbox_easy(Msg, Nonce, Key)
catch error:badarg -> badarg
end.
secretbox_open_easy(Msg, Nonce, Key) ->
try enacl:secretbox_open_easy(Msg, Nonce, Key)
catch error:badarg -> badarg
end.
prop_secretbox_easy_correct() ->
?FORALL({Msg, Nonce, Key},
{?FAULT_RATE(1, 40, g_iodata()),
?FAULT_RATE(1, 40, nonce()),
?FAULT_RATE(1, 40, secret_key())},
begin
case v_iodata(Msg) andalso nonce_valid(Nonce) andalso secret_key_valid(Key) of
true ->
CipherText = enacl:secretbox_easy(Msg, Nonce, Key),
{ok, DecodedMsg} = enacl:secretbox_open_easy(CipherText, Nonce, Key),
equals(iolist_to_binary(Msg), DecodedMsg);
false ->
case secretbox_easy(Msg, Nonce, Key) of
badarg -> true;
Res ->
failure(secretbox_open_easy(Res, Nonce, Key))
end
end
end).
prop_secretbox_easy_failure_integrity() ->
?FORALL({Msg, Nonce, Key}, {g_iodata(), nonce(), secret_key()},
begin
CipherText = enacl:secretbox_easy(Msg, Nonce, Key),
Err = enacl:secretbox_open_easy([<<"x">>, CipherText], Nonce, Key),
equals(Err, {error, failed_verification})
end).
%% AEAD ChaCha20Poly1305
%% ------------------------------------------------------------
%% * aead_chacha20poly1305_encrypt/4,

View File

@ -59,6 +59,8 @@
secretbox_NONCEBYTES/0,
secretbox/3,
secretbox_open/3,
secretbox_easy/3,
secretbox_open_easy/3,
%% No Tests!
stream_chacha20_KEYBYTES/0,
@ -837,6 +839,50 @@ secretbox_open(CipherText, Nonce, Key) ->
enacl_nif:crypto_secretbox_open([?S_BOXZEROBYTES, CipherText], Nonce, Key)
end.
%% @doc secretbox_easy/3 encrypts a message with a key (and nonce)
%%
%% Given a `Msg', a `Nonce' and a `Key' encrypt the message with the Key while taking the
%% nonce into consideration. `easy' refers to not having to take padding, etc. into
%% account. The function returns the Box obtained from the encryption.
%% @end
-spec secretbox_easy(Msg, Nonce, Key) -> Box
when
Msg :: iodata(),
Nonce :: binary(),
Key :: binary(),
Box :: binary().
secretbox_easy(Msg, Nonce, Key) ->
case iolist_size(Msg) of
K when K =< ?SECRETBOX_SIZE ->
bump(enacl_nif:crypto_secretbox_easy_b(Msg, Nonce, Key),
?SECRETBOX_REDUCTIONS,
?SECRETBOX_SIZE,
K);
_ ->
enacl_nif:crypto_secretbox_easy(Msg, Nonce, Key)
end.
%% @doc secretbox_open_easy/3 opens a sealed box.
%%
%% Given a boxed `CipherText' and given we know the used `Nonce' and `Key' we can open the box
%% to obtain the `Msg' within. `easy' refers to not having to take padding, etc. into
%% account. Returns either `{ok, Msg}' or `{error, failed_verification}'.
%% @end
-spec secretbox_open_easy(CipherText, Nonce, Key) -> {ok, Msg} | {error, failed_verification}
when
CipherText :: iodata(),
Nonce :: binary(),
Key :: binary(),
Msg :: binary().
secretbox_open_easy(CipherText, Nonce, Key) ->
case iolist_size(CipherText) of
K when K =< ?SECRETBOX_SIZE ->
R = enacl_nif:crypto_secretbox_open_easy_b(CipherText, Nonce, Key),
bump(R, ?SECRETBOX_OPEN_REDUCTIONS, ?SECRETBOX_SIZE, K);
_ ->
enacl_nif:crypto_secretbox_open_easy(CipherText, Nonce, Key)
end.
%% @doc secretbox_NONCEBYTES()/0 returns the size of the secretbox nonce
%%
%% When encrypting with a secretbox, the nonce must have this size

View File

@ -57,6 +57,10 @@
crypto_secretbox_b/3,
crypto_secretbox_open/3,
crypto_secretbox_open_b/3,
crypto_secretbox_easy/3,
crypto_secretbox_easy_b/3,
crypto_secretbox_open_easy/3,
crypto_secretbox_open_easy_b/3,
crypto_stream_chacha20_KEYBYTES/0,
crypto_stream_chacha20_NONCEBYTES/0,
@ -303,6 +307,10 @@ crypto_secretbox(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_easy(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_easy_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open_easy(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_secretbox_open_easy_b(_Msg, _Nonce, _Key) -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20_KEYBYTES() -> erlang:nif_error(nif_not_loaded).
crypto_stream_chacha20_NONCEBYTES() -> erlang:nif_error(nif_not_loaded).