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]
- 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.
- AEAD
- enacl
- hash
- kx
- generichash
- pwhash
- randombytes
- secret
@ -25,8 +26,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
### Compatibility
- Many functions returned the type `value() | {error, term()}`. They have been
updated to return the more erlang-idiomatic `{ok, value()} | {error, term()}`.
- Some functions have been streamlined to badarg in certain cases where it made more
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
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

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"),
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"
ERL_NIF_TERM enacl_error_tuple(ErlNifEnv *, char *);
ERL_NIF_TERM enacl_internal_error(ErlNifEnv *);
#endif

View File

@ -90,21 +90,17 @@ ERL_NIF_TERM enacl_crypto_box(ErlNifEnv *env, int argc,
goto bad_arg;
if (!enif_alloc_binary(padded_msg.size, &result)) {
ret = enacl_error_tuple(env, "alloc_failed");
goto done;
}
if (0 != crypto_box(result.data, padded_msg.data, padded_msg.size, nonce.data,
pk.data, sk.data)) {
ret = enacl_error_tuple(env, "box_error");
goto release;
}
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin = enif_make_sub_binary(
env, enif_make_binary(env, &result), crypto_box_BOXZEROBYTES,
ret = enif_make_sub_binary(env, enif_make_binary(env, &result),
crypto_box_BOXZEROBYTES,
padded_msg.size - crypto_box_BOXZEROBYTES);
ret = enif_make_tuple2(env, ret_ok, ret_bin);
goto done;
@ -112,6 +108,8 @@ bad_arg:
return enif_make_badarg(env);
release:
enif_release_binary(&result);
err:
ret = enacl_internal_error(env);
done:
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)) {
return enacl_error_tuple(env, "alloc_failed");
return enacl_internal_error(env);
}
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)) {
return enacl_error_tuple(env, "alloc_failed");
goto err;
}
if (0 != crypto_box_beforenm(k.data, pk.data, sk.data)) {
// error
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);
ERL_NIF_TERM ret_bin = enif_make_binary(env, &k);
return enif_make_tuple2(env, ret_ok, ret_bin);
return enif_make_binary(env, &k);
err:
return enacl_internal_error(env);
}
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)) {
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);
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin = enif_make_sub_binary(
env, enif_make_binary(env, &result), crypto_box_BOXZEROBYTES,
return enif_make_sub_binary(env, enif_make_binary(env, &result),
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,
@ -222,7 +218,7 @@ ERL_NIF_TERM enacl_crypto_box_open_afternm(ErlNifEnv *env, int argc,
}
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,
@ -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)) {
return enacl_error_tuple(env, "alloc_failed");
return enacl_internal_error(env);
}
crypto_box_seal(ciphertext.data, msg.data, msg.size, key.data);
ERL_NIF_TERM ret_ok = enif_make_atom(env, ATOM_OK);
ERL_NIF_TERM ret_bin = enif_make_binary(env, &ciphertext);
return enif_make_tuple2(env, ret_ok, ret_bin);
return enif_make_binary(env, &ciphertext);
}
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)) {
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,

View File

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

View File

@ -183,10 +183,10 @@ prop_box_correct() ->
begin
case v_iodata(Msg) andalso nonce_valid(Nonce) andalso keypair_valid(PK1, SK1) andalso keypair_valid(PK2, SK2) of
true ->
{ok, Key} = enacl:box_beforenm(PK2, SK1),
{ok, Key} = enacl:box_beforenm(PK1, SK2),
{ok, CipherText} = enacl:box(Msg, Nonce, PK2, SK1),
{ok, CipherText} = enacl:box_afternm(Msg, Nonce, Key),
Key = enacl:box_beforenm(PK2, SK1),
Key = enacl:box_beforenm(PK1, SK2),
CipherText = enacl:box(Msg, Nonce, PK2, SK1),
CipherText = enacl:box_afternm(Msg, Nonce, Key),
{ok, DecodedMsg} = enacl:box_open(CipherText, Nonce, PK1, SK2),
{ok, DecodedMsg} = enacl:box_open_afternm(CipherText, Nonce, Key),
equals(iolist_to_binary(Msg), DecodedMsg);
@ -210,8 +210,8 @@ prop_box_failure_integrity() ->
andalso keypair_valid(PK1, SK1)
andalso keypair_valid(PK2, SK2) of
true ->
{ok, Key} = enacl:box_beforenm(PK2, SK1),
{ok, CipherText} = enacl:box(Msg, Nonce, PK2, SK1),
Key = enacl:box_beforenm(PK2, SK1),
CipherText = enacl:box(Msg, Nonce, PK2, SK1),
Err = enacl:box_open([<<"x">>, CipherText], Nonce, PK1, SK2),
Err = enacl:box_open_afternm([<<"x">>, CipherText], Nonce, Key),
equals(Err, {error, failed_verification});
@ -431,7 +431,7 @@ prop_seal_box_failure_integrity() ->
begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true ->
{ok, CT} = enacl:box_seal(Msg, PK1),
CT = enacl:box_seal(Msg, PK1),
Err = enacl:box_seal_open([<<"x">>, CT], PK1, SK1),
equals(Err, {error, failed_verification});
false ->
@ -450,7 +450,7 @@ prop_seal_box_correct() ->
begin
case v_iodata(Msg) andalso keypair_valid(PK1, SK1) of
true ->
{ok, SealedCipherText} = enacl:box_seal(Msg, PK1),
SealedCipherText = enacl:box_seal(Msg, PK1),
{ok, DecodedMsg} = enacl:box_seal_open(SealedCipherText, PK1, SK1),
equals(iolist_to_binary(Msg), DecodedMsg);
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
%% authenticate yourself. Requires a `Nonce' in addition. Returns the ciphered message.
%% @end
-spec box(Msg, Nonce, PK, SK) -> {ok, CipherText} | {error, term()}
-spec box(Msg, Nonce, PK, SK) -> CipherText
when
Msg :: iodata(),
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
%% @end
-spec box_beforenm(PK, SK) -> {ok, binary()} | {error, term()}
-spec box_beforenm(PK, SK) -> binary()
when
PK :: 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,
%% and thus is a much faster operation.
%% @end
-spec box_afternm(Msg, Nonce, K) -> {ok, CipherText} | {error, term()}
-spec box_afternm(Msg, Nonce, K) -> CipherText
when
Msg :: iodata(),
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
%% enciphered message `SealedCipherText' which includes ephemeral public key at head.
%% @end
-spec box_seal(Msg, PK) -> {ok, SealedCipherText} | {error, term()}
-spec box_seal(Msg, PK) -> SealedCipherText
when
Msg :: iodata(),
PK :: binary(),