Split off AEAD functions to a separate file

This commit is contained in:
Jesper Louis Andersen 2020-01-19 13:29:32 +01:00
parent 0047af286f
commit 3ee5a94caf
5 changed files with 248 additions and 191 deletions

View File

@ -30,10 +30,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
following the style of the Erlang/OTP `crypto` library. While here, make sure
we clean up correctly and that we don't accidentally mis-ref-count data. The
code is a bit more goto heavy, but this style is surprisingly common in C code.
- Use sodium's dynamic memory allocators. These guarantee 64bit alignment, and also
provide guard pages around the allocation, somewhat protecting it. It adds some
page table pressure compared to the current code, but is easier to maintain and
much cleaner code.
- The code now rejects updates to generichash states which were already finalized.
- We now track the desired outlen of a generichash operation in the opaque NIF
resource rather than on the Erlang side. This avoids some checks in the code,
and streamlines a good deal of the interface.
- Split AEAD routines off from the main enacl_nif.c file
### Fixes
- Fix a resource leak in generichash/sign init/update/final.

195
c_src/aead.c Normal file
View File

@ -0,0 +1,195 @@
#include "aead.h"
#include "enacl.h"
#include "erl_nif.h"
#include <sodium.h>
/*
* AEAD ChaCha20 Poly1305
*/
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_KEYBYTES);
}
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_NPUBBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_NPUBBYTES);
}
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_ABYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_ABYTES);
}
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env,
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX);
}
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_encrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM result;
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_chacha20poly1305_ietf_KEYBYTES) ||
(nonce.size != crypto_aead_chacha20poly1305_ietf_NPUBBYTES)) {
return enif_make_badarg(env);
}
do {
if (!enif_alloc_binary(message.size +
crypto_aead_chacha20poly1305_ietf_ABYTES,
&ciphertext)) {
result = nacl_error_tuple(env, "alloc_failed");
continue;
}
if (crypto_aead_chacha20poly1305_ietf_encrypt(
ciphertext.data, NULL, message.data, message.size, ad.data, ad.size,
NULL, nonce.data, key.data) < 0) {
result =
nacl_error_tuple(env, "aead_chacha20poly1305_ietf_encrypt_failed");
continue;
}
result = enif_make_binary(env, &ciphertext);
} while (0);
return result;
}
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_decrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM result;
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_chacha20poly1305_ietf_ABYTES) ||
(key.size != crypto_aead_chacha20poly1305_ietf_KEYBYTES) ||
(nonce.size != crypto_aead_chacha20poly1305_ietf_NPUBBYTES)) {
return enif_make_badarg(env);
}
do {
if (!enif_alloc_binary(ciphertext.size -
crypto_aead_chacha20poly1305_ietf_ABYTES,
&message)) {
result = nacl_error_tuple(env, "alloc_failed");
continue;
}
if (crypto_aead_chacha20poly1305_ietf_decrypt(
message.data, NULL, NULL, ciphertext.data, ciphertext.size, ad.data,
ad.size, nonce.data, key.data) < 0) {
result =
nacl_error_tuple(env, "aead_chacha20poly1305_ietf_decrypt_failed");
continue;
}
result = enif_make_binary(env, &message);
} while (0);
return result;
}
/*
* AEAD XChaCha20 Poly1305
*/
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}

46
c_src/aead.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef ENACL_AEAD_H
#define ENACL_AEAD_H
#include "erl_nif.h"
/* AEAD ChaCha20 Poly1305 */
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_NPUBBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_ABYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_encrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_decrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
/* AEAD XChaCha20 Poly1305 */
ERL_NIF_TERM
enif_crypto_aead_xchacha20poly1305_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_xchacha20poly1305_NPUBBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_xchacha20poly1305_ABYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_xchacha20poly1305_MESSAGEBYTES_MAX(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_xchacha20poly1305_encrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
ERL_NIF_TERM
enif_crypto_aead_xchacha20poly1305_decrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]);
#endif

View File

@ -3,6 +3,7 @@
#include <sodium.h>
#include <string.h>
#include "aead.h"
#include "enacl.h"
#include "generichash.h"
#include "hash.h"
@ -1544,196 +1545,6 @@ static ERL_NIF_TERM enif_crypto_pwhash_str_verify(ErlNifEnv *env, int argc,
return retVal;
}
/*
* AEAD ChaCha20 Poly1305
*/
static ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_KEYBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_KEYBYTES);
}
static ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_NPUBBYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_NPUBBYTES);
}
static ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_ABYTES(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env, crypto_aead_chacha20poly1305_ietf_ABYTES);
}
static ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
return enif_make_int64(env,
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX);
}
static ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_encrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM result;
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_chacha20poly1305_ietf_KEYBYTES) ||
(nonce.size != crypto_aead_chacha20poly1305_ietf_NPUBBYTES)) {
return enif_make_badarg(env);
}
do {
if (!enif_alloc_binary(message.size +
crypto_aead_chacha20poly1305_ietf_ABYTES,
&ciphertext)) {
result = nacl_error_tuple(env, "alloc_failed");
continue;
}
if (crypto_aead_chacha20poly1305_ietf_encrypt(
ciphertext.data, NULL, message.data, message.size, ad.data, ad.size,
NULL, nonce.data, key.data) < 0) {
result =
nacl_error_tuple(env, "aead_chacha20poly1305_ietf_encrypt_failed");
continue;
}
result = enif_make_binary(env, &ciphertext);
} while (0);
return result;
}
static ERL_NIF_TERM
enif_crypto_aead_chacha20poly1305_decrypt(ErlNifEnv *env, int argc,
ERL_NIF_TERM const argv[]) {
ERL_NIF_TERM result;
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_chacha20poly1305_ietf_ABYTES) ||
(key.size != crypto_aead_chacha20poly1305_ietf_KEYBYTES) ||
(nonce.size != crypto_aead_chacha20poly1305_ietf_NPUBBYTES)) {
return enif_make_badarg(env);
}
do {
if (!enif_alloc_binary(ciphertext.size -
crypto_aead_chacha20poly1305_ietf_ABYTES,
&message)) {
result = nacl_error_tuple(env, "alloc_failed");
continue;
}
if (crypto_aead_chacha20poly1305_ietf_decrypt(
message.data, NULL, NULL, ciphertext.data, ciphertext.size, ad.data,
ad.size, nonce.data, key.data) < 0) {
result =
nacl_error_tuple(env, "aead_chacha20poly1305_ietf_decrypt_failed");
continue;
}
result = enif_make_binary(env, &message);
} while (0);
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);
}
/* Tie the knot to the Erlang world */
static ErlNifFunc nif_funcs[] = {
{"crypto_box_NONCEBYTES", 0, enif_crypto_box_NONCEBYTES},

View File

@ -79,7 +79,7 @@ generichash_chunked(_Config) ->
{ok, Expected} = enacl:generichash_final(State),
ok.
generichash_chunked(State, Msg, 0) -> State;
generichash_chunked(State, _Msg, 0) -> State;
generichash_chunked(State, Msg, N) ->
State2 = enacl:generichash_update(State, Msg),
generichash_chunked(State2, Msg, N-1).