Decide on an even better API

This commit is contained in:
Jesper Louis Andersen 2020-02-04 14:00:02 +01:00
parent aa2c69529a
commit 59b94439d1
7 changed files with 44 additions and 41 deletions

View File

@ -7,12 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [TODO] ## [TODO]
- Go through all calls and make them return {ok, _} | {error, _} if applicable. - Go through all calls and make them return streamlined exceptions if applicable.
Pretty large change, but OTOH, this ought to happen before a 1.0 release as well. Pretty large change, but OTOH, this ought to happen before a 1.0 release as well.
- AEAD - AEAD
- enacl - enacl
- hash - hash
- kx - kx
- generichash
- pwhash - pwhash
- randombytes - randombytes
- secret - secret
@ -25,8 +26,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased] ## [Unreleased]
### Compatibility ### Compatibility
- Many functions returned the type `value() | {error, term()}`. They have been - Some functions have been streamlined to badarg in certain cases where it made more
updated to return the more erlang-idiomatic `{ok, value()} | {error, term()}`. sense to do so than returning back an error to the caller.
- Functions generally don't return error values for internal errors. They now raise
exceptions when this happens. If you can't allocate a binary, there is usually not
much the programmer can do with that information, sans crashing.
- If you used `aead_chacha20poly1305_*` functions, please read through the changelog - If you used `aead_chacha20poly1305_*` functions, please read through the changelog
carefully as we have made changes to these functions. TL;DR: look for carefully as we have made changes to these functions. TL;DR: look for
`aead_chacha20poly1305_ietf_*` but note it is *not* just a simple substitution `aead_chacha20poly1305_ietf_*` but note it is *not* just a simple substitution

View File

@ -6,3 +6,7 @@ ERL_NIF_TERM enacl_error_tuple(ErlNifEnv *env, char *error_atom) {
return enif_make_tuple2(env, enif_make_atom(env, "error"), return enif_make_tuple2(env, enif_make_atom(env, "error"),
enif_make_atom(env, error_atom)); enif_make_atom(env, error_atom));
} }
ERL_NIF_TERM enacl_internal_error(ErlNifEnv *env) {
return enif_raise_exception(env, enif_make_atom(env, "internal_error"));
}

View File

@ -9,5 +9,6 @@
#define ATOM_FALSE "false" #define ATOM_FALSE "false"
ERL_NIF_TERM enacl_error_tuple(ErlNifEnv *, char *); ERL_NIF_TERM enacl_error_tuple(ErlNifEnv *, char *);
ERL_NIF_TERM enacl_internal_error(ErlNifEnv *);
#endif #endif

View File

@ -90,21 +90,17 @@ ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc,
goto bad_arg; goto bad_arg;
if (!enif_alloc_binary(padded_msg.size, &result)) { if (!enif_alloc_binary(padded_msg.size, &result)) {
ret = enacl_error_tuple(env, "alloc_failed");
goto done; goto done;
} }
if (0 != crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data, if (0 != crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data,
pk.data, sk.data)) { pk.data, sk.data)) {
ret = enacl_error_tuple(env, "box_error");
goto release; goto release;
} }
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK); ret = enif_make_sub_binary(env, enif_make_binary(env, &result),
ERL_NIF_TERM ret_bin = enif_make_sub_binary( crypto_box_BOXZEROBYTES,
env, enif_make_binary(env, &result), crypto_box_BOXZEROBYTES, padded_msg.size - crypto_box_BOXZEROBYTES);
padded_msg.size - crypto_box_BOXZEROBYTES);
ret = enif_make_tuple2(env, ret_ok, ret_bin);
goto done; goto done;
@ -112,6 +108,8 @@ bad_arg:
return enif_make_badarg(env); return enif_make_badarg(env);
release: release:
enif_release_binary(&result); enif_release_binary(&result);
err:
ret = enacl_internal_error(env);
done: done:
return ret; return ret;
} }
@ -136,7 +134,7 @@ ERL_NIF_TERM enacl_crypto_box_open(ErlNifEnv *env, int argc,
} }
if (!enif_alloc_binary(padded_ciphertext.size, &result)) { if (!enif_alloc_binary(padded_ciphertext.size, &result)) {
return enacl_error_tuple(env, "alloc_failed"); return enacl_internal_error(env);
} }
if (0 != crypto_box_open(result.data, padded_ciphertext.data, if (0 != crypto_box_open(result.data, padded_ciphertext.data,
@ -168,18 +166,18 @@ ERL_NIF_TERM enacl_crypto_box_beforenm(ErlNifEnv *env, int argc,
} }
if (!enif_alloc_binary(crypto_box_BEFORENMBYTES, &k)) { if (!enif_alloc_binary(crypto_box_BEFORENMBYTES, &k)) {
return enacl_error_tuple(env, "alloc_failed"); goto err;
} }
if (0 != crypto_box_beforenm(k.data, pk.data, sk.data)) { if (0 != crypto_box_beforenm(k.data, pk.data, sk.data)) {
// error // error
enif_release_binary(&k); enif_release_binary(&k);
return enacl_error_tuple(env, "error_gen_shared_secret"); goto err;
} }
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK); return enif_make_binary(env, &k);
ERL_NIF_TERM ret_bin = enif_make_binary(env, &k); err:
return enif_make_tuple2(env, ret_ok, ret_bin); return enacl_internal_error(env);
} }
ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc, ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc,
@ -196,16 +194,14 @@ ERL_NIF_TERM enacl_crypto_box_afternm(ErlNifEnv *env, int argc,
} }
if (!enif_alloc_binary(m.size, &result)) { if (!enif_alloc_binary(m.size, &result)) {
return enacl_error_tuple(env, "alloc_failed"); return enacl_internal_error(env);
} }
crypto_box_afternm(result.data, m.data, m.size, nonce.data, k.data); crypto_box_afternm(result.data, m.data, m.size, nonce.data, k.data);
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK); return enif_make_sub_binary(env, enif_make_binary(env, &result),
ERL_NIF_TERM ret_bin = enif_make_sub_binary( crypto_box_BOXZEROBYTES,
env, enif_make_binary(env, &result), crypto_box_BOXZEROBYTES, m.size - crypto_box_BOXZEROBYTES);
m.size - crypto_box_BOXZEROBYTES);
return enif_make_tuple2(env, ret_ok, ret_bin);
} }
ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc, ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc,
@ -222,7 +218,7 @@ ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc,
} }
if (!enif_alloc_binary(m.size, &result)) { if (!enif_alloc_binary(m.size, &result)) {
return enacl_error_tuple(env, "alloc_failed"); return enacl_internal_error(env);
} }
if (0 != crypto_box_open_afternm(result.data, m.data, m.size, nonce.data, if (0 != crypto_box_open_afternm(result.data, m.data, m.size, nonce.data,
@ -250,14 +246,12 @@ ERL_NIF_TERM enacl_crypto_box_seal(ErlNifEnv *env, int argc,
} }
if (!enif_alloc_binary(msg.size + crypto_box_SEALBYTES, &ciphertext)) { if (!enif_alloc_binary(msg.size + crypto_box_SEALBYTES, &ciphertext)) {
return enacl_error_tuple(env, "alloc_failed"); return enacl_internal_error(env);
} }
crypto_box_seal(ciphertext.data, msg.data, msg.size, key.data); crypto_box_seal(ciphertext.data, msg.data, msg.size, key.data);
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK); return enif_make_binary(env, &ciphertext);
ERL_NIF_TERM ret_bin = enif_make_binary(env, &ciphertext);
return enif_make_tuple2(env, ret_ok, ret_bin);
} }
ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc, ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc,
@ -276,7 +270,7 @@ ERL_NIF_TERM enacl_crypto_box_seal_open(ErlNifEnv *env, int argc,
} }
if (!enif_alloc_binary(ciphertext.size - crypto_box_SEALBYTES, &msg)) { if (!enif_alloc_binary(ciphertext.size - crypto_box_SEALBYTES, &msg)) {
return enacl_error_tuple(env, "alloc_failed"); return enacl_internal_error(env);
} }
if (crypto_box_seal_open(msg.data, ciphertext.data, ciphertext.size, pk.data, if (crypto_box_seal_open(msg.data, ciphertext.data, ciphertext.size, pk.data,

View File

@ -15,7 +15,7 @@ ERL_NIF_TERM enif_randombytes(ErlNifEnv *env, int argc,
} }
if (!enif_alloc_binary(req_size, &result)) { if (!enif_alloc_binary(req_size, &result)) {
return enacl_error_tuple(env, "alloc_failed"); return enacl_internal_error(env);
} }
randombytes(result.data, result.size); randombytes(result.data, result.size);

View File

@ -183,10 +183,10 @@ prop_box_correct() ->
begin begin
case v_iodata(Msg) andalso nonce_valid(Nonce) andalso keypair_valid(PK1, SK1) andalso keypair_valid(PK2, SK2) of case v_iodata(Msg) andalso nonce_valid(Nonce) andalso keypair_valid(PK1, SK1) andalso keypair_valid(PK2, SK2) of
true -> true ->
{ok, Key} = enacl:box_beforenm(PK2, SK1), Key = enacl:box_beforenm(PK2, SK1),
{ok, Key} = enacl:box_beforenm(PK1, SK2), Key = enacl:box_beforenm(PK1, SK2),
{ok, CipherText} = enacl:box(Msg, Nonce, PK2, SK1), CipherText = enacl:box(Msg, Nonce, PK2, SK1),
{ok, CipherText} = enacl:box_afternm(Msg, Nonce, Key), CipherText = enacl:box_afternm(Msg, Nonce, Key),
{ok, DecodedMsg} = enacl:box_open(CipherText, Nonce, PK1, SK2), {ok, DecodedMsg} = enacl:box_open(CipherText, Nonce, PK1, SK2),
{ok, DecodedMsg} = enacl:box_open_afternm(CipherText, Nonce, Key), {ok, DecodedMsg} = enacl:box_open_afternm(CipherText, Nonce, Key),
equals(iolist_to_binary(Msg), DecodedMsg); equals(iolist_to_binary(Msg), DecodedMsg);
@ -210,8 +210,8 @@ prop_box_failure_integrity() ->
andalso keypair_valid(PK1, SK1) andalso keypair_valid(PK1, SK1)
andalso keypair_valid(PK2, SK2) of andalso keypair_valid(PK2, SK2) of
true -> true ->
{ok, Key} = enacl:box_beforenm(PK2, SK1), Key = enacl:box_beforenm(PK2, SK1),
{ok, CipherText} = enacl:box(Msg, Nonce, PK2, SK1), CipherText = enacl:box(Msg, Nonce, PK2, SK1),
Err = enacl:box_open([<<"x">>, CipherText], Nonce, PK1, SK2), Err = enacl:box_open([<<"x">>, CipherText], Nonce, PK1, SK2),
Err = enacl:box_open_afternm([<<"x">>, CipherText], Nonce, Key), Err = enacl:box_open_afternm([<<"x">>, CipherText], Nonce, Key),
equals(Err, {error, failed_verification}); equals(Err, {error, failed_verification});
@ -431,7 +431,7 @@ prop_seal_box_failure_integrity() ->
begin begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true -> true ->
{ok, CT} = enacl:box_seal(Msg, PK1), CT = enacl:box_seal(Msg, PK1),
Err = enacl:box_seal_open([<<"x">>, CT], PK1, SK1), Err = enacl:box_seal_open([<<"x">>, CT], PK1, SK1),
equals(Err, {error, failed_verification}); equals(Err, {error, failed_verification});
false -> false ->
@ -450,7 +450,7 @@ prop_seal_box_correct() ->
begin begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true -> true ->
{ok, SealedCipherText} = enacl:box_seal(Msg, PK1), SealedCipherText = enacl:box_seal(Msg, PK1),
{ok, DecodedMsg} = enacl:box_seal_open(SealedCipherText, PK1, SK1), {ok, DecodedMsg} = enacl:box_seal_open(SealedCipherText, PK1, SK1),
equals(iolist_to_binary(Msg), DecodedMsg); equals(iolist_to_binary(Msg), DecodedMsg);
false -> false ->

View File

@ -453,7 +453,7 @@ box_keypair() ->
%% Encrypt a `Msg' to the party identified by public key `PK' using your own secret key `SK' to %% Encrypt a `Msg' to the party identified by public key `PK' using your own secret key `SK' to
%% authenticate yourself. Requires a `Nonce' in addition. Returns the ciphered message. %% authenticate yourself. Requires a `Nonce' in addition. Returns the ciphered message.
%% @end %% @end
-spec box(Msg, Nonce, PK, SK) -> {ok, CipherText} | {error, term()} -spec box(Msg, Nonce, PK, SK) -> CipherText
when when
Msg :: iodata(), Msg :: iodata(),
Nonce :: binary(), Nonce :: binary(),
@ -481,7 +481,7 @@ box_open(CipherText, Nonce, PK, SK) ->
%% @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
%% @end %% @end
-spec box_beforenm(PK, SK) -> {ok, binary()} | {error, term()} -spec box_beforenm(PK, SK) -> binary()
when when
PK :: binary(), PK :: binary(),
SK :: binary(). SK :: binary().
@ -496,7 +496,7 @@ box_beforenm(PK, SK) ->
%% if you had called `box(M, Nonce, PK, SK)'. Except that it avoids computations in the elliptic curve Curve25519, %% if you had called `box(M, Nonce, PK, SK)'. Except that it avoids computations in the elliptic curve Curve25519,
%% and thus is a much faster operation. %% and thus is a much faster operation.
%% @end %% @end
-spec box_afternm(Msg, Nonce, K) -> {ok, CipherText} | {error, term()} -spec box_afternm(Msg, Nonce, K) -> CipherText
when when
Msg :: iodata(), Msg :: iodata(),
Nonce :: binary(), Nonce :: binary(),
@ -692,7 +692,7 @@ 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 box_seal(Msg, PK) -> {ok, SealedCipherText} | {error, term()} -spec box_seal(Msg, PK) -> SealedCipherText
when when
Msg :: iodata(), Msg :: iodata(),
PK :: binary(), PK :: binary(),