diff --git a/c_src/enacl_nif.c b/c_src/enacl_nif.c index ded376c..78ca59e 100644 --- a/c_src/enacl_nif.c +++ b/c_src/enacl_nif.c @@ -1489,6 +1489,93 @@ enif_crypto_aead_chacha20poly1305_decrypt(ErlNifEnv *env, int argc, return result; } +/* + * AEAD XChaCha20 Poly1305 + */ +static ERL_NIF_TERM +enif_crypto_aead_xchacha20poly1305_KEYBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_aead_xchacha20poly1305_ietf_KEYBYTES); +} + +static ERL_NIF_TERM +enif_crypto_aead_xchacha20poly1305_NPUBBYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_aead_xchacha20poly1305_ietf_NPUBBYTES); +} + +static ERL_NIF_TERM +enif_crypto_aead_xchacha20poly1305_ABYTES(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, crypto_aead_xchacha20poly1305_ietf_ABYTES); +} + +static ERL_NIF_TERM +enif_crypto_aead_xchacha20poly1305_MESSAGEBYTES_MAX(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + return enif_make_int64(env, + crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX); +} + +static ERL_NIF_TERM +enif_crypto_aead_xchacha20poly1305_encrypt(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary key, nonce, ad, message, ciphertext; + + if ((argc != 4) || (!enif_inspect_binary(env, argv[0], &key)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &ad)) || + (!enif_inspect_binary(env, argv[3], &message)) || + (key.size != crypto_aead_xchacha20poly1305_ietf_KEYBYTES) || + (nonce.size != crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(message.size + + crypto_aead_xchacha20poly1305_ietf_ABYTES, + &ciphertext)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (crypto_aead_xchacha20poly1305_ietf_encrypt( + ciphertext.data, NULL, message.data, message.size, ad.data, ad.size, + NULL, nonce.data, key.data) < 0) { + return nacl_error_tuple(env, "aead_xchacha20poly1305_ietf_encrypt_failed"); + } + + return enif_make_binary(env, &ciphertext); +} + +static ERL_NIF_TERM +enif_crypto_aead_xchacha20poly1305_decrypt(ErlNifEnv *env, int argc, + ERL_NIF_TERM const argv[]) { + ErlNifBinary key, nonce, ad, message, ciphertext; + + if ((argc != 4) || (!enif_inspect_binary(env, argv[0], &key)) || + (!enif_inspect_binary(env, argv[1], &nonce)) || + (!enif_inspect_binary(env, argv[2], &ad)) || + (!enif_inspect_binary(env, argv[3], &ciphertext)) || + (ciphertext.size < crypto_aead_xchacha20poly1305_ietf_ABYTES) || + (key.size != crypto_aead_xchacha20poly1305_ietf_KEYBYTES) || + (nonce.size != crypto_aead_xchacha20poly1305_ietf_NPUBBYTES)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(ciphertext.size - + crypto_aead_xchacha20poly1305_ietf_ABYTES, + &message)) { + return nacl_error_tuple(env, "alloc_failed"); + } + + if (crypto_aead_xchacha20poly1305_ietf_decrypt( + message.data, NULL, NULL, ciphertext.data, ciphertext.size, ad.data, + ad.size, nonce.data, key.data) < 0) { + return nacl_error_tuple(env, "aead_xchacha20poly1305_ietf_decrypt_failed"); + } + + return enif_make_binary(env, &message); +} + /* * Generic hash */ @@ -1869,6 +1956,21 @@ static ErlNifFunc nif_funcs[] = { "crypto_aead_chacha20poly1305_decrypt", 4, enif_crypto_aead_chacha20poly1305_decrypt), + {"crypto_aead_xchacha20poly1305_KEYBYTES", 0, + enif_crypto_aead_xchacha20poly1305_KEYBYTES}, + {"crypto_aead_xchacha20poly1305_NPUBBYTES", 0, + enif_crypto_aead_xchacha20poly1305_NPUBBYTES}, + {"crypto_aead_xchacha20poly1305_ABYTES", 0, + enif_crypto_aead_xchacha20poly1305_ABYTES}, + {"crypto_aead_xchacha20poly1305_MESSAGEBYTES_MAX", 0, + enif_crypto_aead_xchacha20poly1305_MESSAGEBYTES_MAX}, + erl_nif_dirty_job_cpu_bound_macro( + "crypto_aead_xchacha20poly1305_encrypt", 4, + enif_crypto_aead_xchacha20poly1305_encrypt), + erl_nif_dirty_job_cpu_bound_macro( + "crypto_aead_xchacha20poly1305_decrypt", 4, + enif_crypto_aead_xchacha20poly1305_decrypt), + {"crypto_generichash_BYTES", 0, enif_crypto_generichash_BYTES}, {"crypto_generichash_BYTES_MIN", 0, enif_crypto_generichash_BYTES_MIN}, {"crypto_generichash_BYTES_MAX", 0, enif_crypto_generichash_BYTES_MAX}, diff --git a/src/enacl.erl b/src/enacl.erl index 883fad8..3bb51f5 100644 --- a/src/enacl.erl +++ b/src/enacl.erl @@ -66,6 +66,14 @@ aead_chacha20poly1305_ABYTES/0, aead_chacha20poly1305_MESSAGEBYTES_MAX/0, + %% No Tests! + aead_xchacha20poly1305_encrypt/4, + aead_xchacha20poly1305_decrypt/4, + aead_xchacha20poly1305_KEYBYTES/0, + aead_xchacha20poly1305_NONCEBYTES/0, + aead_xchacha20poly1305_ABYTES/0, + aead_xchacha20poly1305_MESSAGEBYTES_MAX/0, + %% EQC stream_key_size/0, stream_nonce_size/0, @@ -1140,6 +1148,61 @@ aead_chacha20poly1305_ABYTES() -> aead_chacha20poly1305_MESSAGEBYTES_MAX() -> enacl_nif:crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX(). +%% AEAD XChaCha20 Poly1305 +%% ---------------------- +%% @doc aead_xchacha20poly1305_encrypt/4 encrypts `Message' with additional data +%% `AD' using `Key' and `Nonce'. Returns the encrypted message followed by +%% `aead_xchacha20poly1305_ABYTES/0' bytes of MAC. +%% @end +-spec aead_xchacha20poly1305_encrypt(Key, Nonce, AD, Msg) -> binary() | {error, term()} + when Key :: binary(), + Nonce :: binary(), + AD :: binary(), + Msg :: binary(). +aead_xchacha20poly1305_encrypt(Key, Nonce, AD, Msg) -> + enacl_nif:crypto_aead_xchacha20poly1305_encrypt(Key, Nonce, AD, Msg). + +%% @doc aead_xchacha20poly1305_decrypt/4 decrypts ciphertext `CT' with additional +%% data `AD' using `Key' and `Nonce'. Note: `CipherText' should contain +%% `aead_xchacha20poly1305_ABYTES/0' bytes that is the MAC. Returns the decrypted +%% message. +%% @end +-spec aead_xchacha20poly1305_decrypt(Key, Nonce, AD, CT) -> binary() | {error, term()} + when Key :: binary(), + Nonce :: binary(), + AD :: binary(), + CT :: binary(). +aead_xchacha20poly1305_decrypt(Key, Nonce, AD, CT) -> + enacl_nif:crypto_aead_xchacha20poly1305_decrypt(Key, Nonce, AD, CT). + +%% @doc aead_xchacha20poly1305_KEYBYTES/0 returns the number of bytes +%% of the key used in AEAD XChaCha20 Poly1305 encryption/decryption. +%% @end +-spec aead_xchacha20poly1305_KEYBYTES() -> pos_integer(). +aead_xchacha20poly1305_KEYBYTES() -> + enacl_nif:crypto_aead_xchacha20poly1305_KEYBYTES(). + +%% @doc aead_xchacha20poly1305_NONCEBYTES/0 returns the number of bytes +%% of the Nonce in AEAD XChaCha20 Poly1305 encryption/decryption. +%% @end +-spec aead_xchacha20poly1305_NONCEBYTES() -> pos_integer(). +aead_xchacha20poly1305_NONCEBYTES() -> + enacl_nif:crypto_aead_xchacha20poly1305_NPUBBYTES(). + +%% @doc aead_xchacha20poly1305_ABYTES/0 returns the number of bytes +%% of the MAC in AEAD XChaCha20 Poly1305 encryption/decryption. +%% @end +-spec aead_xchacha20poly1305_ABYTES() -> pos_integer(). +aead_xchacha20poly1305_ABYTES() -> + enacl_nif:crypto_aead_xchacha20poly1305_ABYTES(). + +%% @doc aead_xchacha20poly1305_MESSAGEBYTES_MAX/0 returns the max number of bytes +%% allowed in a message in AEAD XChaCha20 Poly1305 encryption/decryption. +%% @end +-spec aead_xchacha20poly1305_MESSAGEBYTES_MAX() -> pos_integer(). +aead_xchacha20poly1305_MESSAGEBYTES_MAX() -> + enacl_nif:crypto_aead_xchacha20poly1305_MESSAGEBYTES_MAX(). + %% Obtaining random bytes %% @doc randombytes/1 produces a stream of random bytes of the given size diff --git a/src/enacl_nif.erl b/src/enacl_nif.erl index cd5116c..a57e562 100644 --- a/src/enacl_nif.erl +++ b/src/enacl_nif.erl @@ -74,6 +74,13 @@ crypto_aead_chacha20poly1305_ABYTES/0, crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX/0, + crypto_aead_xchacha20poly1305_encrypt/4, + crypto_aead_xchacha20poly1305_decrypt/4, + crypto_aead_xchacha20poly1305_KEYBYTES/0, + crypto_aead_xchacha20poly1305_NPUBBYTES/0, + crypto_aead_xchacha20poly1305_ABYTES/0, + crypto_aead_xchacha20poly1305_MESSAGEBYTES_MAX/0, + crypto_auth_BYTES/0, crypto_auth_KEYBYTES/0, @@ -257,6 +264,13 @@ crypto_aead_chacha20poly1305_NPUBBYTES() -> erlang:nif_ crypto_aead_chacha20poly1305_ABYTES() -> erlang:nif_error(nif_not_loaded). crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX() -> erlang:nif_error(nif_not_loaded). +crypto_aead_xchacha20poly1305_encrypt(_Key, _Nonce, _AD, _Message) -> erlang:nif_error(nif_not_loaded). +crypto_aead_xchacha20poly1305_decrypt(_Key, _Nonce, _AD, _Message) -> erlang:nif_error(nif_not_loaded). +crypto_aead_xchacha20poly1305_KEYBYTES() -> erlang:nif_error(nif_not_loaded). +crypto_aead_xchacha20poly1305_NPUBBYTES() -> erlang:nif_error(nif_not_loaded). +crypto_aead_xchacha20poly1305_ABYTES() -> erlang:nif_error(nif_not_loaded). +crypto_aead_xchacha20poly1305_MESSAGEBYTES_MAX() -> erlang:nif_error(nif_not_loaded). + crypto_auth_BYTES() -> erlang:nif_error(nif_not_loaded). crypto_auth_KEYBYTES() -> erlang:nif_error(nif_not_loaded). crypto_auth(_Msg, _Key) -> erlang:nif_error(nif_not_loaded).