]> git.codecow.com Git - Monocypher.git/commitdiff
Removed AEAD streaming interface. BREAKS COMPATIBILITY
authorLoup Vaillant <loup@loup-vaillant.fr>
Sun, 24 Nov 2019 20:35:33 +0000 (21:35 +0100)
committerLoup Vaillant <loup@loup-vaillant.fr>
Sun, 24 Nov 2019 20:35:33 +0000 (21:35 +0100)
The streaming interface for AEAD was a bad idea: it's harder to test and
encourages unsafe protocol design (unsafe handling of unauthenticated
data, denial of service amplification...).

Its rightful place is the trash bin.

makefile
src/deprecated/aead-incr.c [new file with mode: 0644]
src/deprecated/aead-incr.h [new file with mode: 0644]
src/deprecated/chacha20.c [new file with mode: 0644]
src/deprecated/chacha20.h [new file with mode: 0644]
src/monocypher.c
src/monocypher.h
tests/speed/speed.c
tests/test.c

index a15842a2c4e13109657fee0732b1831c56bb3a4a..531dea0542691c50d5cd1b19d32db22d05261fcc 100644 (file)
--- a/makefile
+++ b/makefile
@@ -97,9 +97,11 @@ lib/libmonocypher.so: lib/$(SONAME)
 lib/$(SONAME): lib/monocypher.o $(LINK_SHA512)
        @mkdir -p $(@D)
        $(CC) $(CFLAGS) -shared -Wl,-soname,$(SONAME) -o $@ $^
-lib/sha512.o    : src/optional/sha512.c src/optional/sha512.h
+lib/sha512.o    : src/optional/sha512.c      src/optional/sha512.h
+lib/chacha20.o  : src/deprecated/chacha20.c  src/deprecated/chacha20.h
+lib/aead-incr.o : src/deprecated/aead-incr.c src/deprecated/aead-incr.h
 lib/monocypher.o: src/monocypher.c src/monocypher.h
-lib/monocypher.o lib/sha512.o:
+lib/monocypher.o lib/sha512.o lib/chacha20.o lib/aead-incr.o:
        @mkdir -p $(@D)
        $(CC) $(CFLAGS) -I src -I src/optional -fPIC -c -o $@ $<
 
@@ -107,7 +109,7 @@ lib/monocypher.o lib/sha512.o:
 TEST_COMMON = tests/utils.h src/monocypher.h src/optional/sha512.h
 SPEED       = tests/speed
 lib/utils.o          :tests/utils.c
-lib/test.o           :tests/test.c               $(TEST_COMMON) tests/vectors.h
+lib/test.o           :tests/test.c               $(TEST_COMMON) tests/vectors.h  src/deprecated/chacha20.h
 lib/speed.o          :$(SPEED)/speed.c           $(TEST_COMMON) $(SPEED)/speed.h
 lib/speed-tweetnacl.o:$(SPEED)/speed-tweetnacl.c $(TEST_COMMON) $(SPEED)/speed.h
 lib/utils.o lib/test.o lib/speed.o lib/speed-tweetnacl.o:
@@ -154,7 +156,7 @@ lib/speed-c25519.o:$(SPEED)/speed-c25519.c \
 
 
 # test & speed executables
-test.out : lib/test.o  lib/utils.o lib/monocypher.o lib/sha512.o
+test.out : lib/test.o  lib/utils.o lib/monocypher.o lib/sha512.o lib/chacha20.o lib/aead-incr.o
 speed.out: lib/speed.o lib/utils.o lib/monocypher.o lib/sha512.o
 test.out speed.out:
        $(CC) $(CFLAGS) -I src -I src/optional -o $@ $^
diff --git a/src/deprecated/aead-incr.c b/src/deprecated/aead-incr.c
new file mode 100644 (file)
index 0000000..7efcf46
--- /dev/null
@@ -0,0 +1,134 @@
+// Deprecated incremental API for authenticated encryption
+//
+// This file *temporarily* provides compatibility with Monocypher 2.x.
+// Do not rely on its continued existence.
+//
+// Deprecated in     : 3.0.0
+// Will be removed in: 4.0.0
+//
+// Deprecated functions & types:
+//     crypto_unlock_ctx
+//     crypto_lock_ctx
+//     crypto_lock_init
+//     crypto_lock_auth_ad
+//     crypto_lock_auth_message
+//     crypto_lock_update
+//     crypto_lock_final
+//     crypto_unlock_init
+//     crypto_unlock_auth_ad
+//     crypto_unlock_auth_message
+//     crypto_unlock_update
+//     crypto_unlock_final
+//
+// For existing deployments that can no longer be updated or modified,
+// use the 2.x family, which will receive security updates until 2024.
+//
+// upgrade strategy:
+// Change your protocol in a way that it does not rely on the removed
+// functions, namely by splitting the file into chunks you each use the
+// crypto_lock() and crypto_unlock() functions on.
+//
+// For files, you may alternatively (and suboptimally) attempt to
+// mmap()/MapViewOfFile() and pass the files as mapped memory into
+// crypto_lock() and crypto_unlock() this way instead.
+
+#include "aead-incr.h"
+
+#define FOR_T(type, i, start, end) for (type i = (start); i < (end); i++)
+#define FOR(i, start, end)         FOR_T(size_t, i, start, end)
+#define WIPE_CTX(ctx)              crypto_wipe(ctx   , sizeof(*(ctx)))
+#define WIPE_BUFFER(buffer)        crypto_wipe(buffer, sizeof(buffer))
+#define MIN(a, b)                  ((a) <= (b) ? (a) : (b))
+#define MAX(a, b)                  ((a) >= (b) ? (a) : (b))
+#define ALIGN(x, block_size)       ((~(x) + 1) & ((block_size) - 1))
+typedef int8_t   i8;
+typedef uint8_t  u8;
+typedef int16_t  i16;
+typedef uint32_t u32;
+typedef int32_t  i32;
+typedef int64_t  i64;
+typedef uint64_t u64;
+
+static const u8 zero[16] = {0};
+
+static void store64_le(u8 out[8], u64 in)
+{
+    out[0] =  in        & 0xff;
+    out[1] = (in >>  8) & 0xff;
+    out[2] = (in >> 16) & 0xff;
+    out[3] = (in >> 24) & 0xff;
+    out[4] = (in >> 32) & 0xff;
+    out[5] = (in >> 40) & 0xff;
+    out[6] = (in >> 48) & 0xff;
+    out[7] = (in >> 56) & 0xff;
+}
+
+static void lock_ad_padding(crypto_lock_ctx *ctx)
+{
+    if (ctx->ad_phase) {
+        ctx->ad_phase = 0;
+        crypto_poly1305_update(&ctx->poly, zero, ALIGN(ctx->ad_size, 16));
+    }
+}
+
+void crypto_lock_init(crypto_lock_ctx *ctx,
+                      const u8 key[32], const u8 nonce[24])
+{
+    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, 64);
+    crypto_poly1305_init  (&ctx->poly  , auth_key);
+    WIPE_BUFFER(auth_key);
+}
+
+void crypto_lock_auth_ad(crypto_lock_ctx *ctx, const u8 *msg, size_t msg_size)
+{
+    crypto_poly1305_update(&ctx->poly, msg, msg_size);
+    ctx->ad_size += msg_size;
+}
+
+void crypto_lock_auth_message(crypto_lock_ctx *ctx,
+                              const u8 *cipher_text, size_t text_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_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])
+{
+    lock_ad_padding(ctx);
+    u8 sizes[16]; // Not secret, not wiped
+    store64_le(sizes + 0, ctx->ad_size);
+    store64_le(sizes + 8, ctx->message_size);
+    crypto_poly1305_update(&ctx->poly, zero, ALIGN(ctx->message_size, 16));
+    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_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])
+{
+    u8 real_mac[16];
+    crypto_lock_final(ctx, real_mac);
+    int mismatch = crypto_verify16(real_mac, mac);
+    WIPE_BUFFER(real_mac);
+    return mismatch;
+}
diff --git a/src/deprecated/aead-incr.h b/src/deprecated/aead-incr.h
new file mode 100644 (file)
index 0000000..3ace56c
--- /dev/null
@@ -0,0 +1,77 @@
+// Deprecated incremental API for authenticated encryption
+//
+// This file *temporarily* provides compatibility with Monocypher 2.x.
+// Do not rely on its continued existence.
+//
+// Deprecated in     : 3.0.0
+// Will be removed in: 4.0.0
+//
+// Deprecated functions & types:
+//     crypto_unlock_ctx
+//     crypto_lock_ctx
+//     crypto_lock_init
+//     crypto_lock_auth_ad
+//     crypto_lock_auth_message
+//     crypto_lock_update
+//     crypto_lock_final
+//     crypto_unlock_init
+//     crypto_unlock_auth_ad
+//     crypto_unlock_auth_message
+//     crypto_unlock_update
+//     crypto_unlock_final
+//
+// For existing deployments that can no longer be updated or modified,
+// use the 2.x family, which will receive security updates until 2024.
+//
+// upgrade strategy:
+// Change your protocol in a way that it does not rely on the removed
+// functions, namely by splitting the file into chunks you each use the
+// crypto_lock() and crypto_unlock() functions on.
+//
+// For files, you may alternatively (and suboptimally) attempt to
+// mmap()/MapViewOfFile() and pass the files as mapped memory into
+// crypto_lock() and crypto_unlock() this way instead.
+
+#ifndef AEAD_INCR_H
+#define AEAD_INCR_H
+
+#include <stddef.h>
+#include <inttypes.h>
+#include "monocypher.h"
+#include "deprecated/chacha20.h"
+
+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
+
+// Encryption
+void crypto_lock_init(crypto_lock_ctx *ctx,
+                      const uint8_t    key[32],
+                      const uint8_t    nonce[24]);
+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,
+                        size_t           text_size);
+void crypto_lock_final(crypto_lock_ctx *ctx, uint8_t mac[16]);
+
+// Decryption
+#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_unlock_ctx *ctx,
+                          uint8_t           *plain_text,
+                          const uint8_t     *cipher_text,
+                          size_t             text_size);
+int crypto_unlock_final(crypto_unlock_ctx *ctx, const uint8_t mac[16]);
+
+#endif // AEAD_INCR_H
diff --git a/src/deprecated/chacha20.c b/src/deprecated/chacha20.c
new file mode 100644 (file)
index 0000000..72416cc
--- /dev/null
@@ -0,0 +1,95 @@
+// Deprecated incremental API for Chacha20
+//
+// This file *temporarily* provides compatibility with Monocypher 2.x.
+// Do not rely on its continued existence.
+//
+// Deprecated in     : 3.0.0
+// Will be removed in: 4.0.0
+//
+// Deprecated functions & types:
+//     crypto_chacha_ctx
+//     crypto_chacha20_H
+//     crypto_chacha20_init
+//     crypto_chacha20_x_init
+//     crypto_chacha20_set_ctr
+//     crypto_chacha20_encrypt
+//     crypto_chacha20_stream
+//
+// For existing deployments that can no longer be updated or modified,
+// use the 2.x family, which will receive security updates until 2024.
+//
+// Upgrade strategy:
+// The new 3.x API can emulate incremental capabilities by setting a
+// custom counter.  Make sure you authenticate each chunk before you
+// decrypt them, though.
+
+#include "chacha20.h"
+#include "monocypher.h"
+
+#define FOR_T(type, i, start, end) for (type i = (start); i < (end); i++)
+#define FOR(i, start, end)         FOR_T(size_t, i, start, end)
+#define WIPE_CTX(ctx)              crypto_wipe(ctx   , sizeof(*(ctx)))
+#define WIPE_BUFFER(buffer)        crypto_wipe(buffer, sizeof(buffer))
+#define MIN(a, b)                  ((a) <= (b) ? (a) : (b))
+#define MAX(a, b)                  ((a) >= (b) ? (a) : (b))
+#define ALIGN(x, block_size)       ((~(x) + 1) & ((block_size) - 1))
+typedef int8_t   i8;
+typedef uint8_t  u8;
+typedef int16_t  i16;
+typedef uint32_t u32;
+typedef int32_t  i32;
+typedef int64_t  i64;
+typedef uint64_t u64;
+
+void crypto_chacha20_H(u8 out[32], const u8 key[32], const u8 in[16])
+{
+    crypto_hchacha20(out, key, in);
+}
+
+void crypto_chacha20_init(crypto_chacha_ctx *ctx,
+                          const u8 key[32], const u8 nonce[8])
+{
+    FOR (i, 0, 32) { ctx->key  [i] = key  [i]; }
+    FOR (i, 0,  8) { ctx->nonce[i] = nonce[i]; }
+    crypto_chacha20_set_ctr(ctx, 0);
+}
+
+void crypto_chacha20_x_init(crypto_chacha_ctx *ctx,
+                            const u8 key[32], const u8 nonce[24])
+{
+    crypto_hchacha20(ctx->key, key, nonce);
+    FOR (i, 0,  8) { ctx->nonce[i] = nonce[i + 16]; }
+    crypto_chacha20_set_ctr(ctx, 0);
+}
+
+void crypto_chacha20_set_ctr(crypto_chacha_ctx *ctx, u64 ctr)
+{
+    ctx->ctr = ctr;
+    ctx->pool_idx = 64; // The random pool (re)starts empty
+}
+
+void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx, u8 *cipher_text,
+                             const u8 *plain_text, size_t text_size)
+{
+    FOR (i, 0, text_size) {
+        if (ctx->pool_idx == 64) {
+            crypto_chacha20_ctr(ctx->pool, 0, 64,
+                                ctx->key, ctx-> nonce, ctx->ctr);
+            ctx->pool_idx = 0;
+            ctx->ctr++;
+        }
+        u8 plain = 0;
+        if (plain_text != 0) {
+            plain = *plain_text;
+            plain_text++;
+        }
+        *cipher_text = ctx->pool[ctx->pool_idx] ^ plain;
+        ctx->pool_idx++;
+        cipher_text++;
+    }
+}
+
+void crypto_chacha20_stream(crypto_chacha_ctx *ctx, u8 *stream, size_t size)
+{
+    crypto_chacha20_encrypt(ctx, stream, 0, size);
+}
diff --git a/src/deprecated/chacha20.h b/src/deprecated/chacha20.h
new file mode 100644 (file)
index 0000000..fc7c539
--- /dev/null
@@ -0,0 +1,68 @@
+// Deprecated incremental API for Chacha20
+//
+// This file *temporarily* provides compatibility with Monocypher 2.x.
+// Do not rely on its continued existence.
+//
+// Deprecated in     : 3.0.0
+// Will be removed in: 4.0.0
+//
+// Deprecated functions & types:
+//     crypto_chacha_ctx
+//     crypto_chacha20_H
+//     crypto_chacha20_init
+//     crypto_chacha20_x_init
+//     crypto_chacha20_set_ctr
+//     crypto_chacha20_encrypt
+//     crypto_chacha20_stream
+//
+// For existing deployments that can no longer be updated or modified,
+// use the 2.x family, which will receive security updates until 2024.
+//
+// Upgrade strategy:
+// The new 3.x API can emulate incremental capabilities by setting a
+// custom counter.  Make sure you authenticate each chunk before you
+// decrypt them, though.
+
+#ifndef CHACHA20_H
+#define CHACHA20_H
+
+#include <stddef.h>
+#include <inttypes.h>
+
+// Chacha20
+typedef struct {
+    uint8_t  key[32];
+    uint8_t  nonce[8];
+    uint64_t ctr;
+    uint8_t  pool[64];
+    size_t   pool_idx;
+} crypto_chacha_ctx;
+
+// Chacha20 (old API)
+// ------------------
+
+// Specialised hash.
+void crypto_chacha20_H(uint8_t       out[32],
+                       const uint8_t key[32],
+                       const uint8_t in [16]);
+
+void crypto_chacha20_init(crypto_chacha_ctx *ctx,
+                          const uint8_t      key[32],
+                          const uint8_t      nonce[8]);
+
+void crypto_chacha20_x_init(crypto_chacha_ctx *ctx,
+                            const uint8_t      key[32],
+                            const uint8_t      nonce[24]);
+
+void crypto_chacha20_set_ctr(crypto_chacha_ctx *ctx, uint64_t ctr);
+
+void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx,
+                             uint8_t           *cipher_text,
+                             const uint8_t     *plain_text,
+                             size_t             text_size);
+
+void crypto_chacha20_stream(crypto_chacha_ctx *ctx,
+                            uint8_t *stream, size_t size);
+
+
+#endif // CHACHA20_H
index a3c7656ad674b8fbbeeeba37237d71f33ccb5fa3..6b2f50a73a0517e1315dcbceb62eeee240d5f2b7 100644 (file)
@@ -139,148 +139,143 @@ static void chacha20_rounds(u32 out[16], const u32 in[16])
     out[12] = t12;  out[13] = t13;  out[14] = t14;  out[15] = t15;
 }
 
-static void chacha20_init_key(crypto_chacha_ctx *ctx, const u8 key[32])
+void chacha20_init_key(u32 block[16], const u8 key[32])
 {
     // constant
-    ctx->input[0] = load32_le((const u8*)"expa");
-    ctx->input[1] = load32_le((const u8*)"nd 3");
-    ctx->input[2] = load32_le((const u8*)"2-by");
-    ctx->input[3] = load32_le((const u8*)"te k");
+    block[0] = load32_le((const u8*)"expa");
+    block[1] = load32_le((const u8*)"nd 3");
+    block[2] = load32_le((const u8*)"2-by");
+    block[3] = load32_le((const u8*)"te k");
     // key
     FOR (i, 0, 8) {
-        ctx->input[i+4] = load32_le(key + i*4);
+        block[i+4] = load32_le(key + i*4);
     }
 }
 
-static u8 chacha20_pool_byte(crypto_chacha_ctx *ctx)
+void chacha20_fill_pool(u8 pool[64], u32 input[16])
 {
-    u32 pool_word = ctx->pool[ctx->pool_idx >> 2];
-    u8  pool_byte = (u8)(pool_word >> (8*(ctx->pool_idx & 3)));
-    ctx->pool_idx++;
-    return pool_byte;
-}
-
-// Fill the pool if needed, update the counters
-static void chacha20_refill_pool(crypto_chacha_ctx *ctx)
-{
-    chacha20_rounds(ctx->pool, ctx->input);
+    u32 tmp[16];
+    chacha20_rounds(tmp, input);
     FOR (j, 0, 16) {
-        ctx->pool[j] += ctx->input[j];
+        tmp[j] += input[j];
+    }
+    input[12]++;
+    if (input[12] == 0) {
+        input[13]++;
     }
-    ctx->pool_idx = 0;
-    ctx->input[12]++;
-    if (ctx->input[12] == 0) {
-        ctx->input[13]++;
+    FOR (i, 0, 16) {
+        store32_le(pool + i*4, tmp[i]);
     }
 }
 
-void crypto_chacha20_H(u8 out[32], const u8 key[32], const u8 in[16])
+void crypto_hchacha20(u8 out[32], const u8 key[32], const u8 in [16])
 {
-    crypto_chacha_ctx ctx;
-    chacha20_init_key(&ctx, key);
+    u32 block[16];
+    chacha20_init_key(block, key);
+    // input
     FOR (i, 0, 4) {
-        ctx.input[i+12] = load32_le(in + i*4);
+        block[i+12] = load32_le(in + i*4);
     }
-    u32 buffer[16];
-    chacha20_rounds(buffer, ctx.input);
+    chacha20_rounds(block, block);
     // prevents reversal of the rounds by revealing only half of the buffer.
     FOR (i, 0, 4) {
-        store32_le(out      + i*4, buffer[i     ]); // constant
-        store32_le(out + 16 + i*4, buffer[i + 12]); // counter and nonce
+        store32_le(out      + i*4, block[i     ]); // constant
+        store32_le(out + 16 + i*4, block[i + 12]); // counter and nonce
     }
-    WIPE_CTX(&ctx);
-    WIPE_BUFFER(buffer);
+    WIPE_BUFFER(block);
 }
 
-static void chacha20_encrypt(crypto_chacha_ctx *ctx,
-                             u8                *cipher_text,
-                             const u8          *plain_text,
-                             size_t             text_size)
+void chacha20_core(u32 input[16], u8 *cipher_text, const u8 *plain_text,
+                   size_t text_size)
 {
-    FOR (i, 0, text_size) {
-        if (ctx->pool_idx == 64) {
-            chacha20_refill_pool(ctx);
+    u8 pool[64];
+    while (text_size >= 64) {
+        chacha20_fill_pool(pool, input);
+        // TODO: there must be cleaner, faster ways to do this.
+        if (plain_text != 0) {
+            FOR (i, 0, 64) {
+                cipher_text[i] = pool[i] ^ plain_text[i];
+            }
+            plain_text  += 64;
+        } else {
+            FOR (i, 0, 64) {
+                cipher_text[i] = pool[i];
+            }
         }
-        u8 plain = 0;
+        cipher_text += 64;
+        text_size   -= 64;
+    }
+    if (text_size > 0) {
+        chacha20_fill_pool(pool, input);
+        // TODO: there must be cleaner, faster ways to do this.
         if (plain_text != 0) {
-            plain = *plain_text;
-            plain_text++;
+            FOR (i, 0, text_size) {
+                cipher_text[i] = pool[i] ^ plain_text[i];
+            }
+        } else {
+            FOR (i, 0, text_size) {
+                cipher_text[i] = pool[i];
+            }
         }
-        *cipher_text = chacha20_pool_byte(ctx) ^ plain;
-        cipher_text++;
     }
+    WIPE_BUFFER(pool);
 }
 
-void crypto_chacha20_init(crypto_chacha_ctx *ctx,
-                          const u8           key[32],
-                          const u8           nonce[8])
+void crypto_chacha20_ctr(u8 *cipher_text, const u8 *plain_text,
+                         size_t text_size, const u8 key[32], const u8 nonce[8],
+                         u64 ctr)
 {
-    chacha20_init_key      (ctx, key);     // key
-    crypto_chacha20_set_ctr(ctx, 0  );     // counter
-    ctx->input[14] = load32_le(nonce + 0); // nonce
-    ctx->input[15] = load32_le(nonce + 4); // nonce
+    u32 input[16];
+    chacha20_init_key(input, key);
+    input[12] = (u32) ctr;
+    input[13] = (u32)(ctr >> 32);
+    input[14] = load32_le(nonce);
+    input[15] = load32_le(nonce + 4);
+    chacha20_core(input, cipher_text, plain_text, text_size);
+    WIPE_BUFFER(input);
 }
 
-void crypto_chacha20_x_init(crypto_chacha_ctx *ctx,
-                            const u8           key[32],
-                            const u8           nonce[24])
+void crypto_ietf_chacha20_ctr(u8 *cipher_text, const u8 *plain_text,
+                              size_t text_size,
+                              const u8 key[32], const u8 nonce[12], u32 ctr)
 {
-    u8 derived_key[32];
-    crypto_chacha20_H(derived_key, key, nonce);
-    crypto_chacha20_init(ctx, derived_key, nonce + 16);
-    WIPE_BUFFER(derived_key);
+    u32 input[16];
+    chacha20_init_key(input, key);
+    input[12] = (u32) ctr;
+    input[13] = load32_le(nonce);
+    input[14] = load32_le(nonce + 4);
+    input[15] = load32_le(nonce + 8);
+    chacha20_core(input, cipher_text, plain_text, text_size);
+    WIPE_BUFFER(input);
 }
 
-void crypto_chacha20_set_ctr(crypto_chacha_ctx *ctx, u64 ctr)
+void crypto_xchacha20_ctr(u8 *cipher_text, const u8 *plain_text,
+                          size_t text_size,
+                          const u8 key[32], const u8 nonce[24], u64 ctr)
 {
-    ctx->input[12] = ctr & 0xffffffff;
-    ctx->input[13] = ctr >> 32;
-    ctx->pool_idx  = 64;  // The random pool (re)starts empty
+    u8 sub_key[32];
+    crypto_hchacha20(sub_key, key, nonce);
+    crypto_chacha20_ctr(cipher_text, plain_text, text_size, key, nonce+16, ctr);
 }
 
-void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx,
-                             u8                *cipher_text,
-                             const u8          *plain_text,
-                             size_t             text_size)
+void crypto_chacha20(u8 *cipher_text, const u8 *plain_text, size_t text_size,
+                     const u8 key[32], const u8 nonce[8])
 {
-    // Align ourselves with block boundaries
-    size_t align = MIN(ALIGN(ctx->pool_idx, 64), text_size);
-    chacha20_encrypt(ctx, cipher_text, plain_text, align);
-    if (plain_text != 0) {
-        plain_text += align;
-    }
-    cipher_text += align;
-    text_size   -= align;
-
-    // Process the message block by block
-    FOR (i, 0, text_size >> 6) {  // number of blocks
-        chacha20_refill_pool(ctx);
-        if (plain_text != 0) {
-            FOR (j, 0, 16) {
-                u32 plain = load32_le(plain_text);
-                store32_le(cipher_text, ctx->pool[j] ^ plain);
-                plain_text  += 4;
-                cipher_text += 4;
-            }
-        } else {
-            FOR (j, 0, 16) {
-                store32_le(cipher_text, ctx->pool[j]);
-                cipher_text += 4;
-            }
-        }
-        ctx->pool_idx = 64;
-    }
-    text_size &= 63;
+    crypto_chacha20_ctr(cipher_text, plain_text, text_size, key, nonce, 0);
 
-    // remaining bytes
-    chacha20_encrypt(ctx, cipher_text, plain_text, text_size);
 }
-
-void crypto_chacha20_stream(crypto_chacha_ctx *ctx, u8 *stream, size_t size)
+void crypto_ietf_chacha20(u8 *cipher_text, const u8 *plain_text,
+                          size_t text_size,
+                          const u8 key[32], const u8 nonce[12])
 {
-    crypto_chacha20_encrypt(ctx, stream, 0, size);
+    crypto_ietf_chacha20_ctr(cipher_text, plain_text, text_size, key, nonce, 0);
 }
 
+void crypto_xchacha20(u8 *cipher_text, const u8 *plain_text, size_t text_size,
+                      const u8 key[32], const u8 nonce[24])
+{
+    crypto_xchacha20_ctr(cipher_text, plain_text, text_size, key, nonce, 0);
+}
 
 /////////////////
 /// Poly 1305 ///
@@ -2061,81 +2056,28 @@ int crypto_key_exchange(u8       shared_key[32],
                         const u8 their_public_key[32])
 {
     int status = crypto_x25519(shared_key, your_secret_key, their_public_key);
-    crypto_chacha20_H(shared_key, shared_key, zero);
+    crypto_hchacha20(shared_key, shared_key, zero);
     return status;
 }
 
 ////////////////////////////////
 /// Authenticated encryption ///
 ////////////////////////////////
-static void lock_ad_padding(crypto_lock_ctx *ctx)
-{
-    if (ctx->ad_phase) {
-        ctx->ad_phase = 0;
-        crypto_poly1305_update(&ctx->poly, zero, ALIGN(ctx->ad_size, 16));
-    }
-}
-
-void crypto_lock_init(crypto_lock_ctx *ctx,
-                      const u8 key[32], const u8 nonce[24])
-{
-    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, 64);
-    crypto_poly1305_init  (&ctx->poly  , auth_key);
-    WIPE_BUFFER(auth_key);
-}
-
-void crypto_lock_auth_ad(crypto_lock_ctx *ctx, const u8 *msg, size_t msg_size)
-{
-    crypto_poly1305_update(&ctx->poly, msg, msg_size);
-    ctx->ad_size += msg_size;
-}
-
-void crypto_lock_auth_message(crypto_lock_ctx *ctx,
-                              const u8 *cipher_text, size_t text_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_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])
+static void lock_auth(u8 mac[16], const u8  auth_key[32],
+                      const u8 *ad         , size_t ad_size,
+                      const u8 *cipher_text, size_t text_size)
 {
-    lock_ad_padding(ctx);
     u8 sizes[16]; // Not secret, not wiped
-    store64_le(sizes + 0, ctx->ad_size);
-    store64_le(sizes + 8, ctx->message_size);
-    crypto_poly1305_update(&ctx->poly, zero, ALIGN(ctx->message_size, 16));
-    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_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])
-{
-    u8 real_mac[16];
-    crypto_lock_final(ctx, real_mac);
-    int mismatch = crypto_verify16(real_mac, mac);
-    WIPE_BUFFER(real_mac);
-    return mismatch;
+    store64_le(sizes + 0, ad_size);
+    store64_le(sizes + 8, text_size);
+    crypto_poly1305_ctx poly_ctx;           // auto wiped...
+    crypto_poly1305_init  (&poly_ctx, auth_key);
+    crypto_poly1305_update(&poly_ctx, ad         , ad_size);
+    crypto_poly1305_update(&poly_ctx, zero       , ALIGN(ad_size, 16));
+    crypto_poly1305_update(&poly_ctx, cipher_text, text_size);
+    crypto_poly1305_update(&poly_ctx, zero       , ALIGN(text_size, 16));
+    crypto_poly1305_update(&poly_ctx, sizes      , 16);
+    crypto_poly1305_final (&poly_ctx, mac); // ...here
 }
 
 void crypto_lock_aead(u8        mac[16],
@@ -2145,11 +2087,15 @@ void crypto_lock_aead(u8        mac[16],
                       const u8 *ad        , size_t ad_size,
                       const u8 *plain_text, size_t text_size)
 {
-    crypto_lock_ctx ctx;
-    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);
+    u8 sub_key[32];
+    u8 auth_key[64]; // "Wasting" the whole Chacha block is faster
+    crypto_hchacha20(sub_key, key, nonce);
+    crypto_chacha20(auth_key, 0, 64, sub_key, nonce + 16);
+    crypto_chacha20_ctr(cipher_text, plain_text, text_size,
+                        sub_key, nonce + 16, 1);
+    lock_auth(mac, auth_key, ad, ad_size, cipher_text, text_size);
+    WIPE_BUFFER(sub_key);
+    WIPE_BUFFER(auth_key);
 }
 
 int crypto_unlock_aead(u8       *plain_text,
@@ -2159,17 +2105,20 @@ int crypto_unlock_aead(u8       *plain_text,
                        const u8 *ad         , size_t ad_size,
                        const u8 *cipher_text, size_t 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);
-        return -1; // reject forgeries before wasting our time decrypting
+    u8 sub_key[32];
+    u8 auth_key[64]; // "Wasting" the whole Chacha block is faster
+    crypto_hchacha20(sub_key, key, nonce);
+    crypto_chacha20(auth_key, 0, 64, sub_key, nonce + 16);
+    u8 real_mac[16];
+    lock_auth(real_mac, auth_key, ad, ad_size, cipher_text, text_size);
+    WIPE_BUFFER(auth_key);
+    if (crypto_verify16(mac, real_mac)) {
+        WIPE_BUFFER(sub_key);
+        return -1;
     }
-    crypto_chacha20_encrypt(&chacha_ctx, plain_text, cipher_text, text_size);
-    WIPE_CTX(&chacha_ctx);
+    crypto_chacha20_ctr(plain_text, cipher_text, text_size,
+                        sub_key, nonce + 16, 1);
+    WIPE_BUFFER(sub_key);
     return 0;
 }
 
index c99561def611a2c213a89c5120b52758243addc4..161520ac8c25061229bf154de5a1434436bfdcba 100644 (file)
 // Do not rely on the size or content on any of those types,
 // they may change without notice.
 
-// Chacha20
-typedef struct {
-    uint32_t input[16]; // current input, unencrypted
-    uint32_t pool [16]; // last input, encrypted
-    size_t   pool_idx;  // pointer to random_pool
-} crypto_chacha_ctx;
-
 // Poly1305
 typedef struct {
     uint32_t r[4];   // constant multiplier (from the secret key)
@@ -29,16 +22,6 @@ typedef struct {
     size_t   c_idx;  // How many bytes are there in the chunk.
 } crypto_poly1305_ctx;
 
-// Authenticated encryption
-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
-
 // Hash (Blake2b)
 typedef struct {
     uint64_t hash[8];
@@ -114,31 +97,6 @@ int crypto_unlock_aead(uint8_t       *plain_text,
                        const uint8_t *ad         , size_t ad_size,
                        const uint8_t *cipher_text, size_t text_size);
 
-// Incremental interface (encryption)
-void crypto_lock_init(crypto_lock_ctx *ctx,
-                      const uint8_t    key[32],
-                      const uint8_t    nonce[24]);
-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,
-                        size_t           text_size);
-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_auth_ad      crypto_lock_auth_ad
-#define crypto_unlock_auth_message crypto_lock_auth_message
-void crypto_unlock_update(crypto_unlock_ctx *ctx,
-                          uint8_t           *plain_text,
-                          const uint8_t     *cipher_text,
-                          size_t             text_size);
-int crypto_unlock_final(crypto_unlock_ctx *ctx, const uint8_t mac[16]);
-
 
 // General purpose hash (Blake2b)
 // ------------------------------
@@ -227,32 +185,47 @@ int crypto_check_final  (crypto_check_ctx *ctx);
 
 // For experts only.  You have been warned.
 
-
 // Chacha20
 // --------
 
 // Specialised hash.
-void crypto_chacha20_H(uint8_t       out[32],
-                       const uint8_t key[32],
-                       const uint8_t in [16]);
-
-void crypto_chacha20_init(crypto_chacha_ctx *ctx,
-                          const uint8_t      key[32],
-                          const uint8_t      nonce[8]);
-
-void crypto_chacha20_x_init(crypto_chacha_ctx *ctx,
-                            const uint8_t      key[32],
-                            const uint8_t      nonce[24]);
-
-void crypto_chacha20_set_ctr(crypto_chacha_ctx *ctx, uint64_t ctr);
-
-void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx,
-                             uint8_t           *cipher_text,
-                             const uint8_t     *plain_text,
-                             size_t             text_size);
-
-void crypto_chacha20_stream(crypto_chacha_ctx *ctx,
-                            uint8_t *stream, size_t size);
+void crypto_hchacha20(uint8_t       out[32],
+                      const uint8_t key[32],
+                      const uint8_t in [16]);
+
+void crypto_chacha20(uint8_t       *cipher_text,
+                     const uint8_t *plain_text,
+                     size_t         text_size,
+                     const uint8_t  key[32],
+                     const uint8_t  nonce[8]);
+void crypto_xchacha20(uint8_t       *cipher_text,
+                      const uint8_t *plain_text,
+                      size_t         text_size,
+                      const uint8_t  key[32],
+                      const uint8_t  nonce[24]);
+void crypto_ietf_chacha20(uint8_t       *cipher_text,
+                          const uint8_t *plain_text,
+                          size_t         text_size,
+                          const uint8_t  key[32],
+                          const uint8_t  nonce[12]);
+void crypto_chacha20_ctr(uint8_t       *cipher_text,
+                         const uint8_t *plain_text,
+                         size_t         text_size,
+                         const uint8_t  key[32],
+                         const uint8_t  nonce[8],
+                         uint64_t       ctr);
+void crypto_xchacha20_ctr(uint8_t       *cipher_text,
+                          const uint8_t *plain_text,
+                          size_t         text_size,
+                          const uint8_t  key[32],
+                          const uint8_t  nonce[24],
+                          uint64_t       ctr);
+void crypto_ietf_chacha20_ctr(uint8_t       *cipher_text,
+                              const uint8_t *plain_text,
+                              size_t         text_size,
+                              const uint8_t  key[32],
+                              const uint8_t  nonce[12],
+                              uint32_t       ctr);
 
 
 // Poly 1305
index 2a1d82faac08bf78c19ddf4b9b60ca6378d11e07..913a953af0ae31fed51dc57223a5fe578ae43341 100644 (file)
@@ -11,9 +11,7 @@ static u64 chacha20(void)
     RANDOM_INPUT(nonce,    8);
 
     TIMING_START {
-        crypto_chacha_ctx ctx;
-        crypto_chacha20_init(&ctx, key, nonce);
-        crypto_chacha20_encrypt(&ctx, out, in, SIZE);
+        crypto_chacha20(out, in, SIZE, key, nonce);
     }
     TIMING_END;
 }
index f2a60130550446376ca5c4200ad3fabb35095279..efe85bf617f43a8b9d157b3c9fecaf9d323b0faa 100644 (file)
@@ -2,6 +2,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include "monocypher.h"
+#include "deprecated/chacha20.h"
+#include "deprecated/aead-incr.h"
 #include "sha512.h"
 #include "utils.h"
 #include "vectors.h"
@@ -21,10 +23,13 @@ static void chacha20(const vector in[], vector *out)
     const vector *nonce = in + 1;
     const vector *plain = in + 2;
     u64 ctr = load64_le(in[3].buf);
-    crypto_chacha_ctx ctx;
-    crypto_chacha20_init   (&ctx, key->buf, nonce->buf);
-    crypto_chacha20_set_ctr(&ctx, ctr);
-    crypto_chacha20_encrypt(&ctx, out->buf, plain->buf, plain->size);
+    crypto_chacha20_ctr(out->buf, plain->buf, plain->size,
+                        key->buf, nonce->buf, ctr);
+
+    /* crypto_chacha_ctx ctx; */
+    /* crypto_chacha20_init   (&ctx, key->buf, nonce->buf); */
+    /* crypto_chacha20_set_ctr(&ctx, ctr); */
+    /* crypto_chacha20_encrypt(&ctx, out->buf, plain->buf, plain->size); */
 }
 
 static void hchacha20(const vector in[], vector *out)