]> git.codecow.com Git - Monocypher.git/commitdiff
Changed authenticated encryptio to match RFC 7539
authorLoup Vaillant <loup@loup-vaillant.fr>
Sat, 10 Feb 2018 18:25:28 +0000 (19:25 +0100)
committerLoup Vaillant <loup@loup-vaillant.fr>
Sat, 10 Feb 2018 18:25:28 +0000 (19:25 +0100)
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).

12 files changed:
doc/man/man3/crypto_lock.3monocypher
doc/man/man3/crypto_lock_auth_ad.3monocypher [moved from doc/man/man3/crypto_lock_aead_auth.3monocypher with 100% similarity]
doc/man/man3/crypto_lock_auth_message [moved from doc/man/man3/crypto_lock_auth.3monocypher with 100% similarity]
doc/man/man3/crypto_lock_init.3monocypher
doc/man/man3/crypto_unlock_auth_ad.3monocypher [moved from doc/man/man3/crypto_lock_encrypt.3monocypher with 100% similarity]
doc/man/man3/crypto_unlock_auth_message.3monocypher [moved from doc/man/man3/crypto_unlock_aead_auth.3monocypher with 100% similarity]
doc/man/man3/intro.3monocypher
src/monocypher.c
src/monocypher.h
tests/gen/aead_ietf.c [new file with mode: 0644]
tests/gen/makefile
tests/test.c

index 77fd8efff780374391d0859b8864107466708e07..615e05f912ea7d5854d441b1d21b98f409d1dc62 100644 (file)
@@ -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.)
index 98cdbf695638cb1616b2e1ee246626180b4c8f31..79247b1aeeb621ac6f8afbe45df33f25b36c343b 100644 (file)
@@ -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
 .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"
 .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"
 .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.
index 846511fd71c067d0470b973dd5f842cb1d1f2f3e..04f0fd407e0c767e4f60940fbeb49274364a968f 100644 (file)
@@ -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 ,
index 45612b036b3cf8ca7bc8fb7ec9ef27f03fd3dcf0..0d99c652c22469c964e7531988c487e142ebd12c 100644 (file)
@@ -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);
index 41f15be1f76e8fce8b873bb3a761a4dbbf5dd4c7..f0998887216c194e3503eca71e63563453393189 100644 (file)
@@ -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 (file)
index 0000000..83535a7
--- /dev/null
@@ -0,0 +1,32 @@
+#include <sodium.h>
+#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;
+}
index 5ea6e4800eb092bb4f4e424ced9348d07680f01d..b59a94132b1bb22aadaed8b9adeb609816d5dadd 100644 (file)
@@ -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
index 9830591f7a38d4ec7af045784c1e8918ffb8b4b2..813640646ab0ec32d3e6acdbe3cd6fd4da83b397 100644 (file)
@@ -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;