diff --git a/CHANGELOG.md b/CHANGELOG.md index 43e395c..614b015 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/c_src/enacl.c b/c_src/enacl.c index 3b39796..fa8a71b 100644 --- a/c_src/enacl.c +++ b/c_src/enacl.c @@ -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")); +} \ No newline at end of file diff --git a/c_src/enacl.h b/c_src/enacl.h index e772d1d..3dc3a59 100644 --- a/c_src/enacl.h +++ b/c_src/enacl.h @@ -9,5 +9,6 @@ #define ATOM_FALSE "false" ERL_NIF_TERM enacl_error_tuple(ErlNifEnv *, char *); +ERL_NIF_TERM enacl_internal_error(ErlNifEnv *); #endif diff --git a/c_src/public.c b/c_src/public.c index 3c47bcf..f2113a8 100644 --- a/c_src/public.c +++ b/c_src/public.c @@ -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, - padded_msg.size - crypto_box_BOXZEROBYTES); - ret = enif_make_tuple2(env, ret_ok, ret_bin); + ret = enif_make_sub_binary(env, enif_make_binary(env, &result), + crypto_box_BOXZEROBYTES, + padded_msg.size - crypto_box_BOXZEROBYTES); 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, - m.size - crypto_box_BOXZEROBYTES); - return enif_make_tuple2(env, ret_ok, ret_bin); + return enif_make_sub_binary(env, enif_make_binary(env, &result), + crypto_box_BOXZEROBYTES, + m.size - crypto_box_BOXZEROBYTES); } 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, diff --git a/c_src/randombytes.c b/c_src/randombytes.c index 5c978a8..209f5b7 100644 --- a/c_src/randombytes.c +++ b/c_src/randombytes.c @@ -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); diff --git a/eqc_test/enacl_eqc.erl b/eqc_test/enacl_eqc.erl index 6a43dcf..66781bb 100644 --- a/eqc_test/enacl_eqc.erl +++ b/eqc_test/enacl_eqc.erl @@ -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 -> diff --git a/src/enacl.erl b/src/enacl.erl index 4ee0e73..f54eeaa 100644 --- a/src/enacl.erl +++ b/src/enacl.erl @@ -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(),