Add generic AES-GCM-SIV support.

AES-GCM-SIV is an AEAD with nonce-misuse resistance. It can reuse
hardware support for AES-GCM and thus encrypt at ~66% the speed, and
decrypt at 100% the speed, of AES-GCM.

See https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02

This implementation is generic, not optimised, and reuses existing AES
and GHASH support as much as possible. It is guarded by !OPENSSL_SMALL,
at least for now.

Change-Id: Ia9f77b256ef5dfb8588bb9ecfe6ee0e827626f57
Reviewed-on: https://boringssl-review.googlesource.com/12541
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/cipher/aead_test.cc b/crypto/cipher/aead_test.cc
index b33a36d..8dbc8a2 100644
--- a/crypto/cipher/aead_test.cc
+++ b/crypto/cipher/aead_test.cc
@@ -23,6 +23,16 @@
 
 #include "../test/file_test.h"
 
+
+#if defined(OPENSSL_SMALL)
+const EVP_AEAD* EVP_aead_aes_128_gcm_siv(void) {
+  return nullptr;
+}
+const EVP_AEAD* EVP_aead_aes_256_gcm_siv(void) {
+  return nullptr;
+}
+#endif
+
 namespace bssl {
 
 // This program tests an AEAD against a series of test vectors from a file,
@@ -302,6 +312,8 @@
 static const struct KnownAEAD kAEADs[] = {
   { "aes-128-gcm", EVP_aead_aes_128_gcm, false },
   { "aes-256-gcm", EVP_aead_aes_256_gcm, false },
+  { "aes-128-gcm-siv", EVP_aead_aes_128_gcm_siv, false },
+  { "aes-256-gcm-siv", EVP_aead_aes_256_gcm_siv, false },
   { "chacha20-poly1305", EVP_aead_chacha20_poly1305, false },
   { "chacha20-poly1305-old", EVP_aead_chacha20_poly1305_old, false },
   { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls, true },
@@ -342,6 +354,11 @@
   }
 
   const EVP_AEAD *const aead = known_aead->func();
+  if (aead == NULL) {
+    // AEAD is not compiled in this configuration.
+    printf("PASS\n");
+    return 0;
+  }
 
   if (!TestCleanupAfterInitFailure(aead)) {
     return 1;
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
index 9225d6a..f99022f 100644
--- a/crypto/cipher/e_aes.c
+++ b/crypto/cipher/e_aes.c
@@ -1446,6 +1446,305 @@
   return &aead_aes_256_ctr_hmac_sha256;
 }
 
+#if !defined(OPENSSL_SMALL)
+
+#define EVP_AEAD_AES_GCM_SIV_TAG_LEN 16
+
+struct aead_aes_gcm_siv_ctx {
+  union {
+    double align;
+    AES_KEY ks;
+  } ks;
+  block128_f kgk_block;
+  unsigned is_256:1;
+};
+
+static int aead_aes_gcm_siv_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
+                                 size_t key_len, size_t tag_len) {
+  const size_t key_bits = key_len * 8;
+
+  if (key_bits != 128 && key_bits != 256) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
+    return 0; /* EVP_AEAD_CTX_init should catch this. */
+  }
+
+  if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) {
+    tag_len = EVP_AEAD_AES_GCM_SIV_TAG_LEN;
+  }
+
+  if (tag_len != EVP_AEAD_AES_GCM_SIV_TAG_LEN) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE);
+    return 0;
+  }
+
+  struct aead_aes_gcm_siv_ctx *gcm_siv_ctx =
+      OPENSSL_malloc(sizeof(struct aead_aes_gcm_siv_ctx));
+  if (gcm_siv_ctx == NULL) {
+    return 0;
+  }
+  memset(gcm_siv_ctx, 0, sizeof(struct aead_aes_gcm_siv_ctx));
+
+  if (aesni_capable()) {
+    aesni_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks);
+    gcm_siv_ctx->kgk_block = (block128_f)aesni_encrypt;
+  } else if (hwaes_capable()) {
+    aes_hw_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks);
+    gcm_siv_ctx->kgk_block = (block128_f)aes_hw_encrypt;
+  } else if (vpaes_capable()) {
+    vpaes_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks);
+    gcm_siv_ctx->kgk_block = (block128_f)vpaes_encrypt;
+  } else {
+    AES_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks);
+    gcm_siv_ctx->kgk_block = (block128_f)AES_encrypt;
+  }
+
+  gcm_siv_ctx->is_256 = (key_len == 32);
+  ctx->aead_state = gcm_siv_ctx;
+
+  return 1;
+}
+
+static void aead_aes_gcm_siv_cleanup(EVP_AEAD_CTX *ctx) {
+  struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state;
+  OPENSSL_cleanse(gcm_siv_ctx, sizeof(struct aead_aes_gcm_siv_ctx));
+  OPENSSL_free(gcm_siv_ctx);
+}
+
+/* gcm_siv_crypt encrypts (or decrypts—it's the same thing) |in_len| bytes from
+ * |in| to |out|, using the block function |enc_block| with |key| in counter
+ * mode, starting at |initial_counter|. This differs from the traditional
+ * counter mode code in that the counter is handled little-endian, only the
+ * first four bytes are used and the GCM-SIV tweak to the final byte is
+ * applied. The |in| and |out| pointers may be equal but otherwise must not
+ * alias. */
+static void gcm_siv_crypt(uint8_t *out, const uint8_t *in, size_t in_len,
+                          const uint8_t initial_counter[AES_BLOCK_SIZE],
+                          block128_f enc_block, const AES_KEY *key) {
+  union {
+    uint32_t w[4];
+    uint8_t c[16];
+  } counter;
+
+  memcpy(counter.c, initial_counter, AES_BLOCK_SIZE);
+  counter.c[15] |= 0x80;
+
+  for (size_t done = 0; done < in_len;) {
+    uint8_t keystream[AES_BLOCK_SIZE];
+    enc_block(counter.c, keystream, key);
+    counter.w[0]++;
+
+    size_t todo = AES_BLOCK_SIZE;
+    if (in_len - done < todo) {
+      todo = in_len - done;
+    }
+
+    for (size_t i = 0; i < todo; i++) {
+      out[done + i] = keystream[i] ^ in[done + i];
+    }
+
+    done += todo;
+  }
+}
+
+/* gcm_siv_polyval evaluates POLYVAL at |auth_key| on the given plaintext and
+ * AD. The result is written to |out_tag|. */
+static void gcm_siv_polyval(uint8_t out_tag[16], const uint8_t *in,
+                            size_t in_len, const uint8_t *ad, size_t ad_len,
+                            const uint8_t auth_key[16]) {
+  struct polyval_ctx polyval_ctx;
+  CRYPTO_POLYVAL_init(&polyval_ctx, auth_key);
+
+  CRYPTO_POLYVAL_update_blocks(&polyval_ctx, ad, ad_len & ~15);
+
+  uint8_t scratch[16];
+  if (ad_len & 15) {
+    memset(scratch, 0, sizeof(scratch));
+    memcpy(scratch, &ad[ad_len & ~15], ad_len & 15);
+    CRYPTO_POLYVAL_update_blocks(&polyval_ctx, scratch, sizeof(scratch));
+  }
+
+  CRYPTO_POLYVAL_update_blocks(&polyval_ctx, in, in_len & ~15);
+  if (in_len & 15) {
+    memset(scratch, 0, sizeof(scratch));
+    memcpy(scratch, &in[in_len & ~15], in_len & 15);
+    CRYPTO_POLYVAL_update_blocks(&polyval_ctx, scratch, sizeof(scratch));
+  }
+
+  union {
+    uint8_t c[16];
+    struct {
+      uint64_t ad;
+      uint64_t in;
+    } bitlens;
+  } length_block;
+
+  length_block.bitlens.ad = ad_len * 8;
+  length_block.bitlens.in = in_len * 8;
+  CRYPTO_POLYVAL_update_blocks(&polyval_ctx, length_block.c,
+                               sizeof(length_block));
+
+  CRYPTO_POLYVAL_finish(&polyval_ctx, out_tag);
+  out_tag[15] &= 0x7f;
+}
+
+/* gcm_siv_record_keys contains the keys used for a specific GCM-SIV record. */
+struct gcm_siv_record_keys {
+  uint8_t auth_key[16];
+  union {
+    double align;
+    AES_KEY ks;
+  } enc_key;
+  block128_f enc_block;
+};
+
+/* gcm_siv_keys calculates the keys for a specific GCM-SIV record with the
+ * given nonce and writes them to |*out_keys|. */
+static void gcm_siv_keys(
+    const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx,
+    struct gcm_siv_record_keys *out_keys,
+    const uint8_t nonce[EVP_AEAD_AES_GCM_SIV_TAG_LEN]) {
+  const AES_KEY *const key = &gcm_siv_ctx->ks.ks;
+  gcm_siv_ctx->kgk_block(nonce, out_keys->auth_key, key);
+
+  if (gcm_siv_ctx->is_256) {
+    uint8_t record_enc_key[32];
+    gcm_siv_ctx->kgk_block(out_keys->auth_key, record_enc_key + 16, key);
+    gcm_siv_ctx->kgk_block(record_enc_key + 16, record_enc_key, key);
+    aes_ctr_set_key(&out_keys->enc_key.ks, NULL, &out_keys->enc_block,
+                    record_enc_key, sizeof(record_enc_key));
+  } else {
+    uint8_t record_enc_key[16];
+    gcm_siv_ctx->kgk_block(out_keys->auth_key, record_enc_key, key);
+    aes_ctr_set_key(&out_keys->enc_key.ks, NULL, &out_keys->enc_block,
+                    record_enc_key, sizeof(record_enc_key));
+  }
+}
+
+static int aead_aes_gcm_siv_seal(const EVP_AEAD_CTX *ctx, uint8_t *out,
+                                 size_t *out_len, size_t max_out_len,
+                                 const uint8_t *nonce, size_t nonce_len,
+                                 const uint8_t *in, size_t in_len,
+                                 const uint8_t *ad, size_t ad_len) {
+  const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state;
+  const uint64_t in_len_64 = in_len;
+  const uint64_t ad_len_64 = ad_len;
+
+  if (in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN < in_len ||
+      in_len_64 > (UINT64_C(1) << 36) ||
+      ad_len_64 >= (UINT64_C(1) << 61)) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
+    return 0;
+  }
+
+  if (max_out_len < in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+
+  if (nonce_len != AES_BLOCK_SIZE) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
+    return 0;
+  }
+
+  struct gcm_siv_record_keys keys;
+  gcm_siv_keys(gcm_siv_ctx, &keys, nonce);
+
+  uint8_t tag[16];
+  gcm_siv_polyval(tag, in, in_len, ad, ad_len, keys.auth_key);
+  keys.enc_block(tag, tag, &keys.enc_key.ks);
+
+  gcm_siv_crypt(out, in, in_len, tag, keys.enc_block, &keys.enc_key.ks);
+
+  memcpy(&out[in_len], tag, EVP_AEAD_AES_GCM_SIV_TAG_LEN);
+  *out_len = in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN;
+
+  return 1;
+}
+
+static int aead_aes_gcm_siv_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
+                                 size_t *out_len, size_t max_out_len,
+                                 const uint8_t *nonce, size_t nonce_len,
+                                 const uint8_t *in, size_t in_len,
+                                 const uint8_t *ad, size_t ad_len) {
+  const uint64_t ad_len_64 = ad_len;
+  if (ad_len_64 >= (UINT64_C(1) << 61)) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
+    return 0;
+  }
+
+  const uint64_t in_len_64 = in_len;
+  if (in_len < EVP_AEAD_AES_GCM_SIV_TAG_LEN ||
+      in_len_64 > (UINT64_C(1) << 36) + AES_BLOCK_SIZE) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
+    return 0;
+  }
+
+  const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state;
+  const size_t plaintext_len = in_len - EVP_AEAD_AES_GCM_SIV_TAG_LEN;
+
+  if (max_out_len < plaintext_len) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
+    return 0;
+  }
+
+  struct gcm_siv_record_keys keys;
+  gcm_siv_keys(gcm_siv_ctx, &keys, nonce);
+
+  gcm_siv_crypt(out, in, plaintext_len, &in[plaintext_len], keys.enc_block,
+                &keys.enc_key.ks);
+
+  uint8_t expected_tag[EVP_AEAD_AES_GCM_SIV_TAG_LEN];
+  gcm_siv_polyval(expected_tag, out, plaintext_len, ad, ad_len, keys.auth_key);
+  keys.enc_block(expected_tag, expected_tag, &keys.enc_key.ks);
+
+  if (CRYPTO_memcmp(expected_tag, &in[plaintext_len], sizeof(expected_tag)) !=
+      0) {
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
+    return 0;
+  }
+
+  *out_len = plaintext_len;
+  return 1;
+}
+
+static const EVP_AEAD aead_aes_128_gcm_siv = {
+    16,                           /* key length */
+    AES_BLOCK_SIZE,               /* nonce length */
+    EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* overhead */
+    EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* max tag length */
+
+    aead_aes_gcm_siv_init,
+    NULL /* init_with_direction */,
+    aead_aes_gcm_siv_cleanup,
+    aead_aes_gcm_siv_seal,
+    aead_aes_gcm_siv_open,
+    NULL /* get_iv */,
+};
+
+static const EVP_AEAD aead_aes_256_gcm_siv = {
+    32,                           /* key length */
+    AES_BLOCK_SIZE,               /* nonce length */
+    EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* overhead */
+    EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* max tag length */
+
+    aead_aes_gcm_siv_init,
+    NULL /* init_with_direction */,
+    aead_aes_gcm_siv_cleanup,
+    aead_aes_gcm_siv_seal,
+    aead_aes_gcm_siv_open,
+    NULL /* get_iv */,
+};
+
+const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void) {
+  return &aead_aes_128_gcm_siv;
+}
+
+const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void) {
+  return &aead_aes_256_gcm_siv;
+}
+
+#endif  /* !OPENSSL_SMALL */
+
 int EVP_has_aes_hardware(void) {
 #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
   return aesni_capable() && crypto_gcm_clmul_enabled();
diff --git a/crypto/cipher/test/aes_128_gcm_siv_tests.txt b/crypto/cipher/test/aes_128_gcm_siv_tests.txt
new file mode 100644
index 0000000..a929b59
--- /dev/null
+++ b/crypto/cipher/test/aes_128_gcm_siv_tests.txt
@@ -0,0 +1,236 @@
+# This is the example from
+# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#section-8
+
+KEY: ee8e1ed9ff2540ae8f2ba9f50bc2f27c
+NONCE: 752abad3e0afb5f434dc4310f71f3d21
+IN: "Hello world"
+AD: "example"
+CT: 810649724764545b3625ff
+TAG: 010a10f4942710781d2948ac0192572f
+
+# Test vectors from
+# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-B
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 
+AD: 
+CT: 
+TAG: cb52de357fad226ae428d0ed5a575496
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0100000000000000
+AD: 
+CT: 7e139f58002d68ee
+TAG: 715835541f2136f03b6dc80ae0a8ac46
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 010000000000000000000000
+AD: 
+CT: 4a87f0cd26e5d5086e90da02
+TAG: 4dff905e48d512e9c34ae8f3be66ec43
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 01000000000000000000000000000000
+AD: 
+CT: 048ca58c46d2368ce00132389f40b511
+TAG: 971da9aa385283522c4f67a9aedb37e5
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0100000000000000000000000000000002000000000000000000000000000000
+AD: 
+CT: e1cf1cf545d2743ec005b26bd2c836ac1a4233d646c195ffa401f28063127baa
+TAG: 1071338b8c2930d3ec4c17cecbefa4b4
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000
+AD: 
+CT: 2e7e6881a02d57b877794b2fbfbfef5484f1cf74f4ad53a751b2582c0e698466bd9a49dcab53806d8e31d864c4632d00
+TAG: 04b1b8a9c1630ff028b14d2e57bca429
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 
+CT: 0ac5be860726209d9218de3e9d533743e1efe1595bc58f93f00e9bb9a7558dc1e1b14a9c0d49eb5064c7efa79842f9c7cfdd77614709f0b545d3227498e774d5
+TAG: 860b73a1ed8a5b9acd925c3f3f49c5c5
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0200000000000000
+AD: 01
+CT: 4919e29e9890e452
+TAG: 1433a5c0284c911163888dbd128e6874
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 020000000000000000000000
+AD: 01
+CT: db55d6da719fe0473538294e
+TAG: 5a8ab948ccd205a70c78e8fdf954693b
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000000000000000000000000000
+AD: 01
+CT: aea3c54272abc1b58ed34a536743f4da
+TAG: da10d98bfe23784cfdfd0af97b6d5b78
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0200000000000000000000000000000003000000000000000000000000000000
+AD: 01
+CT: aa694c0cfe148100cb5c6e27a77a7ff7b4233d6af251d9faa3d84f7c0d1113f1
+TAG: 778c5b68356a1a6a6f3c14a8f96c35ca
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 01
+CT: 9ac909928bcde79c2afa885df9c035c85a9eab136f6f6ea11034456bd306ea3c5dd542f706fffe538b5f139fa9dc622e
+TAG: 26c0c0d146d38787ca0fcbc3f911577a
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000
+AD: 01
+CT: c56be9d61ecf6a31a6289cddc9b91aaf84cdb53a3913b825d6eb5e157906dfb0a308c6b0b095d6fd1a5b761ca7fa0e39ca92f38ae206eec844c0c4ab0c1c165e
+TAG: a60986309b99431a35dd8c5ebeef8375
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000
+AD: 010000000000000000000000
+CT: 47995b96
+TAG: 16b668094202cadde992e0c16205793c
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0300000000000000000000000000000004000000
+AD: 010000000000000000000000000000000200
+CT: 8fe25de75089e9f849150e57ab7f7810981cd319
+TAG: 89ca91ebc560709432fe9496746404cc
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 030000000000000000000000000000000400
+AD: 0100000000000000000000000000000002000000
+CT: b26d43ae158316ac37f41579ccf1d461274e
+TAG: 13b7c01d08dd6969d51d1bf0fbbdc4d2
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 
+AD: 
+CT: 
+TAG: cb52de357fad226ae428d0ed5a575496
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0100000000000000
+AD: 
+CT: 7e139f58002d68ee
+TAG: 715835541f2136f03b6dc80ae0a8ac46
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 010000000000000000000000
+AD: 
+CT: 4a87f0cd26e5d5086e90da02
+TAG: 4dff905e48d512e9c34ae8f3be66ec43
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 01000000000000000000000000000000
+AD: 
+CT: 048ca58c46d2368ce00132389f40b511
+TAG: 971da9aa385283522c4f67a9aedb37e5
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0100000000000000000000000000000002000000000000000000000000000000
+AD: 
+CT: e1cf1cf545d2743ec005b26bd2c836ac1a4233d646c195ffa401f28063127baa
+TAG: 1071338b8c2930d3ec4c17cecbefa4b4
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000
+AD: 
+CT: 2e7e6881a02d57b877794b2fbfbfef5484f1cf74f4ad53a751b2582c0e698466bd9a49dcab53806d8e31d864c4632d00
+TAG: 04b1b8a9c1630ff028b14d2e57bca429
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 
+CT: 0ac5be860726209d9218de3e9d533743e1efe1595bc58f93f00e9bb9a7558dc1e1b14a9c0d49eb5064c7efa79842f9c7cfdd77614709f0b545d3227498e774d5
+TAG: 860b73a1ed8a5b9acd925c3f3f49c5c5
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0200000000000000
+AD: 01
+CT: 4919e29e9890e452
+TAG: 1433a5c0284c911163888dbd128e6874
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 020000000000000000000000
+AD: 01
+CT: db55d6da719fe0473538294e
+TAG: 5a8ab948ccd205a70c78e8fdf954693b
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000000000000000000000000000
+AD: 01
+CT: aea3c54272abc1b58ed34a536743f4da
+TAG: da10d98bfe23784cfdfd0af97b6d5b78
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0200000000000000000000000000000003000000000000000000000000000000
+AD: 01
+CT: aa694c0cfe148100cb5c6e27a77a7ff7b4233d6af251d9faa3d84f7c0d1113f1
+TAG: 778c5b68356a1a6a6f3c14a8f96c35ca
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 01
+CT: 9ac909928bcde79c2afa885df9c035c85a9eab136f6f6ea11034456bd306ea3c5dd542f706fffe538b5f139fa9dc622e
+TAG: 26c0c0d146d38787ca0fcbc3f911577a
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000
+AD: 01
+CT: c56be9d61ecf6a31a6289cddc9b91aaf84cdb53a3913b825d6eb5e157906dfb0a308c6b0b095d6fd1a5b761ca7fa0e39ca92f38ae206eec844c0c4ab0c1c165e
+TAG: a60986309b99431a35dd8c5ebeef8375
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000
+AD: 010000000000000000000000
+CT: 47995b96
+TAG: 16b668094202cadde992e0c16205793c
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0300000000000000000000000000000004000000
+AD: 010000000000000000000000000000000200
+CT: 8fe25de75089e9f849150e57ab7f7810981cd319
+TAG: 89ca91ebc560709432fe9496746404cc
+
+KEY: 01000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 030000000000000000000000000000000400
+AD: 0100000000000000000000000000000002000000
+CT: b26d43ae158316ac37f41579ccf1d461274e
+TAG: 13b7c01d08dd6969d51d1bf0fbbdc4d2
diff --git a/crypto/cipher/test/aes_256_gcm_siv_tests.txt b/crypto/cipher/test/aes_256_gcm_siv_tests.txt
new file mode 100644
index 0000000..cd38e23
--- /dev/null
+++ b/crypto/cipher/test/aes_256_gcm_siv_tests.txt
@@ -0,0 +1,226 @@
+# Test vectors from
+# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-B
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 
+AD: 
+CT: 
+TAG: eb7ccf36eeff369241379c87cc08e4f0
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0100000000000000
+AD: 
+CT: ab3f382a6f0fb4c3
+TAG: a0a69e07b73281f5cdfd034f646cfa08
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 010000000000000000000000
+AD: 
+CT: be8d81f033ca23b953da2197
+TAG: cdf3ba70da9c7cbd45f5140ba0cca9f1
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 01000000000000000000000000000000
+AD: 
+CT: 46e05b7116dbe27aaeffe99892194072
+TAG: be19d78991c62130cf97f628c37c3eaa
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0100000000000000000000000000000002000000000000000000000000000000
+AD: 
+CT: 23ddbe9ef342b03003f56d6b4a2e8aff035c7d7cfd705e1ab4502904254bb67a
+TAG: 16c5944034050657af7c0fec7efbc40f
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000
+AD: 
+CT: b104c8945f280e75b52c05c45a63d1872c7f0552b1501968d9913d71207d0433f978f1a3eecdf782016b77e8c9d3ff53
+TAG: abedb4841c20f3b05e61e0fd1fcaf3d0
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 
+CT: e3f2bd14f4c80c9cea4c90c81f0e4d7eedb87eb19a7c0cf5a5a95cd3e441a71083b1191d115e9a9ff008b93feeb5a86d012a3e0adb89de2d1e3225479022292f
+TAG: 3ced67f5e03bb476a738c1343926dc19
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0200000000000000
+AD: 01
+CT: 4dca2c16c3b0413c
+TAG: ac9b952c76a6f8b5df315f88126daa1c
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 020000000000000000000000
+AD: 01
+CT: ee0ca9068b5b85dfe115a660
+TAG: 756d6155927271077d790a05390ecb71
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000000000000000000000000000
+AD: 01
+CT: 590edb785c0cb89d19f031fa7e7d4f91
+TAG: ac2c8f711c86dbecc8c7b663c5fbc1ea
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0200000000000000000000000000000003000000000000000000000000000000
+AD: 01
+CT: dcf2024f5f98d463b82a8673c47dd82159748cac8bcc7c76b8cfa26029cb333c
+TAG: a9b406643e190e602fb104fbb842a1ac
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 01
+CT: 79216506b1ddadfe16366e4ec886d10dc9400b995259f74c0091f9b5a6add5680a612130f6c31ab833aa76d9b2be86de
+TAG: 3ddfe9ad2c350980942638d3f954ac6d
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000
+AD: 01
+CT: 9535eb67240c49f30a0de5a90670813fa615e71fcb4c522ca79d9a33459a22f8c6a56d650bf0b15eecdd706e7689cf6510a281724613fea76b5366b40574b1b9
+TAG: abcb59ee31d25ee8889b70d7c36f9a41
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000
+AD: 010000000000000000000000
+CT: 9611baa0
+TAG: 53daf2bc5916f7a6750f2432068dabee
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0300000000000000000000000000000004000000
+AD: 010000000000000000000000000000000200
+CT: 78e3a1b54daa6547f775f30c38a45e887aea5c87
+TAG: f65187d8c28adba364d659b627b16431
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 030000000000000000000000000000000400
+AD: 0100000000000000000000000000000002000000
+CT: c6d3d28704bf20067d62e1a3872d40dda44b
+TAG: 6ac0135a4379dbc67967ff55fd4d1f2f
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 
+AD: 
+CT: 
+TAG: eb7ccf36eeff369241379c87cc08e4f0
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0100000000000000
+AD: 
+CT: ab3f382a6f0fb4c3
+TAG: a0a69e07b73281f5cdfd034f646cfa08
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 010000000000000000000000
+AD: 
+CT: be8d81f033ca23b953da2197
+TAG: cdf3ba70da9c7cbd45f5140ba0cca9f1
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 01000000000000000000000000000000
+AD: 
+CT: 46e05b7116dbe27aaeffe99892194072
+TAG: be19d78991c62130cf97f628c37c3eaa
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0100000000000000000000000000000002000000000000000000000000000000
+AD: 
+CT: 23ddbe9ef342b03003f56d6b4a2e8aff035c7d7cfd705e1ab4502904254bb67a
+TAG: 16c5944034050657af7c0fec7efbc40f
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000
+AD: 
+CT: b104c8945f280e75b52c05c45a63d1872c7f0552b1501968d9913d71207d0433f978f1a3eecdf782016b77e8c9d3ff53
+TAG: abedb4841c20f3b05e61e0fd1fcaf3d0
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 
+CT: e3f2bd14f4c80c9cea4c90c81f0e4d7eedb87eb19a7c0cf5a5a95cd3e441a71083b1191d115e9a9ff008b93feeb5a86d012a3e0adb89de2d1e3225479022292f
+TAG: 3ced67f5e03bb476a738c1343926dc19
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0200000000000000
+AD: 01
+CT: 4dca2c16c3b0413c
+TAG: ac9b952c76a6f8b5df315f88126daa1c
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 020000000000000000000000
+AD: 01
+CT: ee0ca9068b5b85dfe115a660
+TAG: 756d6155927271077d790a05390ecb71
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000000000000000000000000000
+AD: 01
+CT: 590edb785c0cb89d19f031fa7e7d4f91
+TAG: ac2c8f711c86dbecc8c7b663c5fbc1ea
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0200000000000000000000000000000003000000000000000000000000000000
+AD: 01
+CT: dcf2024f5f98d463b82a8673c47dd82159748cac8bcc7c76b8cfa26029cb333c
+TAG: a9b406643e190e602fb104fbb842a1ac
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+AD: 01
+CT: 79216506b1ddadfe16366e4ec886d10dc9400b995259f74c0091f9b5a6add5680a612130f6c31ab833aa76d9b2be86de
+TAG: 3ddfe9ad2c350980942638d3f954ac6d
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000
+AD: 01
+CT: 9535eb67240c49f30a0de5a90670813fa615e71fcb4c522ca79d9a33459a22f8c6a56d650bf0b15eecdd706e7689cf6510a281724613fea76b5366b40574b1b9
+TAG: abcb59ee31d25ee8889b70d7c36f9a41
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 02000000
+AD: 010000000000000000000000
+CT: 9611baa0
+TAG: 53daf2bc5916f7a6750f2432068dabee
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 0300000000000000000000000000000004000000
+AD: 010000000000000000000000000000000200
+CT: 78e3a1b54daa6547f775f30c38a45e887aea5c87
+TAG: f65187d8c28adba364d659b627b16431
+
+KEY: 0100000000000000000000000000000000000000000000000000000000000000
+NONCE: 03000000000000000000000000000000
+IN: 030000000000000000000000000000000400
+AD: 0100000000000000000000000000000002000000
+CT: c6d3d28704bf20067d62e1a3872d40dda44b
+TAG: 6ac0135a4379dbc67967ff55fd4d1f2f
diff --git a/crypto/modes/CMakeLists.txt b/crypto/modes/CMakeLists.txt
index 17faa15..dc9e504 100644
--- a/crypto/modes/CMakeLists.txt
+++ b/crypto/modes/CMakeLists.txt
@@ -48,10 +48,11 @@
   OBJECT
 
   cbc.c
-  ctr.c
-  ofb.c
   cfb.c
+  ctr.c
   gcm.c
+  ofb.c
+  polyval.c
 
   ${MODES_ARCH_SOURCES}
 )
diff --git a/crypto/modes/internal.h b/crypto/modes/internal.h
index 64232c4..a53da04 100644
--- a/crypto/modes/internal.h
+++ b/crypto/modes/internal.h
@@ -189,6 +189,12 @@
                                  uint8_t ecount_buf[16], unsigned *num,
                                  ctr128_f ctr);
 
+#if !defined(OPENSSL_NO_ASM) && \
+    (defined(OPENSSL_X86) || defined(OPENSSL_X86_64))
+void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks,
+                                const void *key, const uint8_t *ivec);
+#endif
+
 
 /* GCM.
  *
@@ -328,11 +334,36 @@
                                    block128_f block);
 
 
-#if !defined(OPENSSL_NO_ASM) && \
-    (defined(OPENSSL_X86) || defined(OPENSSL_X86_64))
-void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks,
-                                const void *key, const uint8_t *ivec);
-#endif
+/* POLYVAL.
+ *
+ * POLYVAL is a polynomial authenticator that operates over a field very
+ * similar to the one that GHASH uses. See
+ * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#section-3. */
+
+typedef union {
+  uint64_t u[2];
+  uint8_t c[16];
+} polyval_block;
+
+struct polyval_ctx {
+  polyval_block S;
+  u128 Htable[16];
+  gmult_func gmult;
+  ghash_func ghash;
+};
+
+/* CRYPTO_POLYVAL_init initialises |ctx| using |key|. */
+void CRYPTO_POLYVAL_init(struct polyval_ctx *ctx, const uint8_t key[16]);
+
+/* CRYPTO_POLYVAL_update_blocks updates the accumulator in |ctx| given the
+ * blocks from |in|. Only a whole number of blocks can be processed so |in_len|
+ * must be a multiple of 16. */
+void CRYPTO_POLYVAL_update_blocks(struct polyval_ctx *ctx, const uint8_t *in,
+                                  size_t in_len);
+
+/* CRYPTO_POLYVAL_finish writes the accumulator from |ctx| to |out|. */
+void CRYPTO_POLYVAL_finish(const struct polyval_ctx *ctx, uint8_t out[16]);
+
 
 #if defined(__cplusplus)
 } /* extern C */
diff --git a/crypto/modes/polyval.c b/crypto/modes/polyval.c
new file mode 100644
index 0000000..c5121a1
--- /dev/null
+++ b/crypto/modes/polyval.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2016, 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. */
+
+#include <openssl/base.h>
+
+#if !defined(OPENSSL_SMALL)
+
+#include <assert.h>
+#include <string.h>
+
+#include "internal.h"
+#include "../internal.h"
+
+
+/* byte_reverse reverses the order of the bytes in |b->c|. */
+static void byte_reverse(polyval_block *b) {
+  const uint64_t t = CRYPTO_bswap8(b->u[0]);
+  b->u[0] = CRYPTO_bswap8(b->u[1]);
+  b->u[1] = t;
+}
+
+/* reverse_and_mulX_ghash interprets the bytes |b->c| as a reversed element of
+ * the GHASH field, multiplies that by 'x' and serialises the result back into
+ * |b|, but with GHASH's backwards bit ordering. */
+static void reverse_and_mulX_ghash(polyval_block *b) {
+  uint64_t hi = b->u[0];
+  uint64_t lo = b->u[1];
+  const unsigned carry = constant_time_eq(hi & 1, 1);
+  hi >>= 1;
+  hi |= lo << 63;
+  lo >>= 1;
+  lo ^= ((uint64_t) constant_time_select(carry, 0xe1, 0)) << 56;
+
+  b->u[0] = CRYPTO_bswap8(lo);
+  b->u[1] = CRYPTO_bswap8(hi);
+}
+
+/* POLYVAL(H, X_1, ..., X_n) =
+ * ByteReverse(GHASH(mulX_GHASH(ByteReverse(H)), ByteReverse(X_1), ...,
+ * ByteReverse(X_n))).
+ *
+ * See https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-A. */
+
+void CRYPTO_POLYVAL_init(struct polyval_ctx *ctx, const uint8_t key[16]) {
+  polyval_block H;
+  memcpy(H.c, key, 16);
+  reverse_and_mulX_ghash(&H);
+
+  CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, ctx->Htable, H.c);
+  memset(&ctx->S, 0, sizeof(ctx->S));
+}
+
+void CRYPTO_POLYVAL_update_blocks(struct polyval_ctx *ctx, const uint8_t *in,
+                                  size_t in_len) {
+  assert((in_len & 15) == 0);
+  polyval_block reversed[32];
+
+  while (in_len > 0) {
+    size_t todo = in_len;
+    if (todo > sizeof(reversed)) {
+      todo = sizeof(reversed);
+    }
+    memcpy(reversed, in, todo);
+    in_len -= todo;
+
+    size_t blocks = todo / sizeof(polyval_block);
+    for (size_t i = 0; i < blocks; i++) {
+      byte_reverse(&reversed[i]);
+    }
+
+    ctx->ghash(ctx->S.u, ctx->Htable, (const uint8_t *) reversed, todo);
+  }
+}
+
+void CRYPTO_POLYVAL_finish(const struct polyval_ctx *ctx, uint8_t out[16]) {
+  polyval_block S = ctx->S;
+  byte_reverse(&S);
+  memcpy(out, &S.c, sizeof(polyval_block));
+}
+
+
+#endif  /* !OPENSSL_SMALL */
diff --git a/include/openssl/aead.h b/include/openssl/aead.h
index fff0e49..eaa2b8f 100644
--- a/include/openssl/aead.h
+++ b/include/openssl/aead.h
@@ -114,6 +114,14 @@
  * authentication. See |EVP_aead_aes_128_ctr_hmac_sha256| for details. */
 OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void);
 
+/* EVP_aead_aes_128_gcm_siv is AES-128 in GCM-SIV mode. See
+ * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 */
+OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void);
+
+/* EVP_aead_aes_256_gcm_siv is AES-256 in GCM-SIV mode. See
+ * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 */
+OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void);
+
 /* EVP_has_aes_hardware returns one if we enable hardware support for fast and
  * constant-time AES-GCM. */
 OPENSSL_EXPORT int EVP_has_aes_hardware(void);
diff --git a/tool/speed.cc b/tool/speed.cc
index f16a9eb..5fd1058 100644
--- a/tool/speed.cc
+++ b/tool/speed.cc
@@ -654,6 +654,12 @@
                  kLegacyADLen, selected) ||
       !SpeedAEAD(EVP_aead_aes_256_cbc_sha1_tls(), "AES-256-CBC-SHA1",
                  kLegacyADLen, selected) ||
+#if !defined(OPENSSL_SMALL)
+      !SpeedAEAD(EVP_aead_aes_128_gcm_siv(), "AES-128-GCM-SIV", kTLSADLen,
+                 selected) ||
+      !SpeedAEAD(EVP_aead_aes_256_gcm_siv(), "AES-256-GCM-SIV", kTLSADLen,
+                 selected) ||
+#endif
       !SpeedHash(EVP_sha1(), "SHA-1", selected) ||
       !SpeedHash(EVP_sha256(), "SHA-256", selected) ||
       !SpeedHash(EVP_sha512(), "SHA-512", selected) ||
diff --git a/util/all_tests.json b/util/all_tests.json
index d2e39ce..5ffa5e8 100644
--- a/util/all_tests.json
+++ b/util/all_tests.json
@@ -8,6 +8,8 @@
 	["crypto/chacha/chacha_test"],
 	["crypto/cipher/aead_test", "aes-128-gcm", "crypto/cipher/test/aes_128_gcm_tests.txt"],
 	["crypto/cipher/aead_test", "aes-256-gcm", "crypto/cipher/test/aes_256_gcm_tests.txt"],
+	["crypto/cipher/aead_test", "aes-128-gcm-siv", "crypto/cipher/test/aes_128_gcm_siv_tests.txt"],
+	["crypto/cipher/aead_test", "aes-256-gcm-siv", "crypto/cipher/test/aes_256_gcm_siv_tests.txt"],
 	["crypto/cipher/aead_test", "chacha20-poly1305", "crypto/cipher/test/chacha20_poly1305_tests.txt"],
 	["crypto/cipher/aead_test", "chacha20-poly1305-old", "crypto/cipher/test/chacha20_poly1305_old_tests.txt"],
 	["crypto/cipher/aead_test", "aes-128-cbc-sha1-tls", "crypto/cipher/test/aes_128_cbc_sha1_tls_tests.txt"],