From: Loup Vaillant Date: Sat, 10 Feb 2018 18:25:28 +0000 (+0100) Subject: Changed authenticated encryptio to match RFC 7539 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=09de649d537e963dbb6b7a6f1bc6885f16df5078;p=Monocypher.git Changed authenticated encryptio to match RFC 7539 Closes #87 This is a breaking change. For data in transit, update everyone at once. For data at rest, decrypt then re-encrypt everything. Sorry about that. I should have thought this through earlier. The main reason for this change is speed. While Monocypher doesn't aim to be as fast as possible itself, it *does* aim to allow upgrades. By ensuring that processing is aligned to block boundaries, RFC 7539 simplifies the implementation of fast algorithms. This change brings the following benefits: - Users who need the best speed possible ever can upgrade. - The length of the additional data is now authenticated, closing a potential minor vulnerability. - We can use Libsodium's crypto_aead_xchacha20poly1305_ietf_encrypt to generate test vectors. --- The monolithic interface stays the same. Function names, types, and buffer sizes, are identical. Just recompile your programs to upgrade. The incremental interface has been changed to be more orthogonal: `crypto_lock_encrypt()` and `crypto_lock_auth()` have been removed. There shall be one true AEAD construction, users don't need those building blocks. Users who *really* need another AEAD construction can write it themselves with the low-level primitives. `crypto_lock_aead_auth()` and `crypto_unlock_aead_auth()` have been renamed `crypto_lock_auth_ad()` and `crypto_unlock_auth_ad()` respectively. "aead" was a misnomer, those functions only authenticate additional data. `crypto_lock_auth_message()` and `crypto_unlock_auth_message()` have been added. They authenticate the cipher text. Their main use is performing a separate authentication pass (usefull when users expect a high corruption rate). --- diff --git a/doc/man/man3/crypto_lock.3monocypher b/doc/man/man3/crypto_lock.3monocypher index 77fd8ef..615e05f 100644 --- a/doc/man/man3/crypto_lock.3monocypher +++ b/doc/man/man3/crypto_lock.3monocypher @@ -255,23 +255,43 @@ crypto_wipe(key, 32); .Xr crypto_wipe 3monocypher , .Xr intro 3monocypher .Sh STANDARDS -These functions implement the XChacha20 (encryption) and Poly1305 -(MAC) primitives. -Chacha20 and Poly1305 are described in RFC 7539. +These functions implement RFC 7539, with XChacha20 instead of Chacha20. XChacha20 derives from Chacha20 the same way XSalsa20 derives from Salsa20, and benefits from the same security reduction (proven secure as long as Chacha20 itself is secure). -.Sh IMPLEMENTATION DETAILS +.Pp .Fn crypto_aead_lock -and -.Fn crypto_aead_unlock -do not authenticate the length themselves to make them compatible with -.Fn crypto_lock -and -.Fn crypto_unlock -when the size of the additional data is zero. -This also simplifies the implementation. +is equivalent to the following: +.Bd -literal -offset indent +void crypto_aead_lock(uint8_t mac[16], uint8_t *cipher_text, + const uint8_t key[32], + const uint8_t nonce[24], + const uint8_t *ad , size_t ad_size, + const uint8_t *plain_text, size_t text_size) +{ + u8 auth_key[64]; /* only the first 32 bytes are used */ + crypto_chacha_ctx ctx_e; + crypto_chacha20_x_init (&ctx_e, key, nonce); + crypto_chacha20_stream (&ctx_e, auth_key, 64); + crypto_chacha20_encrypt(&ctx_e, cipher_text, + plain_text, text_size); + + static const u8 zero [15] = {0}; + u8 sizes[16]; + size_t ad_zero = -ad_size & 15; + size_t text_zero = -text_size & 15; + store64_le(sizes , ad_size); + store64_le(sizes + 8, text_size); + + crypto_poly1305_ctx ctx; + crypto_poly1305_init (&ctx, auth_key); + crypto_poly1305_update(&ctx, ad , ad_size); + crypto_poly1305_update(&ctx, zero , ad_zero); + crypto_poly1305_update(&ctx, cipher_text, text_size); + crypto_poly1305_update(&ctx, zero , text_zero); + crypto_poly1305_update(&ctx, sizes , 16); + crypto_poly1305_final (&ctx, mac); +} +.Ed .Pp -This rarely causes problems in practice, because most of the time, the -length of the additional data is either fixed or self-contained, and -thus outside of attacker control. +(Real code would also wipe the relevant buffers.) diff --git a/doc/man/man3/crypto_lock_aead_auth.3monocypher b/doc/man/man3/crypto_lock_auth_ad.3monocypher similarity index 100% rename from doc/man/man3/crypto_lock_aead_auth.3monocypher rename to doc/man/man3/crypto_lock_auth_ad.3monocypher diff --git a/doc/man/man3/crypto_lock_auth.3monocypher b/doc/man/man3/crypto_lock_auth_message similarity index 100% rename from doc/man/man3/crypto_lock_auth.3monocypher rename to doc/man/man3/crypto_lock_auth_message diff --git a/doc/man/man3/crypto_lock_init.3monocypher b/doc/man/man3/crypto_lock_init.3monocypher index 98cdbf6..79247b1 100644 --- a/doc/man/man3/crypto_lock_init.3monocypher +++ b/doc/man/man3/crypto_lock_init.3monocypher @@ -3,15 +3,15 @@ .Os .Sh NAME .Nm crypto_lock_init , -.Nm crypto_lock_aead_auth , +.Nm crypto_lock_auth_ad , +.Nm crypto_lock_auth_message , .Nm crypto_lock_update , .Nm crypto_lock_final , .Nm crypto_unlock_init , -.Nm crypto_unlock_aead_auth , +.Nm crypto_unlock_auth_ad , +.Nm crypto_unlock_auth_message , .Nm crypto_unlock_update , -.Nm crypto_unlock_final , -.Nm crypto_lock_auth , -.Nm crypto_lock_encrypt +.Nm crypto_unlock_final .Nd incremental authenticated encryption with additional data .Sh SYNOPSIS .In monocypher.h @@ -22,12 +22,18 @@ .Fa "const uint8_t nonce[24]" .Fc .Ft void -.Fo crypto_lock_aead_auth +.Fo crypto_lock_auth_ad .Fa "crypto_lock_ctx *ctx" .Fa "const uint8_t *ad" .Fa "size_t ad_size" .Fc .Ft void +.Fo crypto_lock_auth_message +.Fa "crypto_lock_ctx *ctx" +.Fa "const uint8_t *plain_text" +.Fa "size_t text_size" +.Fc +.Ft void .Fo crypto_lock_update .Fa "crypto_lock_ctx *ctx" .Fa "uint8_t *cipher_text" @@ -46,12 +52,18 @@ .Fa "const uint8_t nonce[24]" .Fc .Ft void -.Fo crypto_unlock_aead_auth +.Fo crypto_unlock_auth_ad .Fa "crypto_unlock_ctx *ctx" .Fa "const uint8_t *ad" .Fa "size_t ad_size" .Fc .Ft void +.Fo crypto_unlock_auth_message +.Fa "crypto_unlock_ctx *ctx" +.Fa "const uint8_t *plain_text" +.Fa "size_t text_size" +.Fc +.Ft void .Fo crypto_unlock_update .Fa "crypto_unlock_ctx *ctx" .Fa "uint8_t *plain_text" @@ -63,19 +75,6 @@ .Fa "crypto_unlock_ctx *ctx" .Fa "const uint8_t mac[16]" .Fc -.Ft void -.Fo crypto_lock_auth -.Fa "crypto_lock_ctx *ctx" -.Fa "const uint8_t *ad" -.Fa "size_t ad_size" -.Fc -.Ft void -.Fo crypto_lock_encrypt -.Fa "crypto_lock_ctx *ctx" -.Fa "uint8_t *cipher_text" -.Fa "const uint8_t *plain_text" -.Fa "size_t text_size" -.Fc .Sh DESCRIPTION These functions are variants of .Xr crypto_lock 3monocypher , @@ -98,7 +97,7 @@ Initialise a context with .Fn crypto_lock_init . .It Authenticate additional data, if any, with -.Fn crypto_lock_aead_auth . +.Fn crypto_lock_auth_ad . .It Encrypt and authenticate some data with .Fn crypto_lock_update . @@ -114,7 +113,7 @@ Initialise a context with .Fn crypto_unlock_init . .It Verify additional data, if any, with -.Fn crypto_unlock_aead_auth . +.Fn crypto_unlock_auth_ad . .It Decrypt and verify some data with .Fn crypto_unlock_update . @@ -122,27 +121,13 @@ Decrypt and verify some data with Verify the MAC with .Fn crypto_unlock_final . .El -.Pp -.Fn crypto_lock_encrypt -encrypts or decrypts data -.Em without authenticating it . -It is meant as a building block. -Used with -.Fn crypto_lock_auth , -it enables various AEAD constructions. -Most users do not need either of them. -Prefer -.Fn crypto_lock_update -and -.Fn crypto_unlock_update -instead. .Sh RETURN VALUES .Fn crypto_lock_init , .Fn crypto_unlock_init , -.Fn crypto_lock_auth , -.Fn crypto_lock_encrypt , -.Fn crypto_lock_aead_auth , -.Fn crypto_unlock_aead_auth , +.Fn crypto_lock_auth_ad , +.Fn crypto_unlock_auth_ad , +.Fn crypto_lock_auth_message , +.Fn crypto_unlock_auth_message , .Fn crypto_lock_update , .Fn crypto_unlock_update , and @@ -173,7 +158,7 @@ crypto_wipe(key, 32); /* Authenticate additional data */ for (size_t i = 0; i < 500; i += 100) { - crypto_lock_aead_auth(&ctx, ad + i, 100); + crypto_lock_auth_ad(&ctx, ad + i, 100); } /* Encrypt message */ @@ -204,7 +189,7 @@ crypto_wipe(key, 32); /* Verify additional data */ for (size_t i = 0; i < 500; i += 100) { - crypto_unlock_aead_auth(&ctx, ad + i, 100); + crypto_unlock_auth_ad(&ctx, ad + i, 100); } /* Decrypt message */ @@ -223,6 +208,38 @@ if (crypto_unlock_final(&ctx, mac)) { crypto_wipe(plain_text, 500); .Ed .Pp +To authenticate the above without decrypting it: +.Bd -literal -offset indent +const uint8_t key [ 32]; /* Session key */ +const uint8_t nonce [ 32]; /* Unique per session key */ +const uint8_t mac [ 16]; /* Transmitted MAC */ +const uint8_t ad [500]; /* Optional additional data */ +const uint8_t cipher_text[500]; /* Encrypted message */ + +/* Set up initial context */ +crypto_unlock_ctx ctx; +crypto_unlock_init(&ctx, key, nonce); +/* Wipe the key if it is no longer needed */ +crypto_wipe(key, 32); + +/* Verify additional data */ +for (size_t i = 0; i < 500; i += 100) { + crypto_unlock_auth_ad(&ctx, ad + i, 100); +} + +/* Verify message */ +for (size_t i = 0; i < 500; i += 100) { + crypto_unlock_auth_message(&ctx, cipher_text + i, 100); +} + +/* Check the MAC */ +if (crypto_unlock_final(&ctx, mac)) { + /* Corrupted message */ +} else { + /* Genuine message */ +} +.Ed +.Pp In-place encryption without additional data: .Bd -literal -offset indent const uint8_t key [ 32]; /* Session key */ @@ -253,9 +270,7 @@ crypto_lock_final(&ctx, mac); .Xr crypto_wipe 3monocypher , .Xr intro 3monocypher .Sh STANDARDS -These functions implement the XChacha20 (encryption) and Poly1305 -(MAC) primitives. -Chacha20 and Poly1305 are described in RFC 7539. +These functions implement RFC 7539, with XChacha20 instead of Chacha20. XChacha20 derives from Chacha20 the same way XSalsa20 derives from Salsa20, and benefits from the same security reduction (proven secure as long as Chacha20 itself is secure). @@ -283,9 +298,9 @@ is an alias to is an alias to .Fn crypto_lock_init . .It -.Fn crypto_lock_aead_auth +.Fn crypto_lock_auth_ad and -.Fn crypto_unlock_aead_auth +.Fn crypto_unlock_auth_ad are aliases to .Fn crypto_lock_auth . .El @@ -294,4 +309,7 @@ The incremental interface is roughly three times slower than the direct interface at identifying corrupted messages. This is because the incremental interface works in a single pass and has to interleave decryption and verification. -Users who expect a high corruption rate may want to avoid it. +Users who expect a high corruption rate may want to perform a first +pass with +.Fn crypto_unlock_auth_message +before decrypting the message. diff --git a/doc/man/man3/crypto_lock_encrypt.3monocypher b/doc/man/man3/crypto_unlock_auth_ad.3monocypher similarity index 100% rename from doc/man/man3/crypto_lock_encrypt.3monocypher rename to doc/man/man3/crypto_unlock_auth_ad.3monocypher diff --git a/doc/man/man3/crypto_unlock_aead_auth.3monocypher b/doc/man/man3/crypto_unlock_auth_message.3monocypher similarity index 100% rename from doc/man/man3/crypto_unlock_aead_auth.3monocypher rename to doc/man/man3/crypto_unlock_auth_message.3monocypher diff --git a/doc/man/man3/intro.3monocypher b/doc/man/man3/intro.3monocypher index 846511f..04f0fd4 100644 --- a/doc/man/man3/intro.3monocypher +++ b/doc/man/man3/intro.3monocypher @@ -82,8 +82,8 @@ the chances of leaks. .Xr crypto_check_update 3monocypher , .Xr crypto_key_exchange 3monocypher , .Xr crypto_lock 3monocypher , -.Xr crypto_lock_auth 3monocypher , -.Xr crypto_lock_encrypt 3monocypher , +.Xr crypto_lock_auth_ad 3monocypher , +.Xr crypto_lock_auth_message 3monocypher , .Xr crypto_lock_final 3monocypher , .Xr crypto_lock_init 3monocypher , .Xr crypto_lock_update 3monocypher , @@ -98,8 +98,11 @@ the chances of leaks. .Xr crypto_sign_public_key 3monocypher , .Xr crypto_sign_update 3monocypher , .Xr crypto_unlock 3monocypher , -.Xr crypto_unlock_update 3monocypher , +.Xr crypto_unlock_auth_ad 3monocypher , +.Xr crypto_unlock_auth_message 3monocypher , .Xr crypto_unlock_final 3monocypher , +.Xr crypto_unlock_init 3monocypher , +.Xr crypto_unlock_update 3monocypher , .Xr crypto_verify16 3monocypher , .Xr crypto_verify32 3monocypher , .Xr crypto_verify64 3monocypher , diff --git a/src/monocypher.c b/src/monocypher.c index 45612b0..0d99c65 100644 --- a/src/monocypher.c +++ b/src/monocypher.c @@ -1706,44 +1706,66 @@ int crypto_key_exchange(u8 shared_key[32], //////////////////////////////// /// Authenticated encryption /// //////////////////////////////// +static void lock_ad_padding(crypto_lock_ctx *ctx) +{ + static const u8 zero[15] = {0}; + if (ctx->ad_phase) { + ctx->ad_phase = 0; + crypto_poly1305_update(&(ctx->poly), zero, -ctx->ad_size & 15); + } +} + void crypto_lock_init(crypto_lock_ctx *ctx, const u8 key[32], const u8 nonce[24]) { - u8 auth_key[32]; + u8 auth_key[64]; // "Wasting" the whole Chacha block is faster + ctx->ad_phase = 1; + ctx->ad_size = 0; + ctx->message_size = 0; crypto_chacha20_x_init(&(ctx->chacha), key, nonce); - crypto_chacha20_stream(&(ctx->chacha), auth_key, 32); + crypto_chacha20_stream(&(ctx->chacha), auth_key, 64); crypto_poly1305_init (&(ctx->poly ), auth_key); WIPE_BUFFER(auth_key); } -void crypto_lock_encrypt(crypto_lock_ctx *ctx, u8 *cipher_text, - const u8 *plain_text, size_t text_size) +void crypto_lock_auth_ad(crypto_lock_ctx *ctx, const u8 *msg, size_t msg_size) { - crypto_chacha20_encrypt(&(ctx->chacha), cipher_text, plain_text, text_size); + crypto_poly1305_update(&(ctx->poly), msg, msg_size); + ctx->ad_size += msg_size; } -void crypto_lock_auth(crypto_lock_ctx *ctx, const u8 *msg, size_t msg_size) +void crypto_lock_auth_message(crypto_lock_ctx *ctx, + const u8 *cipher_text, size_t text_size) { - crypto_poly1305_update(&(ctx->poly), msg, msg_size); + lock_ad_padding(ctx); + ctx->message_size += text_size; + crypto_poly1305_update(&(ctx->poly), cipher_text, text_size); } void crypto_lock_update(crypto_lock_ctx *ctx, u8 *cipher_text, const u8 *plain_text, size_t text_size) { - crypto_lock_encrypt(ctx, cipher_text, plain_text, text_size); - crypto_lock_auth (ctx, cipher_text, text_size); + crypto_chacha20_encrypt(&(ctx->chacha), cipher_text, plain_text, text_size); + crypto_lock_auth_message(ctx, cipher_text, text_size); } void crypto_lock_final(crypto_lock_ctx *ctx, u8 mac[16]) { - crypto_poly1305_final(&(ctx->poly), mac); + lock_ad_padding(ctx); + static const u8 zero[15] = {0}; + u8 sizes[16]; + store64_le(sizes + 0, ctx->ad_size); + store64_le(sizes + 8, ctx->message_size); + crypto_poly1305_update(&(ctx->poly), zero, -ctx->message_size & 15); + crypto_poly1305_update(&(ctx->poly), sizes, 16); + crypto_poly1305_final (&(ctx->poly), mac); WIPE_CTX(ctx); } void crypto_unlock_update(crypto_lock_ctx *ctx, u8 *plain_text, const u8 *cipher_text, size_t text_size) { - crypto_lock_auth (ctx, cipher_text, text_size); - crypto_lock_encrypt(ctx, plain_text, cipher_text, text_size); + crypto_unlock_auth_message(ctx, cipher_text, text_size); + crypto_chacha20_encrypt(&(ctx->chacha), plain_text, cipher_text, text_size); } int crypto_unlock_final(crypto_lock_ctx *ctx, const u8 mac[16]) @@ -1763,11 +1785,10 @@ void crypto_aead_lock(u8 mac[16], const u8 *plain_text, size_t text_size) { crypto_lock_ctx ctx; - crypto_lock_init (&ctx, key, nonce); - // authenticate additional data first, to allow overlapping buffers - crypto_lock_auth (&ctx, ad, ad_size); - crypto_lock_update(&ctx, cipher_text, plain_text, text_size); - crypto_lock_final (&ctx, mac); + crypto_lock_init (&ctx, key, nonce); + crypto_lock_auth_ad(&ctx, ad, ad_size); + crypto_lock_update (&ctx, cipher_text, plain_text, text_size); + crypto_lock_final (&ctx, mac); } int crypto_aead_unlock(u8 *plain_text, @@ -1777,10 +1798,10 @@ int crypto_aead_unlock(u8 *plain_text, const u8 *ad , size_t ad_size, const u8 *cipher_text, size_t text_size) { - crypto_lock_ctx ctx; - crypto_lock_init(&ctx, key, nonce); - crypto_lock_auth(&ctx, ad, ad_size); - crypto_lock_auth(&ctx, cipher_text, text_size); + crypto_unlock_ctx ctx; + crypto_unlock_init (&ctx, key, nonce); + crypto_unlock_auth_ad (&ctx, ad, ad_size); + crypto_unlock_auth_message(&ctx, cipher_text, text_size); crypto_chacha_ctx chacha_ctx = ctx.chacha; // avoid the wiping... if (crypto_unlock_final(&ctx, mac)) { // ...that occurs here WIPE_CTX(&chacha_ctx); diff --git a/src/monocypher.h b/src/monocypher.h index 41f15be..f099888 100644 --- a/src/monocypher.h +++ b/src/monocypher.h @@ -31,6 +31,9 @@ typedef struct { typedef struct { crypto_chacha_ctx chacha; crypto_poly1305_ctx poly; + uint64_t ad_size; + uint64_t message_size; + int ad_phase; } crypto_lock_ctx; #define crypto_unlock_ctx crypto_lock_ctx @@ -113,7 +116,11 @@ int crypto_aead_unlock(uint8_t *plain_text, void crypto_lock_init(crypto_lock_ctx *ctx, const uint8_t key[32], const uint8_t nonce[24]); -#define crypto_lock_aead_auth crypto_lock_auth +void crypto_lock_auth_ad(crypto_lock_ctx *ctx, + const uint8_t *message, + size_t message_size); +void crypto_lock_auth_message(crypto_lock_ctx *ctx, + const uint8_t *cipher_text, size_t text_size); void crypto_lock_update(crypto_lock_ctx *ctx, uint8_t *cipher_text, const uint8_t *plain_text, @@ -121,8 +128,9 @@ void crypto_lock_update(crypto_lock_ctx *ctx, void crypto_lock_final(crypto_lock_ctx *ctx, uint8_t mac[16]); // Incremental interface (decryption) -#define crypto_unlock_init crypto_lock_init -#define crypto_unlock_aead_auth crypto_lock_auth +#define crypto_unlock_init crypto_lock_init +#define crypto_unlock_auth_ad crypto_lock_auth_ad +#define crypto_unlock_auth_message crypto_lock_auth_message void crypto_unlock_update(crypto_lock_ctx *ctx, uint8_t *plain_text, const uint8_t *cipher_text, @@ -271,15 +279,4 @@ int crypto_x25519(uint8_t raw_shared_secret[32], const uint8_t your_secret_key [32], const uint8_t their_public_key [32]); - -// Building block for authenticated encryption -// ------------------------------------------- -void crypto_lock_encrypt(crypto_lock_ctx *ctx, - uint8_t *cipher_text, - const uint8_t *plain_text, - size_t text_size); -void crypto_lock_auth(crypto_lock_ctx *ctx, - const uint8_t *message, - size_t message_size); - #endif // MONOCYPHER_H diff --git a/tests/gen/aead_ietf.c b/tests/gen/aead_ietf.c new file mode 100644 index 0000000..83535a7 --- /dev/null +++ b/tests/gen/aead_ietf.c @@ -0,0 +1,32 @@ +#include +#include "utils.h" + +static void test(size_t text_size, size_t ad_size) +{ + RANDOM_INPUT(key , 32); + RANDOM_INPUT(nonce, 24); + RANDOM_INPUT(ad , 32); // ad size <= 32 + RANDOM_INPUT(text , 128); // text_size <= 128 + u8 out[16 + 128]; // text_size <= 128 + + crypto_aead_xchacha20poly1305_ietf_encrypt_detached( + out + 16, out, 0, text, text_size, ad, ad_size, 0, nonce, key); + + print_vector(key , 32); + print_vector(nonce , 24); + print_vector(ad , ad_size); + print_vector(text , text_size); + print_vector(out , text_size + 16); + printf("\n"); +} + +int main(void) +{ + SODIUM_INIT; + // regular tests + FOR (text_size, 0, 128) { test(text_size, 0); } + FOR (text_size, 0, 128) { test(text_size, 4); } + FOR ( ad_size, 0, 32) { test(0, ad_size); } + FOR ( ad_size, 0, 32) { test(16, ad_size); } + return 0; +} diff --git a/tests/gen/makefile b/tests/gen/makefile index 5ea6e48..b59a941 100644 --- a/tests/gen/makefile +++ b/tests/gen/makefile @@ -6,8 +6,8 @@ HASH = .PHONY: all clean -VEC = chacha20.vec xchacha20.vec poly1305.vec blake2b.vec \ - sha512.vec argon2i.vec edDSA.vec x25519.vec +VEC = chacha20.vec xchacha20.vec aead_ietf.vec poly1305.vec blake2b.vec \ + sha512.vec argon2i.vec edDSA.vec x25519.vec VEC2 = $(patsubst %.vec, %.all.vec, $(VEC)) key_exchange.all.vec HEADERS = $(patsubst %.all.vec, %.h.vec, $(VEC2)) VECTORS = ../vectors.h @@ -55,6 +55,7 @@ chacha20.all.vec : chacha20.vec ../vectors/chacha20 poly1305.all.vec : poly1305.vec ../vectors/poly1305 x25519.all.vec : x25519.vec ../vectors/x25519 xchacha20.all.vec : xchacha20.vec +aead_ietf.all.vec : aead_ietf.vec blake2b.all.vec : blake2b.vec sha512.all.vec : sha512.vec argon2i.all.vec : argon2i.vec diff --git a/tests/test.c b/tests/test.c index 9830591..8136406 100644 --- a/tests/test.c +++ b/tests/test.c @@ -116,6 +116,17 @@ static void poly1305(const vector in[], vector *out) crypto_poly1305(out->buf, msg->buf, msg->size, key->buf); } +static void aead_ietf(const vector in[], vector *out) +{ + const vector *key = in; + const vector *nonce = in + 1; + const vector *ad = in + 2; + const vector *text = in + 3; + crypto_aead_lock(out ->buf, out->buf + 16, key->buf, nonce->buf, + ad->buf, ad->size, text->buf, text->size); +} + + static void blake2b(const vector in[], vector *out) { const vector *msg = in; @@ -675,12 +686,12 @@ static int p_lock_incremental() crypto_aead_lock(mac1, cipher1, key, nonce, ad, ad_size, plain, text_size); crypto_lock_ctx ctx; - crypto_lock_init (&ctx, key, nonce); - crypto_lock_aead_auth(&ctx, ad1, ad_size1); // just to show ad also have - crypto_lock_aead_auth(&ctx, ad2, ad_size2); // an incremental interface - crypto_lock_update (&ctx, cipher2 , plain1, text_size1); - crypto_lock_update (&ctx, cipher2 + text_size1, plain2, text_size2); - crypto_lock_final (&ctx, mac2); + crypto_lock_init (&ctx, key, nonce); + crypto_lock_auth_ad(&ctx, ad1, ad_size1); // just to show ad also have + crypto_lock_auth_ad(&ctx, ad2, ad_size2); // an incremental interface + crypto_lock_update (&ctx, cipher2 , plain1, text_size1); + crypto_lock_update (&ctx, cipher2 + text_size1, plain2, text_size2); + crypto_lock_final (&ctx, mac2); status |= memcmp(mac1 , mac2 , 16 ); status |= memcmp(cipher1, cipher2, text_size); @@ -689,25 +700,25 @@ static int p_lock_incremental() u8 re_plain2[256]; status |= crypto_aead_unlock(re_plain1, key, nonce, mac1, ad, ad_size, cipher1, text_size); - crypto_unlock_init (&ctx, key, nonce); - crypto_unlock_aead_auth(&ctx, ad, ad_size); - crypto_unlock_update (&ctx, re_plain2, cipher2, text_size); + crypto_unlock_init (&ctx, key, nonce); + crypto_unlock_auth_ad(&ctx, ad, ad_size); + crypto_unlock_update (&ctx, re_plain2, cipher2, text_size); status |= crypto_unlock_final(&ctx, mac2); status |= memcmp(mac1 , mac2 , 16 ); status |= memcmp(plain, re_plain1, text_size); status |= memcmp(plain, re_plain2, text_size); // Test authentication without decryption - crypto_lock_init (&ctx, key, nonce); - crypto_lock_aead_auth(&ctx, ad , ad_size ); - crypto_lock_aead_auth(&ctx, cipher2, text_size); + crypto_unlock_init (&ctx, key, nonce); + crypto_unlock_auth_ad (&ctx, ad , ad_size ); + crypto_unlock_auth_message(&ctx, cipher2, text_size); status |= crypto_unlock_final(&ctx, mac2); // The same, except we're supposed to reject forgeries if (text_size > 0) { cipher2[0]++; // forgery attempt - crypto_lock_init (&ctx, key, nonce); - crypto_lock_aead_auth(&ctx, ad , ad_size ); - crypto_lock_aead_auth(&ctx, cipher2, text_size); + crypto_unlock_init (&ctx, key, nonce); + crypto_unlock_auth_ad (&ctx, ad , ad_size ); + crypto_unlock_auth_message(&ctx, cipher2, text_size); status |= !crypto_unlock_final(&ctx, mac2); } } @@ -715,6 +726,37 @@ static int p_lock_incremental() return status; } +// Only additionnal data +static int p_auth() +{ + int status = 0; + FOR (i, 0, 128) { + u8 key [ 32]; p_random(key , 32); + u8 nonce [ 24]; p_random(nonce , 24); + u8 ad [128]; p_random(ad , i); + u8 mac1[16]; + u8 mac2[16]; + // roundtrip + { + crypto_lock_ctx ctx; + crypto_lock_init (&ctx, key, nonce); + crypto_lock_auth_ad(&ctx, ad, i); + crypto_lock_final (&ctx, mac1); + crypto_aead_lock(mac2, 0, key, nonce, ad, i, 0, 0); + status |= memcmp(mac1, mac2, 16); + } + { + crypto_unlock_ctx ctx; + crypto_unlock_init (&ctx, key, nonce); + crypto_unlock_auth_ad(&ctx, ad, i); + status |= crypto_unlock_final(&ctx, mac1); + status |= crypto_aead_unlock(0, key, nonce, mac1, ad, i, 0, 0); + } + } + printf("%s: aead (authentication)\n", status != 0 ? "FAILED" : "OK"); + return status; +} + int main(void) { int status = 0; @@ -723,6 +765,7 @@ int main(void) status |= TEST(chacha20 , 4); status |= TEST(xchacha20 , 4); status |= TEST(poly1305 , 2); + status |= TEST(aead_ietf , 4); status |= TEST(blake2b , 2); status |= TEST(sha512 , 1); status |= TEST(argon2i , 4); @@ -752,6 +795,7 @@ int main(void) status |= p_eddsa_overlap(); status |= p_aead(); status |= p_lock_incremental(); + status |= p_auth(); printf("\n%s\n\n", status != 0 ? "SOME TESTS FAILED" : "All tests OK!"); return status;