[email protected] (Niels Möller) writes:

> Nikos Mavrogiannopoulos <[email protected]> writes:
>
>> For me OCB is low priority.
>
> Ok, let's leave ocb for now (I will still consider it if someone else
> writes a complete patch, including testcases and docs, in time for the
> release).
>
>> Chacha with poly (not in the list above) however is more important to me
>> to implement the final draft (on the current state the algorithm is
>> fixed, only typos and other non-essential parts can be changed)
>> https://tools.ietf.org/html/draft-irtf-cfrg-chacha20-poly1305-08
>
> Thanks for the reminder. I agree that makes a lot of sense for 3.1. You
> have done some work to update of Nettle's implementation, but I don't
> remember the status?

Patch below (and also in the "chacha96"-branch in the public repo). Any
comments before I merge it? In particular, is chacha_set_nonce96 a good
name and function?

Regards,
/Niels

diff --git a/ChangeLog b/ChangeLog
index 00007fe..9fd2d8f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2015-01-30  Niels Möller  <[email protected]>
+
+       Update chacha-poly1305 for draft-irtf-cfrg-chacha20-poly1305-08.
+       * chacha-poly1305.h (CHACHA_POLY1305_NONCE_SIZE): Increase to 12
+       bytes, i.e., CHACHA_NONCE96_SIZE.
+       * chacha-poly1305.c (chacha_poly1305_set_nonce): Use
+       chacha_set_nonce96.
+       (poly1305_pad): New function.
+       (chacha_poly1305_encrypt): Use poly1305_pad.
+       (chacha_poly1305_digest): Call poly1305_pad, and format length
+       fields as a single poly1305 block.
+
+       * chacha-set-nonce.c (chacha_set_nonce96): New function.
+       * chacha.h (CHACHA_NONCE96_SIZE): New constant.
+       * testsuite/chacha-test.c: Add test for chacha with 96-bit nonce.
+
 2015-01-27  Niels Möller  <[email protected]>
 
        * ecc.h: Deleted declarations of unused itch functions. Moved
diff --git a/chacha-poly1305.c b/chacha-poly1305.c
index 35c4bfe..c5109b8 100644
--- a/chacha-poly1305.c
+++ b/chacha-poly1305.c
@@ -2,7 +2,7 @@
 
    AEAD mechanism based on chacha and poly1305.
 
-   Copyright (C) 2014 Niels Möller
+   Copyright (C) 2014, 2015 Niels Möller
 
    This file is part of GNU Nettle.
 
@@ -31,6 +31,20 @@
    not, see http://www.gnu.org/licenses/.
 */
 
+/* This implements chacha-poly1305 according to
+   draft-irtf-cfrg-chacha20-poly1305-08. The inputs to poly1305 are:
+
+     associated data
+     zero padding
+     ciphertext
+     zero padding
+     length of associated data (64-bit, little endian)
+     length of ciphertext (64-bit, little endian)
+
+   where the padding fields are 0-15 zero bytes, filling up to a
+   16-byte boundary.
+*/
+
 #if HAVE_CONFIG_H
 # include "config.h"
 #endif
@@ -62,7 +76,7 @@ chacha_poly1305_set_nonce (struct chacha_poly1305_ctx *ctx,
     uint8_t subkey[32];
   } u;
 
-  chacha_set_nonce (&ctx->chacha, nonce);
+  chacha_set_nonce96 (&ctx->chacha, nonce);
   /* Generate authentication key */
   _chacha_core (u.x, ctx->chacha.state, CHACHA_ROUNDS);
   poly1305_set_key (&ctx->poly1305, u.subkey);  
@@ -84,6 +98,17 @@ poly1305_update (struct chacha_poly1305_ctx *ctx,
   MD_UPDATE (ctx, length, data, COMPRESS, (void) 0);
 }
 
+static void
+poly1305_pad (struct chacha_poly1305_ctx *ctx)
+{
+  if (ctx->index)
+    {
+      memset (ctx->block + ctx->index, 0,
+             POLY1305_BLOCK_SIZE - ctx->index);
+      _poly1305_block(&ctx->poly1305, ctx->block, 1);
+      ctx->index = 0;
+    }
+}
 void
 chacha_poly1305_update (struct chacha_poly1305_ctx *ctx,
                        size_t length, const uint8_t *data)
@@ -102,12 +127,8 @@ chacha_poly1305_encrypt (struct chacha_poly1305_ctx *ctx,
     return;
 
   assert (ctx->data_size % CHACHA_POLY1305_BLOCK_SIZE == 0);
-  if (!ctx->data_size)
-    {
-      uint8_t buf[8];
-      LE_WRITE_UINT64 (buf, ctx->auth_size);
-      poly1305_update (ctx, sizeof(buf), buf);
-    }
+  poly1305_pad (ctx);
+
   chacha_crypt (&ctx->chacha, length, dst, src);
   poly1305_update (ctx, length, dst);
   ctx->data_size += length;
@@ -121,12 +142,8 @@ chacha_poly1305_decrypt (struct chacha_poly1305_ctx *ctx,
     return;
 
   assert (ctx->data_size % CHACHA_POLY1305_BLOCK_SIZE == 0);
-  if (!ctx->data_size)
-    {
-      uint8_t buf[8];
-      LE_WRITE_UINT64 (buf, ctx->auth_size);
-      poly1305_update (ctx, sizeof(buf), buf);
-    }
+  poly1305_pad (ctx);
+
   poly1305_update (ctx, length, src);
   chacha_crypt (&ctx->chacha, length, dst, src);
   ctx->data_size += length;
@@ -136,27 +153,14 @@ void
 chacha_poly1305_digest (struct chacha_poly1305_ctx *ctx,
                        size_t length, uint8_t *digest)
 {
-  uint8_t buf[8];
-  if (!ctx->data_size)
-    {
-      LE_WRITE_UINT64 (buf, ctx->auth_size);
-      poly1305_update (ctx, sizeof(buf), buf);
-    }
-  LE_WRITE_UINT64 (buf, ctx->data_size);
-  poly1305_update (ctx, sizeof(buf), buf);
+  uint8_t buf[16];
 
-  /* Final bytes. FIXME: Duplicated in poly1305_aes128.c */
-  if (ctx->index > 0)
-    {
-      assert (ctx->index < POLY1305_BLOCK_SIZE);
+  poly1305_pad (ctx);
+  LE_WRITE_UINT64 (buf, ctx->auth_size);
+  LE_WRITE_UINT64 (buf + 8, ctx->data_size);
 
-      ctx->block[ctx->index] = 1;
-      memset (ctx->block + ctx->index + 1,
-             0, POLY1305_BLOCK_SIZE - 1 - ctx->index);
+  _poly1305_block (&ctx->poly1305, buf, 1);
 
-      _poly1305_block (&ctx->poly1305, ctx->block, 0);
-    }
-  
   poly1305_digest (&ctx->poly1305, &ctx->s);
   memcpy (digest, &ctx->s.b, length);
 }
diff --git a/chacha-poly1305.h b/chacha-poly1305.h
index 9c2688b..ce40b77 100644
--- a/chacha-poly1305.h
+++ b/chacha-poly1305.h
@@ -53,7 +53,7 @@ extern "C" {
 #define CHACHA_POLY1305_BLOCK_SIZE 64
 /* FIXME: Any need for 128-bit variant? */
 #define CHACHA_POLY1305_KEY_SIZE 32
-#define CHACHA_POLY1305_NONCE_SIZE CHACHA_NONCE_SIZE
+#define CHACHA_POLY1305_NONCE_SIZE CHACHA_NONCE96_SIZE
 #define CHACHA_POLY1305_DIGEST_SIZE 16
 
 struct chacha_poly1305_ctx
diff --git a/chacha-set-nonce.c b/chacha-set-nonce.c
index e73babc..607f176 100644
--- a/chacha-set-nonce.c
+++ b/chacha-set-nonce.c
@@ -59,3 +59,12 @@ chacha_set_nonce(struct chacha_ctx *ctx, const uint8_t 
*nonce)
   ctx->state[14] = LE_READ_UINT32(nonce + 0);
   ctx->state[15] = LE_READ_UINT32(nonce + 4);
 }
+
+void
+chacha_set_nonce96(struct chacha_ctx *ctx, const uint8_t *nonce)
+{
+  ctx->state[12] = 0;
+  ctx->state[13] = LE_READ_UINT32(nonce + 0);
+  ctx->state[14] = LE_READ_UINT32(nonce + 4);
+  ctx->state[15] = LE_READ_UINT32(nonce + 8);
+}
diff --git a/chacha.h b/chacha.h
index 41df707..3f08283 100644
--- a/chacha.h
+++ b/chacha.h
@@ -45,6 +45,7 @@ extern "C" {
 /* Name mangling */
 #define chacha_set_key nettle_chacha_set_key
 #define chacha_set_nonce nettle_chacha_set_nonce
+#define chacha_set_nonce96 nettle_chacha_set_nonce96
 #define chacha_crypt nettle_chacha_crypt
 #define _chacha_core _nettle_chacha_core
 
@@ -52,6 +53,7 @@ extern "C" {
 #define CHACHA_KEY_SIZE 32
 #define CHACHA_BLOCK_SIZE 64
 #define CHACHA_NONCE_SIZE 8
+#define CHACHA_NONCE96_SIZE 12
 
 #define _CHACHA_STATE_LENGTH 16
 
@@ -78,6 +80,9 @@ void
 chacha_set_nonce(struct chacha_ctx *ctx, const uint8_t *nonce);
 
 void
+chacha_set_nonce96(struct chacha_ctx *ctx, const uint8_t *nonce);
+
+void
 chacha_crypt(struct chacha_ctx *ctx, size_t length, 
              uint8_t *dst, const uint8_t *src);
 
diff --git a/testsuite/chacha-poly1305-test.c b/testsuite/chacha-poly1305-test.c
index 2f320f3..313e822 100644
--- a/testsuite/chacha-poly1305-test.c
+++ b/testsuite/chacha-poly1305-test.c
@@ -4,13 +4,30 @@
 void
 test_main(void)
 {
-  /* From draft-agl-tls-chacha20poly1305-04 */
+  /* From draft-irtf-cfrg-chacha20-poly1305-08 */
   test_aead (&nettle_chacha_poly1305, NULL,
-            SHEX("4290bcb154173531f314af57f3be3b50"
-                 "06da371ece272afa1b5dbdd1100a1007"),  /* key */
-            SHEX("87e229d4500845a079c0"),              /* auth data */
-            SHEX("86d09974840bded2a5ca"),              /* plain text */
-            SHEX("e3e446f7ede9a19b62a4"),              /* ciphertext */
-            SHEX("cd7cf67be39c794a"),                  /* nonce */
-            SHEX("677dabf4e3d24b876bb284753896e1d6")); /* tag */
+            SHEX("8081828384858687 88898a8b8c8d8e8f"
+                 "9091929394959697 98999a9b9c9d9e9f"),
+            SHEX("50515253c0c1c2c3 c4c5c6c7"),
+            SHEX("4c61646965732061 6e642047656e746c"
+                 "656d656e206f6620 74686520636c6173"
+                 "73206f6620273939 3a20496620492063"
+                 "6f756c64206f6666 657220796f75206f"
+                 "6e6c79206f6e6520 74697020666f7220"
+                 "7468652066757475 72652c2073756e73"
+                 "637265656e20776f 756c642062652069"
+                 "742e"),
+            SHEX("d31a8d34648e60db7b86afbc53ef7ec2"
+                 "a4aded51296e08fea9e2b5a736ee62d6"
+                 "3dbea45e8ca9671282fafb69da92728b"
+                 "1a71de0a9e060b2905d6a5b67ecd3b36"
+                 "92ddbd7f2d778b8c9803aee328091b58"
+                 "fab324e4fad675945585808b4831d7bc"
+                 "3ff4def08e4b7a9de576d26586cec64b"
+                 "6116"),
+            /* The draft splits the nonce into a "common part" and an
+               iv, and it seams the "common part" is the first 4
+               bytes. */
+            SHEX("0700000040414243 44454647"),
+            SHEX("1ae10b594f09e26a 7e902ecbd0600691"));
 }
diff --git a/testsuite/chacha-test.c b/testsuite/chacha-test.c
index 8c5630d..9edb941 100644
--- a/testsuite/chacha-test.c
+++ b/testsuite/chacha-test.c
@@ -44,20 +44,30 @@ test_chacha(const struct tstring *key, const struct tstring 
*nonce,
 
   ASSERT (key->length == CHACHA_KEY_SIZE);
   chacha_set_key (&ctx, key->data);
-  ASSERT (nonce->length == CHACHA_NONCE_SIZE);
 
   if (rounds == 20)
     {
       uint8_t *data = xalloc (expected->length + 2);
-      data++;
       size_t length;
+      data++;
 
       for (length = 1; length <= expected->length; length++)
        {
          data[-1] = 17;
          memset (data, 0, length);
          data[length] = 17;
-         chacha_set_nonce(&ctx, nonce->data);
+         if (nonce->length == CHACHA_NONCE_SIZE)
+           chacha_set_nonce(&ctx, nonce->data);
+         else if (nonce->length == CHACHA_NONCE96_SIZE)
+           {
+             chacha_set_nonce96(&ctx, nonce->data);
+             /* Use initial counter 1, for
+                draft-irtf-cfrg-chacha20-poly1305-08 test cases. */
+             ctx.state[12]++;
+           }
+         else
+           die ("Bad nonce size %u.\n", (unsigned) nonce->length);
+
          chacha_crypt (&ctx, length, data, data);
 
          ASSERT (data[-1] == 17);
@@ -84,6 +94,7 @@ test_chacha(const struct tstring *key, const struct tstring 
*nonce,
         numbers of rounds. */
       uint32_t out[_CHACHA_STATE_LENGTH];
       ASSERT (expected->length == CHACHA_BLOCK_SIZE);
+      ASSERT (nonce->length == CHACHA_NONCE_SIZE);
 
       chacha_set_nonce(&ctx, nonce->data);
       _chacha_core (out, ctx.state, rounds);
@@ -622,4 +633,14 @@ test_main(void)
                   "ae2c4c90225ba9ea 14d518f55929dea0"
                   "98ca7a6ccfe61227 053c84e49a4a3332"),
              20);
+
+  /* From draft-irtf-cfrg-chacha20-poly1305-08, with 96-bit nonce */
+  test_chacha(SHEX("0001020304050607 08090a0b0c0d0e0f"
+                  "1011121314151617 18191a1b1c1d1e1f"),
+             SHEX("000000090000004a 00000000"),
+             SHEX("10f1e7e4d13b5915 500fdd1fa32071c4"
+                  "c7d1f4c733c06803 0422aa9ac3d46c4e"
+                  "d2826446079faa09 14c2d705d98b02a2"
+                  "b5129cd1de164eb9 cbd083e8a2503c4e"),
+             20);
 }


-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.
_______________________________________________
nettle-bugs mailing list
[email protected]
http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs

Reply via email to