Add XChaCha20-Poly1305 AEAD.

This is a version of ChaCha20-Poly1305 that takes a 24-byte nonce,
making the nonce suitable for random generation. It's compatible with
the AEAD of the same name in libsodium.

Change-Id: Ie8b20ba551e5a290b390d362e487f06377166f4c
Reviewed-on: https://boringssl-review.googlesource.com/30384
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/chacha/chacha.c b/crypto/chacha/chacha.c
index 646ef7a..eac51a5 100644
--- a/crypto/chacha/chacha.c
+++ b/crypto/chacha/chacha.c
@@ -22,12 +22,48 @@
 #include <openssl/cpu.h>
 
 #include "../internal.h"
+#include "internal.h"
 
 
 #define U8TO32_LITTLE(p)                              \
   (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \
    ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24))
 
+// sigma contains the ChaCha constants, which happen to be an ASCII string.
+static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
+                                   '2', '-', 'b', 'y', 't', 'e', ' ', 'k' };
+
+#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
+
+// QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round.
+#define QUARTERROUND(a, b, c, d)                \
+  x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 16); \
+  x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 12); \
+  x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a],  8); \
+  x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c],  7);
+
+void CRYPTO_hchacha20(uint8_t out[32], const uint8_t key[32],
+                      const uint8_t nonce[16]) {
+  uint32_t x[16];
+  OPENSSL_memcpy(x, sigma, sizeof(sigma));
+  OPENSSL_memcpy(&x[4], key, 32);
+  OPENSSL_memcpy(&x[12], nonce, 16);
+
+  for (size_t i = 0; i < 20; i += 2) {
+    QUARTERROUND(0, 4, 8, 12)
+    QUARTERROUND(1, 5, 9, 13)
+    QUARTERROUND(2, 6, 10, 14)
+    QUARTERROUND(3, 7, 11, 15)
+    QUARTERROUND(0, 5, 10, 15)
+    QUARTERROUND(1, 6, 11, 12)
+    QUARTERROUND(2, 7, 8, 13)
+    QUARTERROUND(3, 4, 9, 14)
+  }
+
+  OPENSSL_memcpy(out, &x[0], sizeof(uint32_t) * 4);
+  OPENSSL_memcpy(&out[16], &x[12], sizeof(uint32_t) * 4);
+}
+
 #if !defined(OPENSSL_NO_ASM) &&                         \
     (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
      defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
@@ -69,12 +105,6 @@
 
 #else
 
-// sigma contains the ChaCha constants, which happen to be an ASCII string.
-static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
-                                   '2', '-', 'b', 'y', 't', 'e', ' ', 'k' };
-
-#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
-
 #define U32TO8_LITTLE(p, v)    \
   {                            \
     (p)[0] = (v >> 0) & 0xff;  \
@@ -83,13 +113,6 @@
     (p)[3] = (v >> 24) & 0xff; \
   }
 
-// QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round.
-#define QUARTERROUND(a, b, c, d)                \
-  x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 16); \
-  x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 12); \
-  x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a],  8); \
-  x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c],  7);
-
 // chacha_core performs 20 rounds of ChaCha on the input words in
 // |input| and writes the 64 output bytes to |output|.
 static void chacha_core(uint8_t output[64], const uint32_t input[16]) {
diff --git a/crypto/chacha/internal.h b/crypto/chacha/internal.h
new file mode 100644
index 0000000..5a49811
--- /dev/null
+++ b/crypto/chacha/internal.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2018, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_CHACHA_INTERNAL
+#define OPENSSL_HEADER_CHACHA_INTERNAL
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+// CRYPTO_hchacha20 computes the HChaCha20 function, which should only be used
+// as part of XChaCha20.
+void CRYPTO_hchacha20(uint8_t out[32], const uint8_t key[32],
+                      const uint8_t nonce[16]);
+
+
+#if defined(__cplusplus)
+}  // extern C
+#endif
+
+#endif  // OPENSSL_HEADER_CHACHA_INTERNAL
diff --git a/crypto/cipher_extra/aead_test.cc b/crypto/cipher_extra/aead_test.cc
index 996cb22..fff7d43 100644
--- a/crypto/cipher_extra/aead_test.cc
+++ b/crypto/cipher_extra/aead_test.cc
@@ -63,6 +63,8 @@
 #endif
     {"ChaCha20Poly1305", EVP_aead_chacha20_poly1305,
      "chacha20_poly1305_tests.txt", false, true, 0},
+    {"XChaCha20Poly1305", EVP_aead_xchacha20_poly1305,
+     "xchacha20_poly1305_tests.txt", false, true, 0},
     {"AES_128_CBC_SHA1_TLS", EVP_aead_aes_128_cbc_sha1_tls,
      "aes_128_cbc_sha1_tls_tests.txt", true, false, 11},
     {"AES_128_CBC_SHA1_TLSImplicitIV",
diff --git a/crypto/cipher_extra/e_chacha20poly1305.c b/crypto/cipher_extra/e_chacha20poly1305.c
index 64ab457..e632010 100644
--- a/crypto/cipher_extra/e_chacha20poly1305.c
+++ b/crypto/cipher_extra/e_chacha20poly1305.c
@@ -26,6 +26,7 @@
 
 #include "../fipsmodule/cipher/internal.h"
 #include "../internal.h"
+#include "../chacha/internal.h"
 
 
 #define POLY1305_TAG_LEN 16
@@ -151,16 +152,15 @@
 }
 
 // calc_tag fills |tag| with the authentication tag for the given inputs.
-static void calc_tag(uint8_t tag[POLY1305_TAG_LEN],
-                     const struct aead_chacha20_poly1305_ctx *c20_ctx,
+static void calc_tag(uint8_t tag[POLY1305_TAG_LEN], const uint8_t *key,
                      const uint8_t nonce[12], const uint8_t *ad, size_t ad_len,
                      const uint8_t *ciphertext, size_t ciphertext_len,
                      const uint8_t *ciphertext_extra,
                      size_t ciphertext_extra_len) {
   alignas(16) uint8_t poly1305_key[32];
   OPENSSL_memset(poly1305_key, 0, sizeof(poly1305_key));
-  CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
-                   c20_ctx->key, nonce, 0);
+  CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), key, nonce,
+                   0);
 
   static const uint8_t padding[16] = { 0 };  // Padding is all zeros.
   poly1305_state ctx;
@@ -181,18 +181,16 @@
   CRYPTO_poly1305_finish(&ctx, tag);
 }
 
-static int aead_chacha20_poly1305_seal_scatter(
-    const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
+static int chacha20_poly1305_seal_scatter(
+    const uint8_t *key, uint8_t *out, uint8_t *out_tag,
     size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
     size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
-    size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
-  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
-
-  if (extra_in_len + ctx->tag_len < ctx->tag_len) {
+    size_t extra_in_len, const uint8_t *ad, size_t ad_len, size_t tag_len) {
+  if (extra_in_len + tag_len < tag_len) {
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
-  if (max_out_tag_len < ctx->tag_len + extra_in_len) {
+  if (max_out_tag_len < tag_len + extra_in_len) {
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
@@ -213,7 +211,7 @@
     return 0;
   }
 
-  if (max_out_tag_len < ctx->tag_len) {
+  if (max_out_tag_len < tag_len) {
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
@@ -228,7 +226,7 @@
 
     for (size_t done = 0; done < extra_in_len; block_counter++) {
       memset(block, 0, sizeof(block));
-      CRYPTO_chacha_20(block, block, sizeof(block), c20_ctx->key, nonce,
+      CRYPTO_chacha_20(block, block, sizeof(block), key, nonce,
                        block_counter);
       for (size_t i = offset; i < sizeof(block) && done < extra_in_len;
            i++, done++) {
@@ -240,35 +238,69 @@
 
   union seal_data data;
   if (asm_capable()) {
-    OPENSSL_memcpy(data.in.key, c20_ctx->key, 32);
+    OPENSSL_memcpy(data.in.key, key, 32);
     data.in.counter = 0;
     OPENSSL_memcpy(data.in.nonce, nonce, 12);
     data.in.extra_ciphertext = out_tag;
     data.in.extra_ciphertext_len = extra_in_len;
     chacha20_poly1305_seal(out, in, in_len, ad, ad_len, &data);
   } else {
-    CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
-    calc_tag(data.out.tag, c20_ctx, nonce, ad, ad_len, out, in_len, out_tag,
+    CRYPTO_chacha_20(out, in, in_len, key, nonce, 1);
+    calc_tag(data.out.tag, key, nonce, ad, ad_len, out, in_len, out_tag,
              extra_in_len);
   }
 
-  OPENSSL_memcpy(out_tag + extra_in_len, data.out.tag, ctx->tag_len);
-  *out_tag_len = extra_in_len + ctx->tag_len;
+  OPENSSL_memcpy(out_tag + extra_in_len, data.out.tag, tag_len);
+  *out_tag_len = extra_in_len + tag_len;
   return 1;
 }
 
-static int aead_chacha20_poly1305_open_gather(
-    const EVP_AEAD_CTX *ctx, uint8_t *out, const uint8_t *nonce,
-    size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *in_tag,
-    size_t in_tag_len, const uint8_t *ad, size_t ad_len) {
+static int aead_chacha20_poly1305_seal_scatter(
+    const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
+    size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
+    size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
+    size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
   const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
 
+  return chacha20_poly1305_seal_scatter(
+      c20_ctx->key, out, out_tag, out_tag_len, max_out_tag_len, nonce,
+      nonce_len, in, in_len, extra_in, extra_in_len, ad, ad_len, ctx->tag_len);
+}
+
+static int aead_xchacha20_poly1305_seal_scatter(
+    const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
+    size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
+    size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
+    size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
+  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
+
+  if (nonce_len != 24) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
+    return 0;
+  }
+
+  alignas(4) uint8_t derived_key[32];
+  alignas(4) uint8_t derived_nonce[12];
+  CRYPTO_hchacha20(derived_key, c20_ctx->key, nonce);
+  OPENSSL_memset(derived_nonce, 0, 4);
+  OPENSSL_memcpy(&derived_nonce[4], &nonce[16], 8);
+
+  return chacha20_poly1305_seal_scatter(
+      derived_key, out, out_tag, out_tag_len, max_out_tag_len,
+      derived_nonce, sizeof(derived_nonce), in, in_len, extra_in, extra_in_len,
+      ad, ad_len, ctx->tag_len);
+}
+
+static int chacha20_poly1305_open_gather(
+    const uint8_t *key, uint8_t *out, const uint8_t *nonce,
+    size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *in_tag,
+    size_t in_tag_len, const uint8_t *ad, size_t ad_len, size_t tag_len) {
   if (nonce_len != 12) {
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
     return 0;
   }
 
-  if (in_tag_len != ctx->tag_len) {
+  if (in_tag_len != tag_len) {
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
@@ -287,16 +319,16 @@
 
   union open_data data;
   if (asm_capable()) {
-    OPENSSL_memcpy(data.in.key, c20_ctx->key, 32);
+    OPENSSL_memcpy(data.in.key, key, 32);
     data.in.counter = 0;
     OPENSSL_memcpy(data.in.nonce, nonce, 12);
     chacha20_poly1305_open(out, in, in_len, ad, ad_len, &data);
   } else {
-    calc_tag(data.out.tag, c20_ctx, nonce, ad, ad_len, in, in_len, NULL, 0);
-    CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
+    calc_tag(data.out.tag, key, nonce, ad, ad_len, in, in_len, NULL, 0);
+    CRYPTO_chacha_20(out, in, in_len, key, nonce, 1);
   }
 
-  if (CRYPTO_memcmp(data.out.tag, in_tag, ctx->tag_len) != 0) {
+  if (CRYPTO_memcmp(data.out.tag, in_tag, tag_len) != 0) {
     OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
@@ -304,6 +336,39 @@
   return 1;
 }
 
+static int aead_chacha20_poly1305_open_gather(
+    const EVP_AEAD_CTX *ctx, uint8_t *out, const uint8_t *nonce,
+    size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *in_tag,
+    size_t in_tag_len, const uint8_t *ad, size_t ad_len) {
+  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
+
+  return chacha20_poly1305_open_gather(c20_ctx->key, out, nonce, nonce_len, in,
+                                       in_len, in_tag, in_tag_len, ad, ad_len,
+                                       ctx->tag_len);
+}
+
+static int aead_xchacha20_poly1305_open_gather(
+    const EVP_AEAD_CTX *ctx, uint8_t *out, const uint8_t *nonce,
+    size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *in_tag,
+    size_t in_tag_len, const uint8_t *ad, size_t ad_len) {
+  const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
+
+  if (nonce_len != 24) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
+    return 0;
+  }
+
+  alignas(4) uint8_t derived_key[32];
+  alignas(4) uint8_t derived_nonce[12];
+  CRYPTO_hchacha20(derived_key, c20_ctx->key, nonce);
+  OPENSSL_memset(derived_nonce, 0, 4);
+  OPENSSL_memcpy(&derived_nonce[4], &nonce[16], 8);
+
+  return chacha20_poly1305_open_gather(
+      derived_key, out, derived_nonce, sizeof(derived_nonce), in, in_len,
+      in_tag, in_tag_len, ad, ad_len, ctx->tag_len);
+}
+
 static const EVP_AEAD aead_chacha20_poly1305 = {
     32,                // key len
     12,                // nonce len
@@ -321,6 +386,27 @@
     NULL,  // tag_len
 };
 
+static const EVP_AEAD aead_xchacha20_poly1305 = {
+    32,                // key len
+    24,                // nonce len
+    POLY1305_TAG_LEN,  // overhead
+    POLY1305_TAG_LEN,  // max tag length
+    1,                 // seal_scatter_supports_extra_in
+
+    aead_chacha20_poly1305_init,
+    NULL,  // init_with_direction
+    aead_chacha20_poly1305_cleanup,
+    NULL /* open */,
+    aead_xchacha20_poly1305_seal_scatter,
+    aead_xchacha20_poly1305_open_gather,
+    NULL,  // get_iv
+    NULL,  // tag_len
+};
+
 const EVP_AEAD *EVP_aead_chacha20_poly1305(void) {
   return &aead_chacha20_poly1305;
 }
+
+const EVP_AEAD *EVP_aead_xchacha20_poly1305(void) {
+  return &aead_xchacha20_poly1305;
+}
diff --git a/crypto/cipher_extra/test/xchacha20_poly1305_tests.txt b/crypto/cipher_extra/test/xchacha20_poly1305_tests.txt
new file mode 100644
index 0000000..86549f1
--- /dev/null
+++ b/crypto/cipher_extra/test/xchacha20_poly1305_tests.txt
@@ -0,0 +1,416 @@
+# Test vectors generated from libsodium with this code:
+#
+# #include <stdio.h>
+# #include <sodium.h>
+# #include <stdlib.h>
+#
+# void hexdump(const uint8_t *in, size_t in_len) {
+#   for (size_t i = 0; i < in_len; i++) {
+#     printf("%02x", in[i]);
+#   }
+#   printf("\n");
+# }
+#
+# int main() {
+#   uint8_t nonce[24];
+#   uint8_t key[32];
+#   uint8_t m[64], c[64];
+#   uint8_t ad[16], tag[16];
+#
+#   for (size_t ad_len = 0; ad_len < sizeof(ad); ad_len += 4) {
+#     for (size_t m_len = 0; m_len < sizeof(m); m_len += 5) {
+#       randombytes(nonce, sizeof(nonce));
+#       randombytes(key, sizeof(key));
+#       randombytes(m, m_len);
+#       randombytes(ad, ad_len);
+#
+#       unsigned long long tag_len = sizeof(tag);
+#
+#       if (crypto_aead_xchacha20poly1305_ietf_encrypt_detached(
+#               c, tag, &tag_len, m, m_len, ad, ad_len, NULL, nonce, key)) {
+#         abort();
+#       }
+#
+#       printf("KEY: ");
+#       hexdump(key, sizeof(key));
+#       printf("NONCE: ");
+#       hexdump(nonce, sizeof(nonce));
+#       printf("IN: ");
+#       hexdump(m, m_len);
+#       printf("AD: ");
+#       hexdump(ad, ad_len);
+#       printf("CT: ");
+#       hexdump(c, m_len);
+#       printf("TAG: ");
+#       hexdump(tag, sizeof(tag));
+#       printf("\n");
+#     }
+#   }
+#
+#   return 0;
+# }
+
+KEY: 1f4774fbe6324700d62dd6a104e7b3ca7160cfd958413f2afdb96695475f007e
+NONCE: 029174e5102710975a8a4a936075eb3e0f470d436884d250
+IN:
+AD:
+CT:
+TAG: f55cf0949af356f977479f1f187d7291
+
+KEY: eb27969c7abf9aff79348e1e77f1fcba7508ceb29a7471961b017aef9ceaf1c2
+NONCE: 990009311eab3459c1bee84b5b860bb5bdf93c7bec8767e2
+IN: e7ec3d4b9f
+AD:
+CT: 66bd484861
+TAG: 07e31b4dd0f51f0819a0641c86380f32
+
+KEY: 4b6d89dbd7d019c0e1683d4c2a497305c778e2089ddb0f383f2c7fa2a5a52153
+NONCE: 97525eb02a8d347fcf38c81b1be5c3ba59406241cf251ba6
+IN: 074db54ef9fbc680b41a
+AD:
+CT: 1221898afd6f516f770f
+TAG: 75e7182e7d715f5a32ee6733fd324539
+
+KEY: 766997b1dc6c3c73b1f50e8c28c0fcb90f206258e685aff320f2d4884506c8f4
+NONCE: 30e7a9454892ef304776b6dc3d2c2f767ed97041b331c173
+IN: b8250c93ac6cf28902137b4522cc67
+AD:
+CT: e2a13eeff8831a35d9336cb3b5c5d9
+TAG: 62fdf67735cad0172f9b88603b5f3c13
+
+KEY: 6585031b5649fcabd9d4971d4ac5646fc7dca22f991dfa7dac39647001004e20
+NONCE: 705ee25d03fec430e24c9c6ccaa633f5b86dd43682778278
+IN: 9a4ca0633886a742e0241f132e8f90794c34dfd4
+AD:
+CT: 0a8e6fd4cd1640be77c4c87dde4ae6222c887ed7
+TAG: edc4fbc91dfa07021e74ae0d9d1c98dc
+
+KEY: dfc6f7c86a10a319ebcb6362997e585f55b67f3434f47dc4039c2d67973e3077
+NONCE: 6097f30fd75229d928454c7d59a2d2c58bfddcb14c16438e
+IN: 74c946a7f0733377e852a23087506a28dccef86e101a4359c0
+AD:
+CT: 6e8ea0bb4c2f1323841d8e236816c61c3295866b75cefb5c25
+TAG: f16c0e9487ca7de5e7cb2a1b8bb370fc
+
+KEY: 59b8d488773767c4804d918709cfec6c69a193371145bb94f183899851aaadac
+NONCE: ad5bdf8f190ca2d2cc02a75bb62aa22274cb3c98fe2d25f2
+IN: 066b9ed10f16d3dc132b409aae02d8cac209dd9b4fb789c4d34725ab2a1f
+AD:
+CT: 2bbd4542489006df66ad1462a932524642b139ddcbf86b6b480e9e6d976c
+TAG: ca4835419ba029bc57010a8cc8bca80c
+
+KEY: 8c0cb4633cf8dc6b4b9552d1035f85517cb1ba4c36bcbc43338a8c6c7d15ce20
+NONCE: 8418b9655a0376fadefa3cdf8805815c4f7b56f467a74a95
+IN: 50c205a9c5d4088ba8e59a96fcd837f5170669854547678288199f1078ff2a81f0b19a
+AD:
+CT: 8b55a12df1a85dd3fb19c34ab047a85849d15a30225bb5360bad1f0a8f5f2bd49f5898
+TAG: bce13201df6e4a7e6d896262e45d969d
+
+KEY: b45386a75a5772e34bd193e1946f69ebfb90c37ae4581d39c9669d75e4584f50
+NONCE: 9fb763d0926585b5f726af9b8e3babdb331e9aa97f8d99ed
+IN: 64df0e341145d9e4a0d090153591a74893bc36cb9dae1e9570d8fee62e907cf004f9d8a360343483
+AD:
+CT: 3146d8a5c898edd832ec9d126e93b3a433ec97dc47dce0e1985bda88c88c6aeca46fc7d9a68e30ab
+TAG: 44fdb0d69abd8068442cb2ea6df8b2f2
+
+KEY: f2efbd358dd353639a162be39a957d27c0175d5ab72aeba4a266aeda434e4a58
+NONCE: 65a6f7ebe48de78beb183b518589a0afacf71b40a949fa59
+IN: f7473947996e6682a3b9c720f03cfaf26bbcdaf76c83342d2ad922435e227a5d1eacbd9bd6ea1727ec19fb0e42
+AD:
+CT: 778a0fb701b9d671ccfaf1454e8928158ede9bb4395119356a8133036840c1bcbb8fe5e19922fbbcf8b18596e7
+TAG: 9d195a89fdd29ca271405d3330f996f9
+
+KEY: 9dd674fb4a30a7bb85fc78050479ab0e2c3cc9f9f5b8689a7a67413aca304b21
+NONCE: ad9e8fe15940694725f232e88f79cda7c82fe1b8aae58ba4
+IN: 7272bb6609cbd1399a0b89f6ea255165f99330aeb170ac88fccdd8e226df0952407e35718fb5edc9e987faabb271cc69f7e7
+AD:
+CT: 846901650cb38974463a18c367676e1579ebdaf3e96b57224e842f5d5f678f3270b9a15f01241795662befb3db0768800e25
+TAG: 900004db3613acbeb33d65d74dd437d7
+
+KEY: 280cbe7380a0d8bb4d8dd4476012f2eeb388a37b8b71067969abb99f6a888007
+NONCE: 2e1854617c67002599e6b077a812c326deb22fe29d093cbb
+IN: d0901ec3d31ece2832685ff577f383bdff26c31341ea254acee7c5929a5df74fea2aa964524dc680b2f55fbd4fea900e956c304cc4ac3c
+AD:
+CT: 546370726cc63068d3520d67f4f57f65d03b9ecec21c2a8c7b1133089ad28b07025a7181bddeb4a49f514fac1a44f64ee3af33d778fb98
+TAG: 39084e33e42a1b05f58da65ba487d138
+
+KEY: 887564f75afa78f595cdadcea7340d20f5c5a2df169d0ad14b15fe32ce337004
+NONCE: 54c11df13d1f444da80b0964caeb59474b17b23a650a33f5
+IN: f0f008eece79ecb24b715dff8a3456dfe253924b99f98f2f1b18564cced50925fca860d1c2d4785bdf4a964c76c3079efa6b37c4ba2cacc534fb590c
+AD:
+CT: 32bb077268568d569b39e8ccdeeeb447ef424eaa2ffab565209a19b16a25952f897e5405bb0d67d8c9005d1c0b32687164d17fa4d0f412b80414c025
+TAG: 0bac7c0f8dce12917fbd4ed1738ac0cc
+
+KEY: 21c6aa88eb1a320d251f71a4b312ca75347040990d869a1dd2a1982c30fda2c7
+NONCE: 7dead2f1a3d9d45a9124a40efe8994300976991a4417ef4d
+IN:
+AD: e1bf7de4
+CT:
+TAG: 341e9d0687006f981bced2f985f953e6
+
+KEY: 0c97b9a65ffcd80b8f7c20c3904d0d6dd8809a7f97d7f46d39a12c198a85da5d
+NONCE: 1f2c1dbc5f52fc9c8f9ca7695515d01d15904b86f703fba3
+IN: ecaf65b66d
+AD: bd8a6f18
+CT: 8d1b2b0e38
+TAG: 27a7c7ac8bda627085414f0f31206a07
+
+KEY: 4ab5e3595f39c4379a924e5f8ebcf3279075c08d18daff01d9ddfa40e03faf12
+NONCE: 94e6ddc294f5f1531924ec018823343ebcc220a88ea5ee33
+IN: c91b73abe5316c3effc6
+AD: c576f6ea
+CT: abe960fbc64b339c53b1
+TAG: 7ebae48a2ff10117069324f04619ad6f
+
+KEY: a1e6146c71c2ea22300e9063455f621e15bd5bf1a3762e17f845e1aba5dd5a9c
+NONCE: 82ddb6929abff8a9ad03dfb86c0bb3e7c092d45ebfa60a1b
+IN: f011f32ccc2955158c117f53cf7b12
+AD: 5d14bc05
+CT: 44592321c665f51e9ffea052df1fea
+TAG: d556798b97f9b647729801419424affc
+
+KEY: 7a1af30362c27fd55b8c24b7fca324d350decee1d1f8fae56b66253a9dd127dd
+NONCE: 61201d6247992002e24e1a893180d4f0c19a3ae4cc74bf0c
+IN: 5c7150b6a4daa362e62f82f676fdc4c4b558df64
+AD: 00c49210
+CT: 27d9e2730b6809c08efbd4b0d24639c7b67486f3
+TAG: 5889fdee25379960038778e36b2cedb2
+
+KEY: 0b3fd9073e545ac44a7967263ead139c9547f7a54f06228fd3c8609fa2620784
+NONCE: 6450e1097d6f9ea76eb42e8e65972d501041c3a58baf8770
+IN: d679ae442b0351e5bff9906b099d45aab4f6aea5306a7a794f
+AD: 318d292b
+CT: a3f9ee45316d7b0f948a26145ee4fd0552bc6dc25e577e777a
+TAG: 0068a401a194b8417ec0e198baa81830
+
+KEY: 047c7d378fe80c02ee48df6f679a859253aed534fdcdd87023eb3d2f93fcafe3
+NONCE: ed240b0ff6f8ac585b3ea1ab2dab8080fc2f6401b010c5d0
+IN: 7288afb4e0fa5c58602090a75c10d84b5f5f1c0e03498519afe457251aa7
+AD: e4310302
+CT: 87906b14ca3e32ab01523b31ae0bb74590ce9e1df0811e743a2c7a93415a
+TAG: 3a0abeab93792b1ffe768d316da74741
+
+KEY: 1ad4e42acc5dfd07eb0a2456e9103cd0e150a36c667eb2f2b73c0d1ac1089ce3
+NONCE: 48efb52387284c5d38b4940c75f0c39a3f81f60bfebb48cb
+IN: da7edb5b3193b4484f09efa85fcf85600968ecdc537d3829a469c866ee67b0df677866
+AD: 446be8e3
+CT: b76457ca99e95b6539b12f1d6bdac55a6d5c6469b1ff274459363ec05241f7e6e5d3ce
+TAG: 06880ee508ce929da5a81f8b9de0031c
+
+KEY: 702a554c1b703d4dd69ad51234293ab787a01e15bdb3ce88bf89e18c01a67164
+NONCE: ea535d9c371241b9850b8b4a596b63db79eea60bd2cd9fbb
+IN: a97156e9b39d05c00b811552d22088d7ee090a117a7f08adac574820d592021f16207720d49fb5fd
+AD: ba5790e3
+CT: 8d0b2b04479c33287096f0c6276a73f6c037edc1a2b28f8d3b2b8e6d4c5f9dc5113309dd3ecb15e6
+TAG: 3cf303305e12924d29c223976699fb73
+
+KEY: 1bb7303fefa4d8d344bb9a215901b2314324bf1f3aeb9df5d1c1532c3a55ebf1
+NONCE: a304551e5f0dc98995ddfee6215a9995023a3696debfd302
+IN: 6cf6819ce3e7ed9d4f85f4a5699701dbcaf3161adc210c0b7825ddfd83d6d7c685db62f68b3801ccc8a786066d
+AD: 901c5feb
+CT: bc5ef09c111f76e54f897e6fce4aee1d25b6ed934f641ed5262d0c5eed45f610a6aea3b58b7771e34256d43a16
+TAG: b83f73f7995ba1b243dbf48ddfeb8e3a
+
+KEY: 24b294f6cbac10d87158d1c6aca83b337d596132afac7633f69a3b3e58823f11
+NONCE: 805772ff619cc6fcc5ec0e9965435d6f74a2290c055ec754
+IN: 65e8581286868caabcec1a9814db00b805edc660b94ee3babc6ce19a3ca868bd322105484d59b4ce02ced4071bc16642a1f2
+AD: 7ae1c561
+CT: fe1d463b1466e8e411f0b0700f90760472ee5141f3e5afef43fd729f1623dca75cd4d00576765b335f8b2b77b00527599cb3
+TAG: 111d8540fd5ec04b9ba16ed810133026
+
+KEY: 38e63e8b6402ac3f6d1641a1e3b74d2074be0fe41129975a3ff62b74ca52af05
+NONCE: 228d671b036710cbdaa72e9bf1d9ed6982b0bb3428a69fd6
+IN: 20a8d18878924d09aac32853c10e73dbd741134b7050ae6999839f2dbc727cb0052b5497c4bbd2a89e716278f15c81b871953614a49693
+AD: e9e6ac73
+CT: 80e0fe8eb26e5df229c6d939c944d440a37aa3cabf76eab5b9a420095513021ea4241ab367f6f44a20817b14631549ae6c96aa963970e1
+TAG: 1e80fbafcc7168e0494fce4cd76d692c
+
+KEY: 4325dd8406fdb8431a81f1b5db3603995256de36121019724cca2190c87a6e83
+NONCE: dcbf3077b36d5d678d668fd2d0c99284c780b55c4658ea75
+IN: 4f599ad04f79be9add10fdc649b8be53e1062ea5e9c2bed22265dc6fb30d5ab4fd4425b38ff14d8e68013405bec1eff8c9ef3069902e492aac73dcd9
+AD: 6fa0d757
+CT: 7decbdc7043495c59ecc64e720436bb0708b586a46f8745f74391477f5a2520905dfcebc3765a330999013d309dfaa997bf70bab6a0b8f4f2a2a3cdf
+TAG: 051ec4ecce208d9be0cd17f434e13be3
+
+KEY: 2d3d9ed4bc9eb9668733bafbb73e88be2cd17021c3a23be69b981d9f0df71df1
+NONCE: 84cae69639240c82b58895997511f145e474ebe1b008f391
+IN:
+AD: 64db597c26a4c3da
+CT:
+TAG: 2a22c4a962d46a719014ab7b0ffaf6d3
+
+KEY: 09ec4e79a02db53b19b54dd2d3592afc92c74ef57d1e0f51f3726a6631b1b73f
+NONCE: 2907ced16e0777fedb1e2de30df11b3fd712af41dd714a4b
+IN: b6e50cd4ea
+AD: b5488e9b7f339b7b
+CT: 0163e75330
+TAG: e29401c6d756adcc516580ae656852aa
+
+KEY: 9d5ac25a417b8a57b85332979e8a7cbad23617bb27772bbccc2acb0acae7b755
+NONCE: ff152421688dd6af7fef87817b508493a32d97a06fbda4f3
+IN: 92f4b9bc809be77e6a0d
+AD: 892b793f7a6e0727
+CT: bcc594f59de8ee8c22c6
+TAG: 1a8275816c0d32a1b6cfd41fa3889558
+
+KEY: eccf80c5f744d2ecc932f95ade0d9fe9327e19795023db1846d68d04720a2401
+NONCE: abc050fad8876589633b222d6a0f2e0bf709f73610aa23ee
+IN: 45a380e438405314510c166bac6840
+AD: c32c9a1ce6852046
+CT: 9fa452dc9ca04c16ff7bde9925e246
+TAG: 3d5e826162fa78de3fc043af26044a08
+
+KEY: b1912d6bc3cff47f0c3beccff85d7cd915b70ab88d0d3a8a59e994e1b0da8ac8
+NONCE: d8756090a42eea14ff25be890e66bfe4949fad498776ea20
+IN: e2f85df2ebcfa6045bd521abfe8af37fc88a0be1
+AD: 4576bb59b78032c8
+CT: 5eb6324aa48e0a4f72f5cb0a4917faf93af4209c
+TAG: 774f8077f039588495045fee07950e14
+
+KEY: 85162b111c9f3163f57c2cbc311a1e9aeed9dd6136b5784bc9c0b5052f8bffbd
+NONCE: 23cdb8b546bb8a5a746b24446f0ab4199f0543d915ff51f1
+IN: dc81000077d5743beef09ac91663885d984212bbccf3dbe6f3
+AD: 3084f3e9c4d0a15f
+CT: 692d17ae0b524ec6edc0cf49b69ac90c99bed44691f7ae63b7
+TAG: efe72ff84b3bccb4d83a27ddc574bc21
+
+KEY: b05ca358d8ca79f51283d83e2673bfb741c379ba271a773b8dd9c6a108e758d3
+NONCE: 9a53ad79f535c6e9da011463063c896f2ec7645e6e3548fc
+IN: 44e793742c774020e7349c996418042dc0dc30ee2bfd2654008c8929a436
+AD: 71ab5948c5e0f4c6
+CT: c5eddb7aeaa175b5f3dab68cf746f2acaf56fc62b29804629e25e2d63879
+TAG: bec3b7a8b8dad22ff3d14d26273294d2
+
+KEY: abb5136a01354c765a96e832df58bec3b088bd19dc4d6bd6674f2f02007ebdaa
+NONCE: 71267ac9f4fe5caa1d52cd85948a170a778f0141d54dbffe
+IN: afb526fe41c4e2a767ce77c4145b9d054268f5f3b279237dec97f8bc46f9d158868b86
+AD: 047baa2b04748b62
+CT: 0032d4c1e65da2266539464c5d3c2b1618454a6af0e7f1e3cfc87845c75f2f4ae8b03f
+TAG: b526a95a33f17ab61f2cdfc1e2dd486a
+
+KEY: bb826ed38008a0d7fb34c0c1a1a1149d2cad16b691d5129cc83f5eff2b3e5748
+NONCE: 4e02fe0915d81e9d5a62e5b3551b9db882e3873c0aaa230d
+IN: 20270d291a8d9791b0f5e35a64387bb4237bad61169841d7e1667c994ad49869c7d5580ffa752a2d
+AD: db852a275081e29b
+CT: d740012efb7e1bb986ce2c535134a45f658b92163c109bdecf1ce5b836879fe9e006a56be1fac8d7
+TAG: 21e931042e7df80695262198a06286c9
+
+KEY: 938d2c59f6f3e2e7316726537932372e05e8c1b5577aae0ee870bf712ff001ab
+NONCE: fb4d71cf7eb2f70df9759a64c76a36b75203f88bf64f4edb
+IN: 8910415d674a93c54c8f5e4aa88e59648d9a0a5039a66837d58ab14f0665a5f6d9af9b839f9033d0fe8bc58f19
+AD: a3fca278a63bf944
+CT: 1905c6987a702980b7f87f1ed2d3ae073abe1401b23434f3db43b5c37c979c2068ce9a92afedcdc218003848ea
+TAG: 1bd712f64777381f68be5ccc73f364a3
+
+KEY: dd0521842f498d23236692a22db0eb2f0f14fef57577e5fb194503e206b0973d
+NONCE: 519e0eee8f86c75c7a364e0905a5d10d82073e11b91083a5
+IN: 61ff13acb99c5a7fd1921ec787c8de23c1a712ff002b08cecc644a78c47341eab78e7680380c93c7d53d5e56ef050d6ff192
+AD: bb5c4e5ae8f7e461
+CT: 9bfdb0fd195fa5d37da3416b3b1e8f67bd2a456eb0317c02aabf9aac9d833a19bda299e6388e7b7119be235761477a34d49e
+TAG: 0f0c03b8423583cb8305a74f622fa1f9
+
+KEY: 189bd84be3fb02723539b29cf76d41507c8b85b7217777ee1fb8f84a24aa7fee
+NONCE: ef1bf39f22ba2edf86853505c24fafdf62c1a067963c63ba
+IN: d5f96e240b5dd77b9fb2bf11c154fcbff312a791c3eb0717684e4fd84bf943e788050b47e76c427f42f3e5344b2636091603ba3b1d7a91
+AD: 93368a8e0900c7b6
+CT: c55a8b7f587bee4f97514582c5115582abffd6312914d76c2568be6836f62ba098789ed897c9a7508a5dc214bf8c218664f29941ccdfd6
+TAG: 78f87352dcb1143038c95dc6e7352cfd
+
+KEY: 23a2dbfcd02d265805169fa86e6927c7d49c9a24d2707884e18955e32dafc542
+NONCE: 305c7851f46f23ea8d832d5ed09d266714fd14f82ba0f69c
+IN: 224de94a938d49cad46144e657e548bd86690a1b57b81558095eace59df1c552600dea389aaa609304fbc1eadf2241f2118c8bdf04522e1898efe1d4
+AD: 0075b20502bd29b2
+CT: 8e10c59369bbb0d72958100b05788498f59588795e075b8bce21d92d320206348b04010ced9b8cd3d651e825488915ce4a6e4f1af2f4d2f77b955376
+TAG: c39f0595ae8112dea6ef96df1c12458b
+
+KEY: 264e3c3f47bdf795cdde57d9a30be5a4da8b18463c0e3e05df28b7bf4e56410b
+NONCE: 3ee09b6e205c261bf48ac53a9ba0afa460a5d5c0f2d80be8
+IN:
+AD: 8eeec09d8972cb8ab0069554
+CT:
+TAG: 245a034d84edab9fa6f0decb6b984766
+
+KEY: d8ba98a272b5f91797b04b114311c3b92b7f2e3bb72edb7f78ed311b9f8ea2ad
+NONCE: 481de9a06eee76a501e3c2b9d7423d90596193ad9d8a6564
+IN: 9ee1a3134d
+AD: 928653701f6d6c8429b08c0d
+CT: 459a07898f
+TAG: 9188ec8d8e3bd91dcfda48fcc76773f7
+
+KEY: ac9afd627a745df682bb003517056f07876eb94d2f8c610c61b6ac0d34ec4ec0
+NONCE: eaae7b8704530db1e8c3dcc968a00604a333c7c27ba51b16
+IN: f7c3f6ee2e9c03394dc8
+AD: 796620b367d5f041821baf69
+CT: d4a69005790cc91d8d34
+TAG: e4c83def113afcf83a1ea8cb204a0eae
+
+KEY: ea1a07c1fd60a5421f1fb6c43b4318090e290c97aa3bfa037e6fc5ee00fd47d4
+NONCE: 37327805cce92b38a669affbca1de92e068727fcf6fbb09a
+IN: 7002ca765b91913ee719e7521ef5ac
+AD: 64e7c48fc3041eac0734737f
+CT: 9d8857a8c52a9ab3bf44b024b191b6
+TAG: d072c31714a7d0fe1596fd443a96e715
+
+KEY: b3beb34fe0229fc8f49b354e941025bde6a788f25017a60e8a49591ed5d7e7da
+NONCE: dd0e9fec76de1f6efb022b12164f7e9248b8e8c01d14ac02
+IN: acf360d7529a42be1f132f74745a940da9e823f2
+AD: 1489ca8d852f0a8547dbe8bc
+CT: 2e8718372d6e8167213cf112dc41c80377244f5a
+TAG: e4f31e8f84b9356999dc60989009e698
+
+KEY: 9357cecd10bab8d2e42ed88c0386204827c3b76e9e51150d09fd4e3b4e0e1e6f
+NONCE: 81f2106a5379e0ed861cf76b3cf95afb17515478b5cbcae9
+IN: ee51a0f25d091288b5e2b91ad11d491329e48b35a18a3a8685
+AD: b80cb677f4b409cd1537363b
+CT: f681f19fa8de1fdea3538001a46f30fa6333b76d6439337e68
+TAG: afad5e6d282d9df6d8119c32237b3e60
+
+KEY: 9f868600fbf81e40398b7dfb201fcae35d34bba10908860b0b2bf8b942b4e8fa
+NONCE: 2ddcc13c97185614095d437900b8c0a9170e0a4a50e46ba5
+IN: 133fa3ac176fee6df67472752e41c6834f13300c0064ff5b190f903b7ac7
+AD: 0d61321fbee8bb1f3f5cb454
+CT: b93abb311ec0bf018dc300c7d511b42ade72780373186e231820b44f22f0
+TAG: f8bd2f649a337783ff911e37966037bd
+
+KEY: 05affcdfce0a28539924370db8d80a78b835254778ec41acbff52bfab092fa33
+NONCE: 3edaeb185f7273b1a7cccba54f84c5f7d6583433b49d3694
+IN: 7657581faad266cc1037962a380c8aa5306f88000427d0a05397696b503790ad2643c6
+AD: d7c213e9e6f4a40f3e5b662c
+CT: 5eb19080aadc89f2329da4f5c41dc60568651c424c1b05d827f2bfb8dbff42c5a08224
+TAG: 2da20087b5674f0b967d1baa664bbd82
+
+KEY: 645ed60ec74ddfe1f02694792db4436c262d20405d8645cd9755d64876219799
+NONCE: d83665b44c1fdf567299f2b8501e9c0e7ae2dda0bb8f2c82
+IN: ceee69d32ad4667a00909964d9611bf34fd98be41ad7f0feaaaff8169060d64cf310c13bcb9394cf
+AD: 57379f8f44191ec9cf3b1a07
+CT: 4496a0666f0f895ebce224b448a04502f2ae7b354d868b7c54295bf051162e82c530c767d1ffd2cc
+TAG: 1ffc56da4fb961ffdfabe66d82ec8f29
+
+KEY: 06624c9a75bb7dbe224a3f23791281f53c40b407a14161a3f82f34924623dc02
+NONCE: e647b8b4739bf542a81d72d695e1cd6ba348fa593987ac47
+IN: 2658763f8d70e8c3303582d66ba3d736ce9d407e9507f6c6627e382d0144da157d73d0aee10ef034083cdd9013
+AD: 75536443a6c2189a57d553bb
+CT: 305cab5c2f9a6edccac307d6965febe3c86f2a1e31ac8c74e88924a10c2a29106bce980c803b7886985bba8ec5
+TAG: 8c12bb58c84175b9f601b704d0f8a25c
+
+KEY: 63aeb46083100bbcc430f4f09bcc34410df9cfd5883d629e4af8645ffabb89c2
+NONCE: b09830874dc549195a5d6da93b9dcc12aa1ec8af201c96bd
+IN: 1b3c9050e0a062f5a5cff7bec8706864cf8648142ec5cb1f9867ace384e9b2bba33aab8dc83e83b2d2fac70cd5189f2b5ab5
+AD: 7dcc05b0940198bd5c68cdf1
+CT: d8b22e5d381de08a50b163c00dbbca6c07d61c80199cebd52234c7bd4f7ed0a90d47ef05617cdb8e3f782875ae629c0f0ad6
+TAG: 194077f0e6d415bf7307d171e8484a9c
+
+KEY: 4826c1bf8b48088fece4008922173c500ff45790f945b1027f36110da4fecc92
+NONCE: 3a78fc7397944d762303b0a75974ac92a60e250bf112600a
+IN: d26e3a2b92120ff8056bb992660cc8a2364792589c16a518b8d232b8184aed05ba8d4fd0b2ad2b928cd873e11905a21ffece5f1e63c974
+AD: 904d2cd3e50f7bfb9352f142
+CT: 21f4cf679662fad36f57945fc0c0753c3791261eb58d643278dfe1f14bfb585c5a01370ba96f18dc3f6b6945a2c6997330b24f12f5219a
+TAG: 95397c54428f9d069c511b5c82e0151c
+
+KEY: ec526c03d8a08e8a63751112428a76399c399e8b83d98c9247c73164805ac8fe
+NONCE: 2cc1a6ae89c2a091415fa2964b44a0e5da629d40d77b77f1
+IN: 567377f5b6df5442e70bc9a31bc450bd4febfcf89d7ca611353c7e612d8b7e36e859f6365ec7e5e99e9e0e882532666dd7203d06f6e25439ed871237
+AD: 35575b56716868b66cd21e24
+CT: 6b738274fe974438f1f5fca8ef1ee7df664f1e72bc54ccd3fb58c4a3df67ef9a73261df41ffe9c52aeafc8be4f6524baf9efb1558d4a57defec7bee3
+TAG: 92599d4b14a795e8c375ec2a8960b4dc
+
diff --git a/include/openssl/aead.h b/include/openssl/aead.h
index 620855e..af31554 100644
--- a/include/openssl/aead.h
+++ b/include/openssl/aead.h
@@ -112,6 +112,10 @@
 // Poly1305 as described in RFC 7539.
 OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305(void);
 
+// EVP_aead_xchacha20_poly1305 is ChaCha20-Poly1305 with an extended nonce that
+// makes random generation of nonces safe.
+OPENSSL_EXPORT const EVP_AEAD *EVP_aead_xchacha20_poly1305(void);
+
 // EVP_aead_aes_128_ctr_hmac_sha256 is AES-128 in CTR mode with HMAC-SHA256 for
 // authentication. The nonce is 12 bytes; the bottom 32-bits are used as the
 // block counter, thus the maximum plaintext size is 64GB.
@@ -184,7 +188,7 @@
 
 // EVP_AEAD_MAX_NONCE_LENGTH contains the maximum nonce length used by
 // any AEAD defined in this header.
-#define EVP_AEAD_MAX_NONCE_LENGTH 16
+#define EVP_AEAD_MAX_NONCE_LENGTH 24
 
 // EVP_AEAD_MAX_OVERHEAD contains the maximum overhead used by any AEAD
 // defined in this header.
diff --git a/sources.cmake b/sources.cmake
index f0c953b..94edcb3 100644
--- a/sources.cmake
+++ b/sources.cmake
@@ -22,6 +22,7 @@
   crypto/cipher_extra/test/aes_256_gcm_siv_tests.txt
   crypto/cipher_extra/test/aes_256_gcm_tests.txt
   crypto/cipher_extra/test/chacha20_poly1305_tests.txt
+  crypto/cipher_extra/test/xchacha20_poly1305_tests.txt
   crypto/cipher_extra/test/cipher_tests.txt
   crypto/cipher_extra/test/des_ede3_cbc_sha1_tls_implicit_iv_tests.txt
   crypto/cipher_extra/test/des_ede3_cbc_sha1_tls_tests.txt