Convert a number of tests to GTest.

BUG=129

Change-Id: Ifcdacb2f5f59fd03b757f88778ceb1e672208fd9
Reviewed-on: https://boringssl-review.googlesource.com/16744
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/CMakeLists.txt b/crypto/CMakeLists.txt
index f402caf..28b6c3a 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -108,7 +108,6 @@
 add_subdirectory(ec_extra)
 add_subdirectory(ecdh)
 add_subdirectory(ecdsa_extra)
-add_subdirectory(hmac_extra)
 
 # Level 3
 add_subdirectory(cmac)
@@ -232,13 +231,15 @@
   bio/bio_test.cc
   bytestring/bytestring_test.cc
   chacha/chacha_test.cc
-  cipher_extra/aead_extra_test.cc
+  cipher_extra/aead_test.cc
+  cipher_extra/cipher_test.cc
   cmac/cmac_test.cc
   compiler_test.cc
   constant_time_test.cc
   curve25519/ed25519_test.cc
   curve25519/spake25519_test.cc
   curve25519/x25519_test.cc
+  ecdh/ecdh_test.cc
   dh/dh_test.cc
   digest_extra/digest_test.cc
   dsa/dsa_test.cc
@@ -247,9 +248,12 @@
   evp/pbkdf_test.cc
   fipsmodule/aes/aes_test.cc
   fipsmodule/ec/ec_test.cc
+  fipsmodule/modes/gcm_test.cc
   fipsmodule/rand/ctrdrbg_test.cc
   hkdf/hkdf_test.cc
+  hmac_extra/hmac_test.cc
   lhash/lhash_test.cc
+  poly1305/poly1305_test.cc
   pool/pool_test.cc
   refcount_test.cc
   rsa_extra/rsa_test.cc
diff --git a/crypto/cipher_extra/CMakeLists.txt b/crypto/cipher_extra/CMakeLists.txt
index 698161c..8af3630 100644
--- a/crypto/cipher_extra/CMakeLists.txt
+++ b/crypto/cipher_extra/CMakeLists.txt
@@ -31,23 +31,5 @@
   ${CIPHER_ARCH_SOURCES}
 )
 
-add_executable(
-  cipher_test
-
-  cipher_test.cc
-  $<TARGET_OBJECTS:test_support>
-)
-
-add_executable(
-  aead_test
-
-  aead_test.cc
-  $<TARGET_OBJECTS:test_support>
-)
-
 perlasm(aes128gcmsiv-x86_64.${ASM_EXT} asm/aes128gcmsiv-x86_64.pl)
 perlasm(chacha20_poly1305_x86_64.${ASM_EXT} asm/chacha20_poly1305_x86_64.pl)
-
-target_link_libraries(cipher_test crypto)
-target_link_libraries(aead_test crypto)
-add_dependencies(all_tests cipher_test aead_test)
diff --git a/crypto/cipher_extra/aead_extra_test.cc b/crypto/cipher_extra/aead_extra_test.cc
deleted file mode 100644
index 073b3d6..0000000
--- a/crypto/cipher_extra/aead_extra_test.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-/* Copyright (c) 2017, 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 <gtest/gtest.h>
-
-#include <openssl/aead.h>
-#include <openssl/cipher.h>
-#include <openssl/err.h>
-
-
-// Test that EVP_aead_aes_128_gcm and EVP_aead_aes_256_gcm reject empty nonces.
-// AES-GCM is not defined for those.
-//
-// TODO(davidben): Fold this into aead_test.cc, once it is converted to GTest.
-TEST(AEADTest, AESGCMEmptyNonce) {
-  static const uint8_t kZeros[32] = {0};
-
-  // Test AES-128-GCM.
-  uint8_t buf[16];
-  size_t len;
-  bssl::ScopedEVP_AEAD_CTX ctx;
-  ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_128_gcm(), kZeros, 16,
-                                EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
-
-  EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf),
-                                 nullptr /* nonce */, 0, nullptr /* in */, 0,
-                                 nullptr /* ad */, 0));
-  uint32_t err = ERR_get_error();
-  EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
-  EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
-
-  EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf),
-                                 nullptr /* nonce */, 0, kZeros /* in */,
-                                 sizeof(kZeros), nullptr /* ad */, 0));
-  err = ERR_get_error();
-  EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
-  EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
-
-  // Test AES-256-GCM.
-  ctx.Reset();
-  ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_256_gcm(), kZeros, 32,
-                                EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
-
-  EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf),
-                                 nullptr /* nonce */, 0, nullptr /* in */, 0,
-                                 nullptr /* ad */, 0));
-  err = ERR_get_error();
-  EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
-  EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
-
-  EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf),
-                                 nullptr /* nonce */, 0, kZeros /* in */,
-                                 sizeof(kZeros), nullptr /* ad */, 0));
-  err = ERR_get_error();
-  EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
-  EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
-}
diff --git a/crypto/cipher_extra/aead_test.cc b/crypto/cipher_extra/aead_test.cc
index 2edbe83..24702ce 100644
--- a/crypto/cipher_extra/aead_test.cc
+++ b/crypto/cipher_extra/aead_test.cc
@@ -12,31 +12,95 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
-#include <assert.h>
 #include <stdint.h>
 #include <string.h>
 
 #include <vector>
 
+#include <gtest/gtest.h>
+
 #include <openssl/aead.h>
-#include <openssl/crypto.h>
+#include <openssl/cipher.h>
 #include <openssl/err.h>
 
 #include "../internal.h"
 #include "../test/file_test.h"
+#include "../test/test_util.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;
-}
+struct KnownAEAD {
+  const char name[40];
+  const EVP_AEAD *(*func)(void);
+  const char *test_vectors;
+  // limited_implementation indicates that tests that assume a generic AEAD
+  // interface should not be performed. For example, the key-wrap AEADs only
+  // handle inputs that are a multiple of eight bytes in length and the
+  // SSLv3/TLS AEADs have the concept of “direction”.
+  bool limited_implementation;
+  // truncated_tags is true if the AEAD supports truncating tags to arbitrary
+  // lengths.
+  bool truncated_tags;
+};
+
+static const struct KnownAEAD kAEADs[] = {
+    {"AES_128_GCM", EVP_aead_aes_128_gcm, "aes_128_gcm_tests.txt", false, true},
+    {"AES_128_GCM_NIST", EVP_aead_aes_128_gcm, "nist_cavp/aes_128_gcm.txt",
+     false, true},
+    {"AES_256_GCM", EVP_aead_aes_256_gcm, "aes_256_gcm_tests.txt", false, true},
+    {"AES_256_GCM_NIST", EVP_aead_aes_256_gcm, "nist_cavp/aes_256_gcm.txt",
+     false, true},
+#if !defined(OPENSSL_SMALL)
+    {"AES_128_GCM_SIV", EVP_aead_aes_128_gcm_siv, "aes_128_gcm_siv_tests.txt",
+     false, false},
+    {"AES_256_GCM_SIV", EVP_aead_aes_256_gcm_siv, "aes_256_gcm_siv_tests.txt",
+     false, false},
 #endif
+    {"ChaCha20Poly1305", EVP_aead_chacha20_poly1305,
+     "chacha20_poly1305_tests.txt", false, true},
+    {"AES_128_CBC_SHA1_TLS", EVP_aead_aes_128_cbc_sha1_tls,
+     "aes_128_cbc_sha1_tls_tests.txt", true, false},
+    {"AES_128_CBC_SHA1_TLSImplicitIV",
+     EVP_aead_aes_128_cbc_sha1_tls_implicit_iv,
+     "aes_128_cbc_sha1_tls_implicit_iv_tests.txt", true, false},
+    {"AES_128_CBC_SHA256_TLS", EVP_aead_aes_128_cbc_sha256_tls,
+     "aes_128_cbc_sha256_tls_tests.txt", true, false},
+    {"AES_256_CBC_SHA1_TLS", EVP_aead_aes_256_cbc_sha1_tls,
+     "aes_256_cbc_sha1_tls_tests.txt", true, false},
+    {"AES_256_CBC_SHA1_TLSImplicitIV",
+     EVP_aead_aes_256_cbc_sha1_tls_implicit_iv,
+     "aes_256_cbc_sha1_tls_implicit_iv_tests.txt", true, false},
+    {"AES_256_CBC_SHA256_TLS", EVP_aead_aes_256_cbc_sha256_tls,
+     "aes_256_cbc_sha256_tls_tests.txt", true, false},
+    {"AES_256_CBC_SHA384_TLS", EVP_aead_aes_256_cbc_sha384_tls,
+     "aes_256_cbc_sha384_tls_tests.txt", true, false},
+    {"DES_EDE3_CBC_SHA1_TLS", EVP_aead_des_ede3_cbc_sha1_tls,
+     "des_ede3_cbc_sha1_tls_tests.txt", true, false},
+    {"DES_EDE3_CBC_SHA1_TLSImplicitIV",
+     EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv,
+     "des_ede3_cbc_sha1_tls_implicit_iv_tests.txt", true, false},
+    {"AES_128_CBC_SHA1_SSL3", EVP_aead_aes_128_cbc_sha1_ssl3,
+     "aes_128_cbc_sha1_ssl3_tests.txt", true, false},
+    {"AES_256_CBC_SHA1_SSL3", EVP_aead_aes_256_cbc_sha1_ssl3,
+     "aes_256_cbc_sha1_ssl3_tests.txt", true, false},
+    {"DES_EDE3_CBC_SHA1_SSL3", EVP_aead_des_ede3_cbc_sha1_ssl3,
+     "des_ede3_cbc_sha1_ssl3_tests.txt", true, false},
+    {"AES_128_CTR_HMAC_SHA256", EVP_aead_aes_128_ctr_hmac_sha256,
+     "aes_128_ctr_hmac_sha256.txt", false, true},
+    {"AES_256_CTR_HMAC_SHA256", EVP_aead_aes_256_ctr_hmac_sha256,
+     "aes_256_ctr_hmac_sha256.txt", false, true},
+};
 
-// This program tests an AEAD against a series of test vectors from a file,
-// using the FileTest format. As an example, here's a valid test case:
+class PerAEADTest : public testing::TestWithParam<KnownAEAD> {
+ public:
+  const EVP_AEAD *aead() { return GetParam().func(); }
+};
+
+INSTANTIATE_TEST_CASE_P(, PerAEADTest, testing::ValuesIn(kAEADs),
+                        [](const testing::TestParamInfo<KnownAEAD> &params)
+                            -> std::string { return params.param.name; });
+
+// Tests an AEAD against a series of test vectors from a file, using the
+// FileTest format. As an example, here's a valid test case:
 //
 //   KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4
 //   NONCE: 978105dfce667bf4
@@ -44,177 +108,134 @@
 //   AD: b654574932
 //   CT: 5294265a60
 //   TAG: 1d45758621762e061368e68868e2f929
+TEST_P(PerAEADTest, TestVector) {
+  std::string test_vectors = "crypto/cipher_extra/test/";
+  test_vectors += GetParam().test_vectors;
+  FileTestGTest(test_vectors.c_str(), [&](FileTest *t) {
+    std::vector<uint8_t> key, nonce, in, ad, ct, tag;
+    ASSERT_TRUE(t->GetBytes(&key, "KEY"));
+    ASSERT_TRUE(t->GetBytes(&nonce, "NONCE"));
+    ASSERT_TRUE(t->GetBytes(&in, "IN"));
+    ASSERT_TRUE(t->GetBytes(&ad, "AD"));
+    ASSERT_TRUE(t->GetBytes(&ct, "CT"));
+    ASSERT_TRUE(t->GetBytes(&tag, "TAG"));
 
-static bool TestAEAD(FileTest *t, void *arg) {
-  const EVP_AEAD *aead = reinterpret_cast<const EVP_AEAD*>(arg);
+    bssl::ScopedEVP_AEAD_CTX ctx;
+    ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
+        ctx.get(), aead(), key.data(), key.size(), tag.size(), evp_aead_seal));
 
-  std::vector<uint8_t> key, nonce, in, ad, ct, tag;
-  if (!t->GetBytes(&key, "KEY") ||
-      !t->GetBytes(&nonce, "NONCE") ||
-      !t->GetBytes(&in, "IN") ||
-      !t->GetBytes(&ad, "AD") ||
-      !t->GetBytes(&ct, "CT") ||
-      !t->GetBytes(&tag, "TAG")) {
-    return false;
-  }
+    std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead()));
+    if (!t->HasAttribute("NO_SEAL")) {
+      size_t out_len;
+      ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
+                                    nonce.data(), nonce.size(), in.data(),
+                                    in.size(), ad.data(), ad.size()));
+      out.resize(out_len);
 
-  bssl::ScopedEVP_AEAD_CTX ctx;
-  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(),
-                                        tag.size(), evp_aead_seal)) {
-    t->PrintLine("Failed to init AEAD.");
-    return false;
-  }
-
-  std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead));
-  if (!t->HasAttribute("NO_SEAL")) {
-    size_t out_len;
-    if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
-                           nonce.data(), nonce.size(), in.data(), in.size(),
-                           ad.data(), ad.size())) {
-      t->PrintLine("Failed to run AEAD.");
-      return false;
+      ASSERT_EQ(out.size(), ct.size() + tag.size());
+      EXPECT_EQ(Bytes(ct), Bytes(out.data(), ct.size()));
+      EXPECT_EQ(Bytes(tag), Bytes(out.data() + ct.size(), tag.size()));
+    } else {
+      out.resize(ct.size() + tag.size());
+      OPENSSL_memcpy(out.data(), ct.data(), ct.size());
+      OPENSSL_memcpy(out.data() + ct.size(), tag.data(), tag.size());
     }
-    out.resize(out_len);
 
-    if (out.size() != ct.size() + tag.size()) {
-      t->PrintLine("Bad output length: %u vs %u.", (unsigned)out_len,
-                   (unsigned)(ct.size() + tag.size()));
-      return false;
-    }
-    if (!t->ExpectBytesEqual(ct.data(), ct.size(), out.data(), ct.size()) ||
-        !t->ExpectBytesEqual(tag.data(), tag.size(), out.data() + ct.size(),
-                             tag.size())) {
-      return false;
-    }
-  } else {
-    out.resize(ct.size() + tag.size());
-    OPENSSL_memcpy(out.data(), ct.data(), ct.size());
-    OPENSSL_memcpy(out.data() + ct.size(), tag.data(), tag.size());
-  }
+    // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
+    // reset after each operation.
+    ctx.Reset();
+    ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
+        ctx.get(), aead(), key.data(), key.size(), tag.size(), evp_aead_open));
 
-  // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
-  // reset after each operation.
-  ctx.Reset();
-  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(),
-                                        tag.size(), evp_aead_open)) {
-    t->PrintLine("Failed to init AEAD.");
-    return false;
-  }
-
-  std::vector<uint8_t> out2(out.size());
-  size_t out2_len;
-  int ret = EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(),
-                              nonce.data(), nonce.size(), out.data(),
-                              out.size(), ad.data(), ad.size());
-  if (t->HasAttribute("FAILS")) {
-    if (ret) {
-      t->PrintLine("Decrypted bad data.");
-      return false;
+    std::vector<uint8_t> out2(out.size());
+    size_t out2_len;
+    int ret = EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(),
+                                nonce.data(), nonce.size(), out.data(),
+                                out.size(), ad.data(), ad.size());
+    if (t->HasAttribute("FAILS")) {
+      ASSERT_FALSE(ret) << "Decrypted bad data.";
+      ERR_clear_error();
+      return;
     }
+
+    ASSERT_TRUE(ret) << "Failed to decrypt.";
+    out2.resize(out2_len);
+    EXPECT_EQ(Bytes(in), Bytes(out2));
+
+    // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
+    // reset after each operation.
+    ctx.Reset();
+    ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
+        ctx.get(), aead(), key.data(), key.size(), tag.size(), evp_aead_open));
+
+    // Garbage at the end isn't ignored.
+    out.push_back(0);
+    out2.resize(out.size());
+    EXPECT_FALSE(EVP_AEAD_CTX_open(
+        ctx.get(), out2.data(), &out2_len, out2.size(), nonce.data(),
+        nonce.size(), out.data(), out.size(), ad.data(), ad.size()))
+        << "Decrypted bad data with trailing garbage.";
     ERR_clear_error();
-    return true;
-  }
 
-  if (!ret) {
-    t->PrintLine("Failed to decrypt.");
-    return false;
-  }
-  out2.resize(out2_len);
-  if (!t->ExpectBytesEqual(in.data(), in.size(), out2.data(), out2.size())) {
-    return false;
-  }
+    // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
+    // reset after each operation.
+    ctx.Reset();
+    ASSERT_TRUE(EVP_AEAD_CTX_init_with_direction(
+        ctx.get(), aead(), key.data(), key.size(), tag.size(), evp_aead_open));
 
-  // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
-  // reset after each operation.
-  ctx.Reset();
-  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(),
-                                        tag.size(), evp_aead_open)) {
-    t->PrintLine("Failed to init AEAD.");
-    return false;
-  }
-
-  // Garbage at the end isn't ignored.
-  out.push_back(0);
-  out2.resize(out.size());
-  if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(),
-                        nonce.data(), nonce.size(), out.data(), out.size(),
-                        ad.data(), ad.size())) {
-    t->PrintLine("Decrypted bad data with trailing garbage.");
-    return false;
-  }
-  ERR_clear_error();
-
-  // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
-  // reset after each operation.
-  ctx.Reset();
-  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(),
-                                        tag.size(), evp_aead_open)) {
-    t->PrintLine("Failed to init AEAD.");
-    return false;
-  }
-
-  // Verify integrity is checked.
-  out[0] ^= 0x80;
-  out.resize(out.size() - 1);
-  out2.resize(out.size());
-  if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(),
-                        nonce.data(), nonce.size(), out.data(), out.size(),
-                        ad.data(), ad.size())) {
-    t->PrintLine("Decrypted bad data with corrupted byte.");
-    return false;
-  }
-  ERR_clear_error();
-
-  return true;
+    // Verify integrity is checked.
+    out[0] ^= 0x80;
+    out.resize(out.size() - 1);
+    out2.resize(out.size());
+    EXPECT_FALSE(EVP_AEAD_CTX_open(
+        ctx.get(), out2.data(), &out2_len, out2.size(), nonce.data(),
+        nonce.size(), out.data(), out.size(), ad.data(), ad.size()))
+        << "Decrypted bad data with corrupted byte.";
+    ERR_clear_error();
+  });
 }
 
-static int TestCleanupAfterInitFailure(const EVP_AEAD *aead) {
+TEST_P(PerAEADTest, CleanupAfterInitFailure) {
   uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
   OPENSSL_memset(key, 0, sizeof(key));
-  const size_t key_len = EVP_AEAD_key_length(aead);
-  assert(sizeof(key) >= key_len);
+  const size_t key_len = EVP_AEAD_key_length(aead());
+  ASSERT_GE(sizeof(key), key_len);
 
   EVP_AEAD_CTX ctx;
-  if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len,
-                        9999 /* a silly tag length to trigger an error */,
-                        NULL /* ENGINE */) != 0) {
-    fprintf(stderr, "A silly tag length didn't trigger an error!\n");
-    return 0;
-  }
+  ASSERT_FALSE(EVP_AEAD_CTX_init(
+      &ctx, aead(), key, key_len,
+      9999 /* a silly tag length to trigger an error */, NULL /* ENGINE */));
   ERR_clear_error();
 
   /* Running a second, failed _init should not cause a memory leak. */
-  if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len,
-                        9999 /* a silly tag length to trigger an error */,
-                        NULL /* ENGINE */) != 0) {
-    fprintf(stderr, "A silly tag length didn't trigger an error!\n");
-    return 0;
-  }
+  ASSERT_FALSE(EVP_AEAD_CTX_init(
+      &ctx, aead(), key, key_len,
+      9999 /* a silly tag length to trigger an error */, NULL /* ENGINE */));
   ERR_clear_error();
 
   /* Calling _cleanup on an |EVP_AEAD_CTX| after a failed _init should be a
    * no-op. */
   EVP_AEAD_CTX_cleanup(&ctx);
-  return 1;
 }
 
-static int TestTruncatedTags(const EVP_AEAD *aead) {
+TEST_P(PerAEADTest, TruncatedTags) {
+  if (!GetParam().truncated_tags) {
+    return;
+  }
+
   uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
   OPENSSL_memset(key, 0, sizeof(key));
-  const size_t key_len = EVP_AEAD_key_length(aead);
-  assert(sizeof(key) >= key_len);
+  const size_t key_len = EVP_AEAD_key_length(aead());
+  ASSERT_GE(sizeof(key), key_len);
 
   uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
   OPENSSL_memset(nonce, 0, sizeof(nonce));
-  const size_t nonce_len = EVP_AEAD_nonce_length(aead);
-  assert(sizeof(nonce) >= nonce_len);
+  const size_t nonce_len = EVP_AEAD_nonce_length(aead());
+  ASSERT_GE(sizeof(nonce), nonce_len);
 
   bssl::ScopedEVP_AEAD_CTX ctx;
-  if (!EVP_AEAD_CTX_init(ctx.get(), aead, key, key_len, 1 /* one byte tag */,
-                         NULL /* ENGINE */)) {
-    fprintf(stderr, "Couldn't initialise AEAD with truncated tag.\n");
-    return 1;
-  }
+  ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key, key_len,
+                                1 /* one byte tag */, NULL /* ENGINE */));
 
   const uint8_t plaintext[1] = {'A'};
 
@@ -223,68 +244,53 @@
   constexpr uint8_t kSentinel = 42;
   OPENSSL_memset(ciphertext, kSentinel, sizeof(ciphertext));
 
-  if (!EVP_AEAD_CTX_seal(ctx.get(), ciphertext, &ciphertext_len,
-                         sizeof(ciphertext), nonce, nonce_len, plaintext,
-                         sizeof(plaintext), nullptr /* ad */, 0)) {
-    fprintf(stderr, "Sealing with truncated tag didn't work.\n");
-    return 0;
-  }
+  ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), ciphertext, &ciphertext_len,
+                                sizeof(ciphertext), nonce, nonce_len, plaintext,
+                                sizeof(plaintext), nullptr /* ad */, 0));
 
   for (size_t i = ciphertext_len; i < sizeof(ciphertext); i++) {
     // Sealing must not write past where it said it did.
-    if (ciphertext[i] != kSentinel) {
-      fprintf(stderr, "Sealing wrote off the end of the buffer.\n");
-      return 0;
-    }
+    EXPECT_EQ(kSentinel, ciphertext[i])
+        << "Sealing wrote off the end of the buffer.";
   }
 
   const size_t overhead_used = ciphertext_len - sizeof(plaintext);
   const size_t expected_overhead =
-      1 + EVP_AEAD_max_overhead(aead) - EVP_AEAD_max_tag_len(aead);
-  if (overhead_used != expected_overhead) {
-    fprintf(stderr, "AEAD is probably ignoring request to truncate tags.\n");
-    return 0;
-  }
+      1 + EVP_AEAD_max_overhead(aead()) - EVP_AEAD_max_tag_len(aead());
+  EXPECT_EQ(overhead_used, expected_overhead)
+      << "AEAD is probably ignoring request to truncate tags.";
 
   uint8_t plaintext2[sizeof(plaintext) + 16];
   OPENSSL_memset(plaintext2, kSentinel, sizeof(plaintext2));
 
   size_t plaintext2_len;
-  if (!EVP_AEAD_CTX_open(ctx.get(), plaintext2, &plaintext2_len,
-                         sizeof(plaintext2), nonce, nonce_len, ciphertext,
-                         ciphertext_len, nullptr /* ad */, 0)) {
-    fprintf(stderr, "Opening with truncated tag didn't work.\n");
-    return 0;
-  }
+  ASSERT_TRUE(EVP_AEAD_CTX_open(
+      ctx.get(), plaintext2, &plaintext2_len, sizeof(plaintext2), nonce,
+      nonce_len, ciphertext, ciphertext_len, nullptr /* ad */, 0))
+      << "Opening with truncated tag didn't work.";
 
   for (size_t i = plaintext2_len; i < sizeof(plaintext2); i++) {
     // Likewise, opening should also stay within bounds.
-    if (plaintext2[i] != kSentinel) {
-      fprintf(stderr, "Opening wrote off the end of the buffer.\n");
-      return 0;
-    }
+    EXPECT_EQ(kSentinel, plaintext2[i])
+        << "Opening wrote off the end of the buffer.";
   }
 
-  if (plaintext2_len != sizeof(plaintext) ||
-      OPENSSL_memcmp(plaintext2, plaintext, sizeof(plaintext)) != 0) {
-    fprintf(stderr, "Opening with truncated tag gave wrong result.\n");
-    return 0;
-  }
-
-  return 1;
+  EXPECT_EQ(Bytes(plaintext), Bytes(plaintext2, plaintext2_len));
 }
 
-static bool TestWithAliasedBuffers(const EVP_AEAD *aead) {
-  const size_t key_len = EVP_AEAD_key_length(aead);
-  const size_t nonce_len = EVP_AEAD_nonce_length(aead);
-  const size_t max_overhead = EVP_AEAD_max_overhead(aead);
+TEST_P(PerAEADTest, AliasedBuffers) {
+  if (GetParam().limited_implementation) {
+    return;
+  }
+
+  const size_t key_len = EVP_AEAD_key_length(aead());
+  const size_t nonce_len = EVP_AEAD_nonce_length(aead());
+  const size_t max_overhead = EVP_AEAD_max_overhead(aead());
 
   std::vector<uint8_t> key(key_len, 'a');
   bssl::ScopedEVP_AEAD_CTX ctx;
-  if (!EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key_len,
-                         EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) {
-    return false;
-  }
+  ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead(), key.data(), key_len,
+                                EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
 
   static const uint8_t kPlaintext[260] =
       "testing123456testing123456testing123456testing123456testing123456testing"
@@ -299,13 +305,11 @@
   std::vector<uint8_t> nonce(nonce_len, 'b');
   std::vector<uint8_t> valid_encryption(sizeof(kPlaintext) + max_overhead);
   size_t valid_encryption_len;
-  if (!EVP_AEAD_CTX_seal(
-          ctx.get(), valid_encryption.data(), &valid_encryption_len,
-          sizeof(kPlaintext) + max_overhead, nonce.data(), nonce_len,
-          kPlaintext, sizeof(kPlaintext), nullptr, 0)) {
-    fprintf(stderr, "EVP_AEAD_CTX_seal failed with disjoint buffers.\n");
-    return false;
-  }
+  ASSERT_TRUE(EVP_AEAD_CTX_seal(
+      ctx.get(), valid_encryption.data(), &valid_encryption_len,
+      sizeof(kPlaintext) + max_overhead, nonce.data(), nonce_len, kPlaintext,
+      sizeof(kPlaintext), nullptr, 0))
+      << "EVP_AEAD_CTX_seal failed with disjoint buffers.";
 
   // Test with out != in which we expect to fail.
   std::vector<uint8_t> buffer(2 + valid_encryption_len);
@@ -315,138 +319,81 @@
 
   OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext));
   size_t out_len;
-  if (EVP_AEAD_CTX_seal(ctx.get(), out1, &out_len,
-                        sizeof(kPlaintext) + max_overhead, nonce.data(),
-                        nonce_len, in, sizeof(kPlaintext), nullptr, 0) ||
-      EVP_AEAD_CTX_seal(ctx.get(), out2, &out_len,
-                        sizeof(kPlaintext) + max_overhead, nonce.data(),
-                        nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
-    fprintf(stderr, "EVP_AEAD_CTX_seal unexpectedly succeeded.\n");
-    return false;
-  }
+  EXPECT_FALSE(EVP_AEAD_CTX_seal(
+      ctx.get(), out1 /* in - 1 */, &out_len, sizeof(kPlaintext) + max_overhead,
+      nonce.data(), nonce_len, in, sizeof(kPlaintext), nullptr, 0));
+  EXPECT_FALSE(EVP_AEAD_CTX_seal(
+      ctx.get(), out2 /* in + 1 */, &out_len, sizeof(kPlaintext) + max_overhead,
+      nonce.data(), nonce_len, in, sizeof(kPlaintext), nullptr, 0));
   ERR_clear_error();
 
   OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len);
-  if (EVP_AEAD_CTX_open(ctx.get(), out1, &out_len, valid_encryption_len,
-                        nonce.data(), nonce_len, in, valid_encryption_len,
-                        nullptr, 0) ||
-      EVP_AEAD_CTX_open(ctx.get(), out2, &out_len, valid_encryption_len,
-                        nonce.data(), nonce_len, in, valid_encryption_len,
-                        nullptr, 0)) {
-    fprintf(stderr, "EVP_AEAD_CTX_open unexpectedly succeeded.\n");
-    return false;
-  }
+  EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out1 /* in - 1 */, &out_len,
+                                 valid_encryption_len, nonce.data(), nonce_len,
+                                 in, valid_encryption_len, nullptr, 0));
+  EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out2 /* in + 1 */, &out_len,
+                                 valid_encryption_len, nonce.data(), nonce_len,
+                                 in, valid_encryption_len, nullptr, 0));
   ERR_clear_error();
 
   // Test with out == in, which we expect to work.
   OPENSSL_memcpy(in, kPlaintext, sizeof(kPlaintext));
 
-  if (!EVP_AEAD_CTX_seal(ctx.get(), in, &out_len,
-                         sizeof(kPlaintext) + max_overhead, nonce.data(),
-                         nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
-    fprintf(stderr, "EVP_AEAD_CTX_seal failed in-place.\n");
-    return false;
-  }
-
-  if (out_len != valid_encryption_len ||
-      OPENSSL_memcmp(in, valid_encryption.data(), out_len) != 0) {
-    fprintf(stderr, "EVP_AEAD_CTX_seal produced bad output in-place.\n");
-    return false;
-  }
+  ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), in, &out_len,
+                                sizeof(kPlaintext) + max_overhead, nonce.data(),
+                                nonce_len, in, sizeof(kPlaintext), nullptr, 0));
+  EXPECT_EQ(Bytes(valid_encryption.data(), valid_encryption_len),
+            Bytes(in, out_len));
 
   OPENSSL_memcpy(in, valid_encryption.data(), valid_encryption_len);
-  if (!EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len,
-                         nonce.data(), nonce_len, in, valid_encryption_len,
-                         nullptr, 0)) {
-    fprintf(stderr, "EVP_AEAD_CTX_open failed in-place.\n");
-    return false;
-  }
-
-  if (out_len != sizeof(kPlaintext) ||
-      OPENSSL_memcmp(in, kPlaintext, out_len) != 0) {
-    fprintf(stderr, "EVP_AEAD_CTX_open produced bad output in-place.\n");
-    return false;
-  }
-
-  return true;
+  ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len,
+                                nonce.data(), nonce_len, in,
+                                valid_encryption_len, nullptr, 0));
+  EXPECT_EQ(Bytes(kPlaintext), Bytes(in, out_len));
 }
 
-struct KnownAEAD {
-  const char name[40];
-  const EVP_AEAD *(*func)(void);
-  // limited_implementation indicates that tests that assume a generic AEAD
-  // interface should not be performed. For example, the key-wrap AEADs only
-  // handle inputs that are a multiple of eight bytes in length and the
-  // SSLv3/TLS AEADs have the concept of “direction”.
-  bool limited_implementation;
-  // truncated_tags is true if the AEAD supports truncating tags to arbitrary
-  // lengths.
-  bool truncated_tags;
-};
+// Test that EVP_aead_aes_128_gcm and EVP_aead_aes_256_gcm reject empty nonces.
+// AES-GCM is not defined for those.
+TEST(AEADTest, AESGCMEmptyNonce) {
+  static const uint8_t kZeros[32] = {0};
 
-static const struct KnownAEAD kAEADs[] = {
-  { "aes-128-gcm", EVP_aead_aes_128_gcm, false, true },
-  { "aes-256-gcm", EVP_aead_aes_256_gcm, false, true },
-  { "aes-128-gcm-siv", EVP_aead_aes_128_gcm_siv, false, false },
-  { "aes-256-gcm-siv", EVP_aead_aes_256_gcm_siv, false, false },
-  { "chacha20-poly1305", EVP_aead_chacha20_poly1305, false, true },
-  { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls, true, false },
-  { "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv, true, false },
-  { "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls, true, false },
-  { "aes-256-cbc-sha1-tls", EVP_aead_aes_256_cbc_sha1_tls, true, false },
-  { "aes-256-cbc-sha1-tls-implicit-iv", EVP_aead_aes_256_cbc_sha1_tls_implicit_iv, true, false },
-  { "aes-256-cbc-sha256-tls", EVP_aead_aes_256_cbc_sha256_tls, true, false },
-  { "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls, true, false },
-  { "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls, true, false },
-  { "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv, true, false },
-  { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3, true, false },
-  { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3, true, false },
-  { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3, true, false },
-  { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256, false, true },
-  { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256, false, true },
-  { "", NULL, false, false },
-};
+  // Test AES-128-GCM.
+  uint8_t buf[16];
+  size_t len;
+  bssl::ScopedEVP_AEAD_CTX ctx;
+  ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_128_gcm(), kZeros, 16,
+                                EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
 
-int main(int argc, char **argv) {
-  CRYPTO_library_init();
+  EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf),
+                                 nullptr /* nonce */, 0, nullptr /* in */, 0,
+                                 nullptr /* ad */, 0));
+  uint32_t err = ERR_get_error();
+  EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
+  EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
 
-  if (argc != 3) {
-    fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]);
-    return 1;
-  }
+  EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf),
+                                 nullptr /* nonce */, 0, kZeros /* in */,
+                                 sizeof(kZeros), nullptr /* ad */, 0));
+  err = ERR_get_error();
+  EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
+  EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
 
-  const struct KnownAEAD *known_aead;
-  for (unsigned i = 0;; i++) {
-    known_aead = &kAEADs[i];
-    if (known_aead->func == NULL) {
-      fprintf(stderr, "Unknown AEAD: %s\n", argv[1]);
-      return 2;
-    }
-    if (strcmp(known_aead->name, argv[1]) == 0) {
-      break;
-    }
-  }
+  // Test AES-256-GCM.
+  ctx.Reset();
+  ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_256_gcm(), kZeros, 32,
+                                EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
 
-  const EVP_AEAD *const aead = known_aead->func();
-  if (aead == NULL) {
-    // AEAD is not compiled in this configuration.
-    printf("PASS\n");
-    return 0;
-  }
+  EXPECT_FALSE(EVP_AEAD_CTX_seal(ctx.get(), buf, &len, sizeof(buf),
+                                 nullptr /* nonce */, 0, nullptr /* in */, 0,
+                                 nullptr /* ad */, 0));
+  err = ERR_get_error();
+  EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
+  EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
 
-  if (!TestCleanupAfterInitFailure(aead)) {
-    return 1;
-  }
-
-  if (known_aead->truncated_tags && !TestTruncatedTags(aead)) {
-    fprintf(stderr, "Truncated tags test failed for %s.\n", known_aead->name);
-    return 1;
-  }
-
-  if (!known_aead->limited_implementation && !TestWithAliasedBuffers(aead)) {
-    fprintf(stderr, "Aliased buffers test failed for %s.\n", known_aead->name);
-    return 1;
-  }
-
-  return FileTestMain(TestAEAD, const_cast<EVP_AEAD*>(aead), argv[2]);
+  EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), buf, &len, sizeof(buf),
+                                 nullptr /* nonce */, 0, kZeros /* in */,
+                                 sizeof(kZeros), nullptr /* ad */, 0));
+  err = ERR_get_error();
+  EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
+  EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
 }
diff --git a/crypto/cipher_extra/cipher_test.cc b/crypto/cipher_extra/cipher_test.cc
index bdfcf23..977243c 100644
--- a/crypto/cipher_extra/cipher_test.cc
+++ b/crypto/cipher_extra/cipher_test.cc
@@ -57,11 +57,13 @@
 #include <string>
 #include <vector>
 
+#include <gtest/gtest.h>
+
 #include <openssl/cipher.h>
-#include <openssl/crypto.h>
 #include <openssl/err.h>
 
 #include "../test/file_test.h"
+#include "../test/test_util.h"
 
 
 static const EVP_CIPHER *GetCipher(const std::string &name) {
@@ -109,11 +111,8 @@
   return nullptr;
 }
 
-static bool TestOperation(FileTest *t,
-                          const EVP_CIPHER *cipher,
-                          bool encrypt,
-                          size_t chunk_size,
-                          const std::vector<uint8_t> &key,
+static void TestOperation(FileTest *t, const EVP_CIPHER *cipher, bool encrypt,
+                          size_t chunk_size, const std::vector<uint8_t> &key,
                           const std::vector<uint8_t> &iv,
                           const std::vector<uint8_t> &plaintext,
                           const std::vector<uint8_t> &ciphertext,
@@ -131,48 +130,36 @@
   bool is_aead = EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE;
 
   bssl::ScopedEVP_CIPHER_CTX ctx;
-  if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr,
-                         encrypt ? 1 : 0)) {
-    return false;
-  }
+  ASSERT_TRUE(EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr,
+                         encrypt ? 1 : 0));
   if (t->HasAttribute("IV")) {
     if (is_aead) {
-      if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN,
-                               iv.size(), 0)) {
-        return false;
-      }
-    } else if (iv.size() != EVP_CIPHER_CTX_iv_length(ctx.get())) {
-      t->PrintLine("Bad IV length.");
-      return false;
+      ASSERT_TRUE(
+          EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv.size(), 0));
+    } else {
+      ASSERT_EQ(iv.size(), EVP_CIPHER_CTX_iv_length(ctx.get()));
     }
   }
-  if (is_aead && !encrypt &&
-      !EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, tag.size(),
-                           const_cast<uint8_t*>(tag.data()))) {
-    return false;
+  if (is_aead && !encrypt) {
+    ASSERT_TRUE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, tag.size(),
+                                    const_cast<uint8_t *>(tag.data())));
   }
   // The ciphers are run with no padding. For each of the ciphers we test, the
   // output size matches the input size.
   std::vector<uint8_t> result(in->size());
-  if (in->size() != out->size()) {
-    t->PrintLine("Input/output size mismatch (%u vs %u).", (unsigned)in->size(),
-                 (unsigned)out->size());
-    return false;
-  }
+  ASSERT_EQ(in->size(), out->size());
+  int unused, result_len1 = 0, result_len2;
+  ASSERT_TRUE(EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size()));
+  ASSERT_TRUE(EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(),
+                                iv.data(), -1));
   // Note: the deprecated |EVP_CIPHER|-based AES-GCM API is sensitive to whether
   // parameters are NULL, so it is important to skip the |in| and |aad|
   // |EVP_CipherUpdate| calls when empty.
-  int unused, result_len1 = 0, result_len2;
-  if (!EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size()) ||
-      !EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(), iv.data(),
-                         -1) ||
-      (!aad.empty() &&
-       !EVP_CipherUpdate(ctx.get(), nullptr, &unused, aad.data(),
-                         aad.size())) ||
-      !EVP_CIPHER_CTX_set_padding(ctx.get(), 0)) {
-    t->PrintLine("Operation failed.");
-    return false;
+  if (!aad.empty()) {
+    ASSERT_TRUE(
+        EVP_CipherUpdate(ctx.get(), nullptr, &unused, aad.data(), aad.size()));
   }
+  ASSERT_TRUE(EVP_CIPHER_CTX_set_padding(ctx.get(), 0));
   if (chunk_size != 0) {
     for (size_t i = 0; i < in->size();) {
       size_t todo = chunk_size;
@@ -181,72 +168,44 @@
       }
 
       int len;
-      if (!EVP_CipherUpdate(ctx.get(), result.data() + result_len1, &len,
-                            in->data() + i, todo)) {
-        t->PrintLine("Operation failed.");
-        return false;
-      }
+      ASSERT_TRUE(EVP_CipherUpdate(ctx.get(), result.data() + result_len1, &len,
+                                   in->data() + i, todo));
       result_len1 += len;
       i += todo;
     }
-  } else if (!in->empty() &&
-             !EVP_CipherUpdate(ctx.get(), result.data(), &result_len1,
-                               in->data(), in->size())) {
-    t->PrintLine("Operation failed.");
-    return false;
+  } else if (!in->empty()) {
+    ASSERT_TRUE(EVP_CipherUpdate(ctx.get(), result.data(), &result_len1,
+                                 in->data(), in->size()));
   }
-  if (!EVP_CipherFinal_ex(ctx.get(), result.data() + result_len1,
-                          &result_len2)) {
-    t->PrintLine("Operation failed.");
-    return false;
-  }
+  ASSERT_TRUE(
+      EVP_CipherFinal_ex(ctx.get(), result.data() + result_len1, &result_len2));
   result.resize(result_len1 + result_len2);
-  if (!t->ExpectBytesEqual(out->data(), out->size(), result.data(),
-                           result.size())) {
-    return false;
-  }
+  EXPECT_EQ(Bytes(*out), Bytes(result));
   if (encrypt && is_aead) {
     uint8_t rtag[16];
-    if (tag.size() > sizeof(rtag)) {
-      t->PrintLine("Bad tag length.");
-      return false;
-    }
-    if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, tag.size(),
-                             rtag) ||
-        !t->ExpectBytesEqual(tag.data(), tag.size(), rtag,
-                             tag.size())) {
-      return false;
-    }
+    ASSERT_LE(tag.size(), sizeof(rtag));
+    ASSERT_TRUE(
+        EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, tag.size(), rtag));
+    EXPECT_EQ(Bytes(tag), Bytes(rtag, tag.size()));
   }
-  return true;
 }
 
-static bool TestCipher(FileTest *t, void *arg) {
+static void TestCipher(FileTest *t) {
   std::string cipher_str;
-  if (!t->GetAttribute(&cipher_str, "Cipher")) {
-    return false;
-  }
+  ASSERT_TRUE(t->GetAttribute(&cipher_str, "Cipher"));
   const EVP_CIPHER *cipher = GetCipher(cipher_str);
-  if (cipher == nullptr) {
-    t->PrintLine("Unknown cipher: '%s'.", cipher_str.c_str());
-    return false;
-  }
+  ASSERT_TRUE(cipher);
 
   std::vector<uint8_t> key, iv, plaintext, ciphertext, aad, tag;
-  if (!t->GetBytes(&key, "Key") ||
-      !t->GetBytes(&plaintext, "Plaintext") ||
-      !t->GetBytes(&ciphertext, "Ciphertext")) {
-    return false;
-  }
-  if (EVP_CIPHER_iv_length(cipher) > 0 &&
-      !t->GetBytes(&iv, "IV")) {
-    return false;
+  ASSERT_TRUE(t->GetBytes(&key, "Key"));
+  ASSERT_TRUE(t->GetBytes(&plaintext, "Plaintext"));
+  ASSERT_TRUE(t->GetBytes(&ciphertext, "Ciphertext"));
+  if (EVP_CIPHER_iv_length(cipher) > 0) {
+    ASSERT_TRUE(t->GetBytes(&iv, "IV"));
   }
   if (EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE) {
-    if (!t->GetBytes(&aad, "AAD") ||
-        !t->GetBytes(&tag, "Tag")) {
-      return false;
-    }
+    ASSERT_TRUE(t->GetBytes(&aad, "AAD"));
+    ASSERT_TRUE(t->GetBytes(&tag, "Tag"));
   }
 
   enum {
@@ -261,8 +220,7 @@
     } else if (str == "DECRYPT") {
       operation = kDecrypt;
     } else {
-      t->PrintLine("Unknown operation: '%s'.", str.c_str());
-      return false;
+      FAIL() << "Unknown operation: " << str;
     }
   }
 
@@ -270,30 +228,60 @@
                                            17, 31, 32, 33, 63, 64, 65, 512};
 
   for (size_t chunk_size : chunk_sizes) {
+    SCOPED_TRACE(chunk_size);
     // By default, both directions are run, unless overridden by the operation.
-    if (operation != kDecrypt &&
-        !TestOperation(t, cipher, true /* encrypt */, chunk_size, key, iv,
-                       plaintext, ciphertext, aad, tag)) {
-      return false;
+    if (operation != kDecrypt) {
+      SCOPED_TRACE("encrypt");
+      TestOperation(t, cipher, true /* encrypt */, chunk_size, key, iv,
+                    plaintext, ciphertext, aad, tag);
     }
 
-    if (operation != kEncrypt &&
-        !TestOperation(t, cipher, false /* decrypt */, chunk_size, key, iv,
-                       plaintext, ciphertext, aad, tag)) {
-      return false;
+    if (operation != kEncrypt) {
+      SCOPED_TRACE("decrypt");
+      TestOperation(t, cipher, false /* decrypt */, chunk_size, key, iv,
+                    plaintext, ciphertext, aad, tag);
     }
   }
-
-  return true;
 }
 
-int main(int argc, char **argv) {
-  CRYPTO_library_init();
+TEST(CipherTest, TestVectors) {
+  FileTestGTest("crypto/cipher_extra/test/cipher_tests.txt", TestCipher);
+}
 
-  if (argc != 2) {
-    fprintf(stderr, "%s <test file>\n", argv[0]);
-    return 1;
-  }
+TEST(CipherTest, CAVP_AES_128_CBC) {
+  FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_128_cbc.txt",
+                TestCipher);
+}
 
-  return FileTestMain(TestCipher, nullptr, argv[1]);
+TEST(CipherTest, CAVP_AES_128_CTR) {
+  FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_128_ctr.txt",
+                TestCipher);
+}
+
+TEST(CipherTest, CAVP_AES_192_CBC) {
+  FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_192_cbc.txt",
+                TestCipher);
+}
+
+TEST(CipherTest, CAVP_AES_192_CTR) {
+  FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_192_ctr.txt",
+                TestCipher);
+}
+
+TEST(CipherTest, CAVP_AES_256_CBC) {
+  FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_256_cbc.txt",
+                TestCipher);
+}
+
+TEST(CipherTest, CAVP_AES_256_CTR) {
+  FileTestGTest("crypto/cipher_extra/test/nist_cavp/aes_256_ctr.txt",
+                TestCipher);
+}
+
+TEST(CipherTest, CAVP_TDES_CBC) {
+  FileTestGTest("crypto/cipher_extra/test/nist_cavp/tdes_cbc.txt", TestCipher);
+}
+
+TEST(CipherTest, CAVP_TDES_ECB) {
+  FileTestGTest("crypto/cipher_extra/test/nist_cavp/tdes_ecb.txt", TestCipher);
 }
diff --git a/crypto/ecdh/CMakeLists.txt b/crypto/ecdh/CMakeLists.txt
index 3d95180..8eaeae5 100644
--- a/crypto/ecdh/CMakeLists.txt
+++ b/crypto/ecdh/CMakeLists.txt
@@ -7,14 +7,3 @@
 
   ecdh.c
 )
-
-add_executable(
-  ecdh_test
-
-  ecdh_test.cc
-
-  $<TARGET_OBJECTS:test_support>
-)
-
-target_link_libraries(ecdh_test crypto)
-add_dependencies(all_tests ecdh_test)
diff --git a/crypto/ecdh/ecdh_test.cc b/crypto/ecdh/ecdh_test.cc
index a02fd22..b311445 100644
--- a/crypto/ecdh/ecdh_test.cc
+++ b/crypto/ecdh/ecdh_test.cc
@@ -16,6 +16,8 @@
 
 #include <vector>
 
+#include <gtest/gtest.h>
+
 #include <openssl/bn.h>
 #include <openssl/crypto.h>
 #include <openssl/ec.h>
@@ -24,6 +26,7 @@
 #include <openssl/nid.h>
 
 #include "../test/file_test.h"
+#include "../test/test_util.h"
 
 
 static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
@@ -59,67 +62,53 @@
   return bssl::UniquePtr<BIGNUM>(BN_bin2bn(bytes.data(), bytes.size(), nullptr));
 }
 
-static bool TestECDH(FileTest *t, void *arg) {
-  bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
-  bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
-  bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
-  bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
-  bssl::UniquePtr<BIGNUM> peer_x = GetBIGNUM(t, "PeerX");
-  bssl::UniquePtr<BIGNUM> peer_y = GetBIGNUM(t, "PeerY");
-  std::vector<uint8_t> z;
-  if (!group || !priv_key || !x || !y || !peer_x || !peer_y ||
-      !t->GetBytes(&z, "Z")) {
-    return false;
-  }
+TEST(ECDHTest, TestVectors) {
+  FileTestGTest("crypto/ecdh/ecdh_tests.txt", [](FileTest *t) {
+    bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
+    ASSERT_TRUE(group);
+    bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
+    ASSERT_TRUE(priv_key);
+    bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
+    ASSERT_TRUE(x);
+    bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
+    ASSERT_TRUE(y);
+    bssl::UniquePtr<BIGNUM> peer_x = GetBIGNUM(t, "PeerX");
+    ASSERT_TRUE(peer_x);
+    bssl::UniquePtr<BIGNUM> peer_y = GetBIGNUM(t, "PeerY");
+    ASSERT_TRUE(peer_y);
+    std::vector<uint8_t> z;
+    ASSERT_TRUE(t->GetBytes(&z, "Z"));
 
-  bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
-  bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
-  bssl::UniquePtr<EC_POINT> peer_pub_key(EC_POINT_new(group.get()));
-  if (!key || !pub_key || !peer_pub_key ||
-      !EC_KEY_set_group(key.get(), group.get()) ||
-      !EC_KEY_set_private_key(key.get(), priv_key.get()) ||
-      !EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(), x.get(),
-                                           y.get(), nullptr) ||
-      !EC_POINT_set_affine_coordinates_GFp(group.get(), peer_pub_key.get(),
-                                           peer_x.get(), peer_y.get(),
-                                           nullptr) ||
-      !EC_KEY_set_public_key(key.get(), pub_key.get()) ||
-      !EC_KEY_check_key(key.get())) {
-    return false;
-  }
+    bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
+    ASSERT_TRUE(key);
+    bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
+    ASSERT_TRUE(pub_key);
+    bssl::UniquePtr<EC_POINT> peer_pub_key(EC_POINT_new(group.get()));
+    ASSERT_TRUE(peer_pub_key);
+    ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
+    ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get()));
+    ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(),
+                                                    x.get(), y.get(), nullptr));
+    ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
+        group.get(), peer_pub_key.get(), peer_x.get(), peer_y.get(), nullptr));
+    ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
+    ASSERT_TRUE(EC_KEY_check_key(key.get()));
 
-  std::vector<uint8_t> actual_z;
-  // Make |actual_z| larger than expected to ensure |ECDH_compute_key| returns
-  // the right amount of data.
-  actual_z.resize(z.size() + 1);
-  int ret = ECDH_compute_key(actual_z.data(), actual_z.size(),
-                             peer_pub_key.get(), key.get(), nullptr);
-  if (ret < 0 ||
-      !t->ExpectBytesEqual(z.data(), z.size(), actual_z.data(),
-                           static_cast<size_t>(ret))) {
-    return false;
-  }
+    std::vector<uint8_t> actual_z;
+    // Make |actual_z| larger than expected to ensure |ECDH_compute_key| returns
+    // the right amount of data.
+    actual_z.resize(z.size() + 1);
+    int ret = ECDH_compute_key(actual_z.data(), actual_z.size(),
+                               peer_pub_key.get(), key.get(), nullptr);
+    ASSERT_GE(ret, 0);
+    EXPECT_EQ(Bytes(z), Bytes(actual_z.data(), static_cast<size_t>(ret)));
 
-  // Test |ECDH_compute_key| truncates.
-  actual_z.resize(z.size() - 1);
-  ret = ECDH_compute_key(actual_z.data(), actual_z.size(), peer_pub_key.get(),
-                         key.get(), nullptr);
-  if (ret < 0 ||
-      !t->ExpectBytesEqual(z.data(), z.size() - 1, actual_z.data(),
-                           static_cast<size_t>(ret))) {
-    return false;
-  }
-
-  return true;
-}
-
-int main(int argc, char *argv[]) {
-  CRYPTO_library_init();
-
-  if (argc != 2) {
-    fprintf(stderr, "%s <test file.txt>\n", argv[0]);
-    return 1;
-  }
-
-  return FileTestMain(TestECDH, nullptr, argv[1]);
+    // Test |ECDH_compute_key| truncates.
+    actual_z.resize(z.size() - 1);
+    ret = ECDH_compute_key(actual_z.data(), actual_z.size(), peer_pub_key.get(),
+                           key.get(), nullptr);
+    ASSERT_GE(ret, 0);
+    EXPECT_EQ(Bytes(z.data(), z.size() - 1),
+              Bytes(actual_z.data(), static_cast<size_t>(ret)));
+  });
 }
diff --git a/crypto/fipsmodule/CMakeLists.txt b/crypto/fipsmodule/CMakeLists.txt
index c43b103..f048ec4 100644
--- a/crypto/fipsmodule/CMakeLists.txt
+++ b/crypto/fipsmodule/CMakeLists.txt
@@ -206,28 +206,6 @@
 add_dependencies(all_tests bn_test)
 
 add_executable(
-  gcm_test
-
-  modes/gcm_test.cc
-
-  $<TARGET_OBJECTS:test_support>
-)
-
-target_link_libraries(gcm_test crypto)
-add_dependencies(all_tests gcm_test)
-
-add_executable(
-  ctrdrbg_vector_test
-
-  rand/ctrdrbg_vector_test.cc
-
-  $<TARGET_OBJECTS:test_support>
-)
-
-target_link_libraries(ctrdrbg_vector_test crypto)
-add_dependencies(all_tests ctrdrbg_vector_test)
-
-add_executable(
   example_mul
 
   ec/example_mul.c
diff --git a/crypto/fipsmodule/modes/gcm_test.cc b/crypto/fipsmodule/modes/gcm_test.cc
index ce7bd96..bfd4275 100644
--- a/crypto/fipsmodule/modes/gcm_test.cc
+++ b/crypto/fipsmodule/modes/gcm_test.cc
@@ -56,370 +56,65 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <vector>
+
+#include <gtest/gtest.h>
+
 #include <openssl/aes.h>
-#include <openssl/crypto.h>
-#include <openssl/mem.h>
 
 #include "internal.h"
+#include "../../test/file_test.h"
 #include "../../test/test_util.h"
 
 
-struct test_case {
-  const char *key;
-  const char *plaintext;
-  const char *additional_data;
-  const char *nonce;
-  const char *ciphertext;
-  const char *tag;
-};
+TEST(GCMTest, TestVectors) {
+  FileTestGTest("crypto/fipsmodule/modes/gcm_tests.txt", [](FileTest *t) {
+    std::vector<uint8_t> key, plaintext, additional_data, nonce, ciphertext,
+        tag;
+    ASSERT_TRUE(t->GetBytes(&key, "Key"));
+    ASSERT_TRUE(t->GetBytes(&plaintext, "Plaintext"));
+    ASSERT_TRUE(t->GetBytes(&additional_data, "AdditionalData"));
+    ASSERT_TRUE(t->GetBytes(&nonce, "Nonce"));
+    ASSERT_TRUE(t->GetBytes(&ciphertext, "Ciphertext"));
+    ASSERT_TRUE(t->GetBytes(&tag, "Tag"));
 
-static const struct test_case test_cases[] = {
-  {
-    "00000000000000000000000000000000",
-    NULL,
-    NULL,
-    "000000000000000000000000",
-    NULL,
-    "58e2fccefa7e3061367f1d57a4e7455a",
-  },
-  {
-    "00000000000000000000000000000000",
-    "00000000000000000000000000000000",
-    NULL,
-    "000000000000000000000000",
-    "0388dace60b6a392f328c2b971b2fe78",
-    "ab6e47d42cec13bdf53a67b21257bddf",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
-    NULL,
-    "cafebabefacedbaddecaf888",
-    "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
-    "4d5c2af327cd64a62cf35abd2ba6fab4",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "cafebabefacedbaddecaf888",
-    "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
-    "5bc94fbc3221a5db94fae95ae7121a47",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "cafebabefacedbad",
-    "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
-    "3612d2e79e3b0785561be14aaca2fccb",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
-    "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
-    "619cc5aefffe0bfa462af43c1699d050",
-  },
-  {
-    "000000000000000000000000000000000000000000000000",
-    NULL,
-    NULL,
-    "000000000000000000000000",
-    NULL,
-    "cd33b28ac773f74ba00ed1f312572435",
-  },
-  {
-    "000000000000000000000000000000000000000000000000",
-    "00000000000000000000000000000000",
-    NULL,
-    "000000000000000000000000",
-    "98e7247c07f0fe411c267e4384b0f600",
-    "2ff58d80033927ab8ef4d4587514f0fb",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
-    NULL,
-    "cafebabefacedbaddecaf888",
-    "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
-    "9924a7c8587336bfb118024db8674a14",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "cafebabefacedbaddecaf888",
-    "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
-    "2519498e80f1478f37ba55bd6d27618c",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "cafebabefacedbad",
-    "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
-    "65dcc57fcf623a24094fcca40d3533f8",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "cafebabefacedbad",
-    "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
-    "65dcc57fcf623a24094fcca40d3533f8",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
-    "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
-    "dcf566ff291c25bbb8568fc3d376a6d9",
-  },
-  {
-    "0000000000000000000000000000000000000000000000000000000000000000",
-    NULL,
-    NULL,
-    "000000000000000000000000",
-    NULL,
-    "530f8afbc74536b9a963b4f1c4cb738b",
-  },
-  {
-    "0000000000000000000000000000000000000000000000000000000000000000",
-    "00000000000000000000000000000000",
-    NULL,
-    "000000000000000000000000",
-    "cea7403d4d606b6e074ec5d3baf39d18",
-    "d0d1c8a799996bf0265b98b5d48ab919",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
-    NULL,
-    "cafebabefacedbaddecaf888",
-    "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
-    "b094dac5d93471bdec1a502270e3cc6c",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "cafebabefacedbaddecaf888",
-    "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
-    "76fc6ece0f4e1768cddf8853bb2d551b",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "cafebabefacedbad",
-    "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
-    "3a337dbf46a792c45e454913fe2ea8f2",
-  },
-  {
-    "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
-    "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
-    "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
-    "a44a8266ee1c8eb0c8b5d4cf5ae9f19a",
-  },
-  {
-    "00000000000000000000000000000000",
-    NULL,
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
-    "000000000000000000000000",
-    NULL,
-    "5fea793a2d6f974d37e68e0cb8ff9492",
-  },
-  {
-    "00000000000000000000000000000000",
-    "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
-    NULL,
-    /* This nonce results in 0xfff in counter LSB. */
-    "ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
-    "56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606872ca10dee15b3249b1a1b958f23134c4bccb7d03200bce420a2f8eb66dcf3644d1423c1b5699003c13ecef4bf38a3b60eedc34033bac1902783dc6d89e2e774188a439c7ebcc0672dbda4ddcfb2794613b0be41315ef778708a70ee7d75165c",
-    "8b307f6b33286d0ab026a9ed3fe1e85f",
-  },
-};
+    ASSERT_EQ(plaintext.size(), ciphertext.size());
+    ASSERT_TRUE(key.size() == 16 || key.size() == 24 || key.size() == 32);
+    ASSERT_EQ(16u, tag.size());
 
-static int from_hex(uint8_t *out, char in) {
-  if (in >= '0' && in <= '9') {
-    *out = in - '0';
-    return 1;
-  }
-  if (in >= 'a' && in <= 'f') {
-    *out = in - 'a' + 10;
-    return 1;
-  }
-  if (in >= 'A' && in <= 'F') {
-    *out = in - 'A' + 10;
-    return 1;
-  }
+    std::vector<uint8_t> out(plaintext.size());
+    AES_KEY aes_key;
+    ASSERT_EQ(0, AES_set_encrypt_key(key.data(), key.size() * 8, &aes_key));
 
-  return 0;
-}
-
-static int decode_hex(uint8_t **out, size_t *out_len, const char *in,
-                      unsigned test_num, const char *description) {
-  if (in == NULL) {
-    *out = NULL;
-    *out_len = 0;
-    return 1;
-  }
-
-  size_t len = strlen(in);
-  if (len & 1) {
-    fprintf(stderr, "%u: Odd-length %s input.\n", test_num, description);
-    return 0;
-  }
-
-  uint8_t *buf = reinterpret_cast<uint8_t *>(OPENSSL_malloc(len / 2));
-  if (buf == NULL) {
-    fprintf(stderr, "%u: malloc failure.\n", test_num);
-    goto err;
-  }
-
-  for (size_t i = 0; i < len; i += 2) {
-    uint8_t v, v2;
-    if (!from_hex(&v, in[i]) ||
-        !from_hex(&v2, in[i+1])) {
-      fprintf(stderr, "%u: invalid hex digit in %s around offset %zu.\n",
-              test_num, description, i);
-      goto err;
+    GCM128_CONTEXT ctx;
+    CRYPTO_gcm128_init(&ctx, &aes_key, (block128_f)AES_encrypt, 0);
+    CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce.data(), nonce.size());
+    if (!additional_data.empty()) {
+      CRYPTO_gcm128_aad(&ctx, additional_data.data(), additional_data.size());
     }
-    buf[i/2] = (v << 4) | v2;
-  }
-
-  *out = buf;
-  *out_len = len/2;
-  return 1;
-
-err:
-  OPENSSL_free(buf);
-  return 0;
-}
-
-static int run_test_case(unsigned test_num, const struct test_case *test) {
-  size_t key_len, plaintext_len, additional_data_len, nonce_len, ciphertext_len,
-      tag_len;
-  uint8_t *key = NULL, *plaintext = NULL, *additional_data = NULL,
-          *nonce = NULL, *ciphertext = NULL, *tag = NULL, *out = NULL;
-  int ret = 0;
-  AES_KEY aes_key;
-  GCM128_CONTEXT ctx;
-
-  if (!decode_hex(&key, &key_len, test->key, test_num, "key") ||
-      !decode_hex(&plaintext, &plaintext_len, test->plaintext, test_num,
-                  "plaintext") ||
-      !decode_hex(&additional_data, &additional_data_len, test->additional_data,
-                  test_num, "additional_data") ||
-      !decode_hex(&nonce, &nonce_len, test->nonce, test_num, "nonce") ||
-      !decode_hex(&ciphertext, &ciphertext_len, test->ciphertext, test_num,
-                  "ciphertext") ||
-      !decode_hex(&tag, &tag_len, test->tag, test_num, "tag")) {
-    goto out;
-  }
-
-  if (plaintext_len != ciphertext_len) {
-    fprintf(stderr, "%u: plaintext and ciphertext have differing lengths.\n",
-            test_num);
-    goto out;
-  }
-
-  if (key_len != 16 && key_len != 24 && key_len != 32) {
-    fprintf(stderr, "%u: bad key length.\n", test_num);
-    goto out;
-  }
-
-  if (tag_len != 16) {
-    fprintf(stderr, "%u: bad tag length.\n", test_num);
-    goto out;
-  }
-
-  out = reinterpret_cast<uint8_t *>(OPENSSL_malloc(plaintext_len));
-  if (plaintext_len != 0 && out == NULL) {
-    goto out;
-  }
-  if (AES_set_encrypt_key(key, key_len*8, &aes_key)) {
-    fprintf(stderr, "%u: AES_set_encrypt_key failed.\n", test_num);
-    goto out;
-  }
-
-  CRYPTO_gcm128_init(&ctx, &aes_key, (block128_f) AES_encrypt, 0);
-  CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce, nonce_len);
-  OPENSSL_memset(out, 0, plaintext_len);
-  if (additional_data) {
-    CRYPTO_gcm128_aad(&ctx, additional_data, additional_data_len);
-  }
-  if (plaintext) {
-    CRYPTO_gcm128_encrypt(&ctx, &aes_key, plaintext, out, plaintext_len);
-  }
-  if (!CRYPTO_gcm128_finish(&ctx, tag, tag_len) ||
-      (ciphertext && OPENSSL_memcmp(out, ciphertext, plaintext_len) != 0)) {
-    fprintf(stderr, "%u: encrypt failed.\n", test_num);
-    hexdump(stderr, "got :", out, plaintext_len);
-    hexdump(stderr, "want:", ciphertext, plaintext_len);
-    goto out;
-  }
-
-  CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce, nonce_len);
-  OPENSSL_memset(out, 0, plaintext_len);
-  if (additional_data) {
-    CRYPTO_gcm128_aad(&ctx, additional_data, additional_data_len);
-  }
-  if (ciphertext) {
-    CRYPTO_gcm128_decrypt(&ctx, &aes_key, ciphertext, out, plaintext_len);
-  }
-  if (!CRYPTO_gcm128_finish(&ctx, tag, tag_len)) {
-    fprintf(stderr, "%u: decrypt failed.\n", test_num);
-    goto out;
-  }
-  if (plaintext && OPENSSL_memcmp(out, plaintext, plaintext_len)) {
-    fprintf(stderr, "%u: plaintext doesn't match.\n", test_num);
-    goto out;
-  }
-
-  ret = 1;
-
-out:
-  OPENSSL_free(key);
-  OPENSSL_free(plaintext);
-  OPENSSL_free(additional_data);
-  OPENSSL_free(nonce);
-  OPENSSL_free(ciphertext);
-  OPENSSL_free(tag);
-  OPENSSL_free(out);
-  return ret;
-}
-
-static bool TestByteSwap() {
-  return CRYPTO_bswap4(0x01020304) == 0x04030201 &&
-         CRYPTO_bswap8(UINT64_C(0x0102030405060708)) ==
-             UINT64_C(0x0807060504030201);
-}
-
-int main(void) {
-  int ret = 0;
-  unsigned i;
-
-  CRYPTO_library_init();
-
-  if (!TestByteSwap()) {
-    ret = 1;
-  }
-
-  for (i = 0; i < sizeof(test_cases) / sizeof(struct test_case); i++) {
-    if (!run_test_case(i, &test_cases[i])) {
-      ret = 1;
+    if (!plaintext.empty()) {
+      CRYPTO_gcm128_encrypt(&ctx, &aes_key, plaintext.data(), out.data(),
+                            plaintext.size());
     }
-  }
+    ASSERT_TRUE(CRYPTO_gcm128_finish(&ctx, tag.data(), tag.size()));
+    EXPECT_EQ(Bytes(ciphertext), Bytes(out));
 
-  if (ret == 0) {
-    printf("PASS\n");
-  }
+    CRYPTO_gcm128_setiv(&ctx, &aes_key, nonce.data(), nonce.size());
+    OPENSSL_memset(out.data(), 0, out.size());
+    if (!additional_data.empty()) {
+      CRYPTO_gcm128_aad(&ctx, additional_data.data(), additional_data.size());
+    }
+    if (!ciphertext.empty()) {
+      CRYPTO_gcm128_decrypt(&ctx, &aes_key, ciphertext.data(), out.data(),
+                            ciphertext.size());
+    }
+    ASSERT_TRUE(CRYPTO_gcm128_finish(&ctx, tag.data(), tag.size()));
+    EXPECT_EQ(Bytes(plaintext), Bytes(out));
+  });
+}
 
-  return ret;
+TEST(GCMTest, ByteSwap) {
+  EXPECT_EQ(0x04030201u, CRYPTO_bswap4(0x01020304u));
+  EXPECT_EQ(UINT64_C(0x0807060504030201),
+            CRYPTO_bswap8(UINT64_C(0x0102030405060708)));
 }
diff --git a/crypto/fipsmodule/modes/gcm_tests.txt b/crypto/fipsmodule/modes/gcm_tests.txt
new file mode 100644
index 0000000..68b3d07
--- /dev/null
+++ b/crypto/fipsmodule/modes/gcm_tests.txt
@@ -0,0 +1,147 @@
+Key = 00000000000000000000000000000000
+Plaintext = 
+AdditionalData = 
+Nonce = 000000000000000000000000
+Ciphertext = 
+Tag = 58e2fccefa7e3061367f1d57a4e7455a
+
+Key = 00000000000000000000000000000000
+Plaintext = 00000000000000000000000000000000
+AdditionalData = 
+Nonce = 000000000000000000000000
+Ciphertext = 0388dace60b6a392f328c2b971b2fe78
+Tag = ab6e47d42cec13bdf53a67b21257bddf
+
+Key = feffe9928665731c6d6a8f9467308308
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+AdditionalData = 
+Nonce = cafebabefacedbaddecaf888
+Ciphertext = 42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985
+Tag = 4d5c2af327cd64a62cf35abd2ba6fab4
+
+Key = feffe9928665731c6d6a8f9467308308
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = cafebabefacedbaddecaf888
+Ciphertext = 42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091
+Tag = 5bc94fbc3221a5db94fae95ae7121a47
+
+Key = feffe9928665731c6d6a8f9467308308
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = cafebabefacedbad
+Ciphertext = 61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598
+Tag = 3612d2e79e3b0785561be14aaca2fccb
+
+Key = feffe9928665731c6d6a8f9467308308
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
+Ciphertext = 8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5
+Tag = 619cc5aefffe0bfa462af43c1699d050
+
+Key = 000000000000000000000000000000000000000000000000
+Plaintext = 
+AdditionalData = 
+Nonce = 000000000000000000000000
+Ciphertext = 
+Tag = cd33b28ac773f74ba00ed1f312572435
+
+Key = 000000000000000000000000000000000000000000000000
+Plaintext = 00000000000000000000000000000000
+AdditionalData = 
+Nonce = 000000000000000000000000
+Ciphertext = 98e7247c07f0fe411c267e4384b0f600
+Tag = 2ff58d80033927ab8ef4d4587514f0fb
+
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+AdditionalData = 
+Nonce = cafebabefacedbaddecaf888
+Ciphertext = 3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256
+Tag = 9924a7c8587336bfb118024db8674a14
+
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = cafebabefacedbaddecaf888
+Ciphertext = 3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710
+Tag = 2519498e80f1478f37ba55bd6d27618c
+
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = cafebabefacedbad
+Ciphertext = 0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7
+Tag = 65dcc57fcf623a24094fcca40d3533f8
+
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = cafebabefacedbad
+Ciphertext = 0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7
+Tag = 65dcc57fcf623a24094fcca40d3533f8
+
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
+Ciphertext = d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b
+Tag = dcf566ff291c25bbb8568fc3d376a6d9
+
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+Plaintext = 
+AdditionalData = 
+Nonce = 000000000000000000000000
+Ciphertext = 
+Tag = 530f8afbc74536b9a963b4f1c4cb738b
+
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+Plaintext = 00000000000000000000000000000000
+AdditionalData = 
+Nonce = 000000000000000000000000
+Ciphertext = cea7403d4d606b6e074ec5d3baf39d18
+Tag = d0d1c8a799996bf0265b98b5d48ab919
+
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+AdditionalData = 
+Nonce = cafebabefacedbaddecaf888
+Ciphertext = 522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad
+Tag = b094dac5d93471bdec1a502270e3cc6c
+
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = cafebabefacedbaddecaf888
+Ciphertext = 522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662
+Tag = 76fc6ece0f4e1768cddf8853bb2d551b
+
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = cafebabefacedbad
+Ciphertext = c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f
+Tag = 3a337dbf46a792c45e454913fe2ea8f2
+
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+AdditionalData = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Nonce = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
+Ciphertext = 5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f
+Tag = a44a8266ee1c8eb0c8b5d4cf5ae9f19a
+
+Key = 00000000000000000000000000000000
+Plaintext = 
+AdditionalData = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad
+Nonce = 000000000000000000000000
+Ciphertext = 
+Tag = 5fea793a2d6f974d37e68e0cb8ff9492
+
+Key = 00000000000000000000000000000000
+Plaintext = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+AdditionalData = 
+# This nonce results in 0xfff in counter LSB.
+Nonce = ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Ciphertext = 56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606872ca10dee15b3249b1a1b958f23134c4bccb7d03200bce420a2f8eb66dcf3644d1423c1b5699003c13ecef4bf38a3b60eedc34033bac1902783dc6d89e2e774188a439c7ebcc0672dbda4ddcfb2794613b0be41315ef778708a70ee7d75165c
+Tag = 8b307f6b33286d0ab026a9ed3fe1e85f
diff --git a/crypto/fipsmodule/rand/ctrdrbg_test.cc b/crypto/fipsmodule/rand/ctrdrbg_test.cc
index a35e6b0..bd84782 100644
--- a/crypto/fipsmodule/rand/ctrdrbg_test.cc
+++ b/crypto/fipsmodule/rand/ctrdrbg_test.cc
@@ -18,6 +18,7 @@
 #include <openssl/sha.h>
 
 #include "internal.h"
+#include "../../test/file_test.h"
 #include "../../test/test_util.h"
 
 
@@ -81,3 +82,38 @@
 
   CTR_DRBG_clear(&drbg);
 }
+
+TEST(CTRDRBGTest, TestVectors) {
+  FileTestGTest("crypto/fipsmodule/rand/ctrdrbg_vectors.txt", [](FileTest *t) {
+    std::vector<uint8_t> seed, personalisation, reseed, ai_reseed, ai1, ai2,
+        expected;
+    ASSERT_TRUE(t->GetBytes(&seed, "EntropyInput"));
+    ASSERT_TRUE(t->GetBytes(&personalisation, "PersonalizationString"));
+    ASSERT_TRUE(t->GetBytes(&reseed, "EntropyInputReseed"));
+    ASSERT_TRUE(t->GetBytes(&ai_reseed, "AdditionalInputReseed"));
+    ASSERT_TRUE(t->GetBytes(&ai1, "AdditionalInput1"));
+    ASSERT_TRUE(t->GetBytes(&ai2, "AdditionalInput2"));
+    ASSERT_TRUE(t->GetBytes(&expected, "ReturnedBits"));
+
+    ASSERT_EQ(static_cast<size_t>(CTR_DRBG_ENTROPY_LEN), seed.size());
+    ASSERT_EQ(static_cast<size_t>(CTR_DRBG_ENTROPY_LEN), reseed.size());
+
+    CTR_DRBG_STATE drbg;
+    CTR_DRBG_init(&drbg, seed.data(),
+                  personalisation.size() > 0 ? personalisation.data() : nullptr,
+                  personalisation.size());
+    CTR_DRBG_reseed(&drbg, reseed.data(),
+                    ai_reseed.size() > 0 ? ai_reseed.data() : nullptr,
+                    ai_reseed.size());
+
+    std::vector<uint8_t> out;
+    out.resize(expected.size());
+
+    CTR_DRBG_generate(&drbg, out.data(), out.size(),
+                      ai1.size() > 0 ? ai1.data() : nullptr, ai1.size());
+    CTR_DRBG_generate(&drbg, out.data(), out.size(),
+                      ai2.size() > 0 ? ai2.data() : nullptr, ai2.size());
+
+    EXPECT_EQ(Bytes(expected), Bytes(out));
+  });
+}
diff --git a/crypto/fipsmodule/rand/ctrdrbg_vector_test.cc b/crypto/fipsmodule/rand/ctrdrbg_vector_test.cc
deleted file mode 100644
index 4680e6e..0000000
--- a/crypto/fipsmodule/rand/ctrdrbg_vector_test.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Copyright (c) 2017, 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/rand.h>
-
-#include <openssl/crypto.h>
-
-#include "internal.h"
-#include "../../test/test_util.h"
-#include "../../test/file_test.h"
-
-
-static bool TestCTRDRBG(FileTest *t, void *arg) {
-  std::vector<uint8_t> seed, personalisation, reseed, ai_reseed, ai1, ai2,
-    expected;
-  if (!t->GetBytes(&seed, "EntropyInput") ||
-      !t->GetBytes(&personalisation, "PersonalizationString") ||
-      !t->GetBytes(&reseed, "EntropyInputReseed") ||
-      !t->GetBytes(&ai_reseed, "AdditionalInputReseed") ||
-      !t->GetBytes(&ai1, "AdditionalInput1") ||
-      !t->GetBytes(&ai2, "AdditionalInput2") ||
-      !t->GetBytes(&expected, "ReturnedBits")) {
-    t->PrintLine("missing value");
-    return false;
-  }
-
-  if (seed.size() != CTR_DRBG_ENTROPY_LEN ||
-      reseed.size() != CTR_DRBG_ENTROPY_LEN) {
-    t->PrintLine("bad seed length");
-    return false;
-  }
-
-  CTR_DRBG_STATE drbg;
-  CTR_DRBG_init(&drbg, seed.data(),
-                personalisation.size() > 0 ? personalisation.data() : nullptr,
-                personalisation.size());
-  CTR_DRBG_reseed(&drbg, reseed.data(),
-                  ai_reseed.size() > 0 ? ai_reseed.data() : nullptr,
-                  ai_reseed.size());
-
-  std::vector<uint8_t> out;
-  out.resize(expected.size());
-
-  CTR_DRBG_generate(&drbg, out.data(), out.size(),
-                    ai1.size() > 0 ? ai1.data() : nullptr, ai1.size());
-  CTR_DRBG_generate(&drbg, out.data(), out.size(),
-                    ai2.size() > 0 ? ai2.data() : nullptr, ai2.size());
-
-  return t->ExpectBytesEqual(expected.data(), expected.size(), out.data(),
-                             out.size());
-}
-
-int main(int argc, char **argv) {
-  CRYPTO_library_init();
-
-  if (argc != 2) {
-    fprintf(stderr, "%s <test file>\n", argv[0]);
-    return 1;
-  }
-
-  return FileTestMain(TestCTRDRBG, nullptr, argv[1]);
-}
diff --git a/crypto/hmac_extra/CMakeLists.txt b/crypto/hmac_extra/CMakeLists.txt
deleted file mode 100644
index 045213a..0000000
--- a/crypto/hmac_extra/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-include_directories(../../include)
-
-add_executable(
-  hmac_test
-
-  hmac_test.cc
-
-  $<TARGET_OBJECTS:test_support>
-)
-
-target_link_libraries(hmac_test crypto)
-add_dependencies(all_tests hmac_test)
diff --git a/crypto/hmac_extra/hmac_test.cc b/crypto/hmac_extra/hmac_test.cc
index 7b216e2..d285343 100644
--- a/crypto/hmac_extra/hmac_test.cc
+++ b/crypto/hmac_extra/hmac_test.cc
@@ -54,18 +54,17 @@
  * copied and put under another distribution licence
  * [including the GNU Public Licence.] */
 
-#include <stdio.h>
-#include <string.h>
-
 #include <memory>
 #include <string>
 #include <vector>
 
-#include <openssl/crypto.h>
+#include <gtest/gtest.h>
+
 #include <openssl/digest.h>
 #include <openssl/hmac.h>
 
 #include "../test/file_test.h"
+#include "../test/test_util.h"
 
 
 static const EVP_MD *GetDigest(const std::string &name) {
@@ -85,85 +84,47 @@
   return nullptr;
 }
 
-static bool TestHMAC(FileTest *t, void *arg) {
-  std::string digest_str;
-  if (!t->GetAttribute(&digest_str, "HMAC")) {
-    return false;
-  }
-  const EVP_MD *digest = GetDigest(digest_str);
-  if (digest == nullptr) {
-    t->PrintLine("Unknown digest '%s'", digest_str.c_str());
-    return false;
-  }
+TEST(HMACTest, TestVectors) {
+  FileTestGTest("crypto/hmac_extra/hmac_tests.txt", [](FileTest *t) {
+    std::string digest_str;
+    ASSERT_TRUE(t->GetAttribute(&digest_str, "HMAC"));
+    const EVP_MD *digest = GetDigest(digest_str);
+    ASSERT_TRUE(digest) << "Unknown digest: " << digest_str;
 
-  std::vector<uint8_t> key, input, output;
-  if (!t->GetBytes(&key, "Key") ||
-      !t->GetBytes(&input, "Input") ||
-      !t->GetBytes(&output, "Output")) {
-    return false;
-  }
+    std::vector<uint8_t> key, input, output;
+    ASSERT_TRUE(t->GetBytes(&key, "Key"));
+    ASSERT_TRUE(t->GetBytes(&input, "Input"));
+    ASSERT_TRUE(t->GetBytes(&output, "Output"));
+    ASSERT_EQ(EVP_MD_size(digest), output.size());
 
-  // Test using the one-shot API.
-  unsigned expected_mac_len = EVP_MD_size(digest);
-  std::unique_ptr<uint8_t[]> mac(new uint8_t[expected_mac_len]);
-  unsigned mac_len;
-  if (nullptr == HMAC(digest, key.data(), key.size(), input.data(),
-                      input.size(), mac.get(), &mac_len) ||
-      mac_len != expected_mac_len ||
-      !t->ExpectBytesEqual(output.data(), output.size(), mac.get(), mac_len)) {
-    t->PrintLine("One-shot API failed.");
-    return false;
-  }
+    // Test using the one-shot API.
+    unsigned expected_mac_len = EVP_MD_size(digest);
+    std::unique_ptr<uint8_t[]> mac(new uint8_t[expected_mac_len]);
+    unsigned mac_len;
+    ASSERT_TRUE(HMAC(digest, key.data(), key.size(), input.data(), input.size(),
+                     mac.get(), &mac_len));
+    EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len));
 
-  // Test using HMAC_CTX.
-  bssl::ScopedHMAC_CTX ctx;
-  if (!HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr) ||
-      !HMAC_Update(ctx.get(), input.data(), input.size()) ||
-      !HMAC_Final(ctx.get(), mac.get(), &mac_len) ||
-      mac_len != expected_mac_len ||
-      !t->ExpectBytesEqual(output.data(), output.size(), mac.get(), mac_len)) {
-    t->PrintLine("HMAC_CTX failed.");
-   return false;
-  }
+    // Test using HMAC_CTX.
+    bssl::ScopedHMAC_CTX ctx;
+    ASSERT_TRUE(
+        HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr));
+    ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size()));
+    ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len));
+    EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len));
 
-  // Test that an HMAC_CTX may be reset with the same key.
-  if (!HMAC_Init_ex(ctx.get(), nullptr, 0, digest, nullptr) ||
-      !HMAC_Update(ctx.get(), input.data(), input.size()) ||
-      !HMAC_Final(ctx.get(), mac.get(), &mac_len) ||
-      mac_len != expected_mac_len ||
-      !t->ExpectBytesEqual(output.data(), output.size(), mac.get(), mac_len)) {
-    t->PrintLine("HMAC_CTX with reset failed.");
-   return false;
-  }
+    // Test that an HMAC_CTX may be reset with the same key.
+    ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, digest, nullptr));
+    ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size()));
+    ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len));
+    EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len));
 
-  // Test feeding the input in byte by byte.
-  if (!HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr)) {
-   t->PrintLine("HMAC_CTX streaming failed.");
-   return false;
-  }
-  for (size_t i = 0; i < input.size(); i++) {
-    if (!HMAC_Update(ctx.get(), &input[i], 1)) {
-      t->PrintLine("HMAC_CTX streaming failed.");
-      return false;
+    // Test feeding the input in byte by byte.
+    ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr));
+    for (size_t i = 0; i < input.size(); i++) {
+      ASSERT_TRUE(HMAC_Update(ctx.get(), &input[i], 1));
     }
-  }
-  if (!HMAC_Final(ctx.get(), mac.get(), &mac_len) ||
-      mac_len != expected_mac_len ||
-      !t->ExpectBytesEqual(output.data(), output.size(), mac.get(), mac_len)) {
-    t->PrintLine("HMAC_CTX streaming failed.");
-    return false;
-  }
-
-  return true;
-}
-
-int main(int argc, char *argv[]) {
-  CRYPTO_library_init();
-
-  if (argc != 2) {
-    fprintf(stderr, "%s <test file.txt>\n", argv[0]);
-    return 1;
-  }
-
-  return FileTestMain(TestHMAC, nullptr, argv[1]);
+    ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len));
+    EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len));
+  });
 }
diff --git a/crypto/poly1305/CMakeLists.txt b/crypto/poly1305/CMakeLists.txt
index 1b6a804..5534e62 100644
--- a/crypto/poly1305/CMakeLists.txt
+++ b/crypto/poly1305/CMakeLists.txt
@@ -19,13 +19,3 @@
 
   ${POLY1305_ARCH_SOURCES}
 )
-
-add_executable(
-  poly1305_test
-
-  poly1305_test.cc
-  $<TARGET_OBJECTS:test_support>
-)
-
-target_link_libraries(poly1305_test crypto)
-add_dependencies(all_tests poly1305_test)
diff --git a/crypto/poly1305/poly1305_test.cc b/crypto/poly1305/poly1305_test.cc
index 2c25e93..198cca1 100644
--- a/crypto/poly1305/poly1305_test.cc
+++ b/crypto/poly1305/poly1305_test.cc
@@ -17,15 +17,16 @@
 
 #include <vector>
 
-#include <openssl/crypto.h>
+#include <gtest/gtest.h>
+
 #include <openssl/poly1305.h>
 
 #include "../internal.h"
 #include "../test/file_test.h"
+#include "../test/test_util.h"
 
 
-static bool TestSIMD(FileTest *t, unsigned excess,
-                     const std::vector<uint8_t> &key,
+static void TestSIMD(unsigned excess, const std::vector<uint8_t> &key,
                      const std::vector<uint8_t> &in,
                      const std::vector<uint8_t> &mac) {
   poly1305_state state;
@@ -64,68 +65,40 @@
   // |CRYPTO_poly1305_finish| requires a 16-byte-aligned output.
   alignas(16) uint8_t out[16];
   CRYPTO_poly1305_finish(&state, out);
-  if (!t->ExpectBytesEqual(mac.data(), mac.size(), out, 16)) {
-    t->PrintLine("SIMD pattern %u failed.", excess);
-    return false;
-  }
-
-  return true;
+  EXPECT_EQ(Bytes(out), Bytes(mac)) << "SIMD pattern " << excess << " failed.";
 }
 
-static bool TestPoly1305(FileTest *t, void *arg) {
-  std::vector<uint8_t> key, in, mac;
-  if (!t->GetBytes(&key, "Key") ||
-      !t->GetBytes(&in, "Input") ||
-      !t->GetBytes(&mac, "MAC")) {
-    return false;
-  }
-  if (key.size() != 32 || mac.size() != 16) {
-    t->PrintLine("Invalid test");
-    return false;
-  }
+TEST(Poly1305Test, TestVectors) {
+  FileTestGTest("crypto/poly1305/poly1305_tests.txt", [](FileTest *t) {
+    std::vector<uint8_t> key, in, mac;
+    ASSERT_TRUE(t->GetBytes(&key, "Key"));
+    ASSERT_TRUE(t->GetBytes(&in, "Input"));
+    ASSERT_TRUE(t->GetBytes(&mac, "MAC"));
+    ASSERT_EQ(32u, key.size());
+    ASSERT_EQ(16u, mac.size());
 
-  // Test single-shot operation.
-  poly1305_state state;
-  CRYPTO_poly1305_init(&state, key.data());
-  CRYPTO_poly1305_update(&state, in.data(), in.size());
-  // |CRYPTO_poly1305_finish| requires a 16-byte-aligned output.
-  alignas(16) uint8_t out[16];
-  CRYPTO_poly1305_finish(&state, out);
-  if (!t->ExpectBytesEqual(out, 16, mac.data(), mac.size())) {
-    t->PrintLine("Single-shot Poly1305 failed.");
-    return false;
-  }
+    // Test single-shot operation.
+    poly1305_state state;
+    CRYPTO_poly1305_init(&state, key.data());
+    CRYPTO_poly1305_update(&state, in.data(), in.size());
+    // |CRYPTO_poly1305_finish| requires a 16-byte-aligned output.
+    alignas(16) uint8_t out[16];
+    CRYPTO_poly1305_finish(&state, out);
+    EXPECT_EQ(Bytes(out), Bytes(mac)) << "Single-shot Poly1305 failed.";
 
-  // Test streaming byte-by-byte.
-  CRYPTO_poly1305_init(&state, key.data());
-  for (size_t i = 0; i < in.size(); i++) {
-    CRYPTO_poly1305_update(&state, &in[i], 1);
-  }
-  CRYPTO_poly1305_finish(&state, out);
-  if (!t->ExpectBytesEqual(mac.data(), mac.size(), out, 16)) {
-    t->PrintLine("Streaming Poly1305 failed.");
-    return false;
-  }
+    // Test streaming byte-by-byte.
+    CRYPTO_poly1305_init(&state, key.data());
+    for (size_t i = 0; i < in.size(); i++) {
+      CRYPTO_poly1305_update(&state, &in[i], 1);
+    }
+    CRYPTO_poly1305_finish(&state, out);
+    EXPECT_EQ(Bytes(out), Bytes(mac)) << "Streaming Poly1305 failed.";
 
-  // Test SIMD stress patterns. OpenSSL's AVX2 assembly needs a multiple of
-  // four blocks, so test up to three blocks of excess.
-  if (!TestSIMD(t, 0, key, in, mac) ||
-      !TestSIMD(t, 16, key, in, mac) ||
-      !TestSIMD(t, 32, key, in, mac) ||
-      !TestSIMD(t, 48, key, in, mac)) {
-    return false;
-  }
-
-  return true;
-}
-
-int main(int argc, char **argv) {
-  CRYPTO_library_init();
-
-  if (argc != 2) {
-    fprintf(stderr, "%s <test file>\n", argv[0]);
-    return 1;
-  }
-
-  return FileTestMain(TestPoly1305, nullptr, argv[1]);
+    // Test SIMD stress patterns. OpenSSL's AVX2 assembly needs a multiple of
+    // four blocks, so test up to three blocks of excess.
+    TestSIMD(0, key, in, mac);
+    TestSIMD(16, key, in, mac);
+    TestSIMD(32, key, in, mac);
+    TestSIMD(48, key, in, mac);
+  });
 }
diff --git a/crypto/test/file_test_gtest.cc b/crypto/test/file_test_gtest.cc
index 9d3c3e4..cffacb3 100644
--- a/crypto/test/file_test_gtest.cc
+++ b/crypto/test/file_test_gtest.cc
@@ -23,6 +23,8 @@
 
 #include <gtest/gtest.h>
 
+#include <openssl/err.h>
+
 
 std::string GetTestData(const char *path);
 
@@ -81,5 +83,8 @@
 
     SCOPED_TRACE(testing::Message() << path << ", line " << t.start_line());
     run_test(&t);
+
+    // Clean up the error queue for the next test.
+    ERR_clear_error();
   }
 }
diff --git a/sources.cmake b/sources.cmake
index 4de0d07..89c64f7 100644
--- a/sources.cmake
+++ b/sources.cmake
@@ -6,6 +6,41 @@
 set(
   CRYPTO_TEST_DATA
 
+  crypto/cipher_extra/test/aes_128_cbc_sha1_ssl3_tests.txt
+  crypto/cipher_extra/test/aes_128_cbc_sha1_tls_implicit_iv_tests.txt
+  crypto/cipher_extra/test/aes_128_cbc_sha1_tls_tests.txt
+  crypto/cipher_extra/test/aes_128_cbc_sha256_tls_tests.txt
+  crypto/cipher_extra/test/aes_128_ctr_hmac_sha256.txt
+  crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt
+  crypto/cipher_extra/test/aes_128_gcm_tests.txt
+  crypto/cipher_extra/test/aes_256_cbc_sha1_ssl3_tests.txt
+  crypto/cipher_extra/test/aes_256_cbc_sha1_tls_implicit_iv_tests.txt
+  crypto/cipher_extra/test/aes_256_cbc_sha1_tls_tests.txt
+  crypto/cipher_extra/test/aes_256_cbc_sha256_tls_tests.txt
+  crypto/cipher_extra/test/aes_256_cbc_sha384_tls_tests.txt
+  crypto/cipher_extra/test/aes_256_ctr_hmac_sha256.txt
+  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/cipher_tests.txt
+  crypto/cipher_extra/test/des_ede3_cbc_sha1_ssl3_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
+  crypto/cipher_extra/test/nist_cavp/aes_128_cbc.txt
+  crypto/cipher_extra/test/nist_cavp/aes_128_ctr.txt
+  crypto/cipher_extra/test/nist_cavp/aes_128_gcm.txt
+  crypto/cipher_extra/test/nist_cavp/aes_192_cbc.txt
+  crypto/cipher_extra/test/nist_cavp/aes_192_ctr.txt
+  crypto/cipher_extra/test/nist_cavp/aes_256_cbc.txt
+  crypto/cipher_extra/test/nist_cavp/aes_256_ctr.txt
+  crypto/cipher_extra/test/nist_cavp/aes_256_gcm.txt
+  crypto/cipher_extra/test/nist_cavp/tdes_cbc.txt
+  crypto/cipher_extra/test/nist_cavp/tdes_ecb.txt
   crypto/curve25519/ed25519_tests.txt
+  crypto/ecdh/ecdh_tests.txt
   crypto/fipsmodule/aes/aes_tests.txt
+  crypto/fipsmodule/modes/gcm_tests.txt
+  crypto/fipsmodule/rand/ctrdrbg_vectors.txt
+  crypto/hmac_extra/hmac_tests.txt
+  crypto/poly1305/poly1305_tests.txt
 )
diff --git a/util/all_tests.json b/util/all_tests.json
index e496b8f..e209cf9 100644
--- a/util/all_tests.json
+++ b/util/all_tests.json
@@ -1,51 +1,16 @@
 [
-	["crypto/cipher_extra/aead_test", "aes-128-cbc-sha1-ssl3", "crypto/cipher_extra/test/aes_128_cbc_sha1_ssl3_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-128-cbc-sha1-tls", "crypto/cipher_extra/test/aes_128_cbc_sha1_tls_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-128-cbc-sha1-tls-implicit-iv", "crypto/cipher_extra/test/aes_128_cbc_sha1_tls_implicit_iv_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-128-cbc-sha256-tls", "crypto/cipher_extra/test/aes_128_cbc_sha256_tls_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-128-ctr-hmac-sha256", "crypto/cipher_extra/test/aes_128_ctr_hmac_sha256.txt"],
-	["crypto/cipher_extra/aead_test", "aes-128-gcm", "crypto/cipher_extra/test/aes_128_gcm_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-128-gcm", "crypto/cipher_extra/test/nist_cavp/aes_128_gcm.txt"],
-	["crypto/cipher_extra/aead_test", "aes-128-gcm-siv", "crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-256-cbc-sha1-ssl3", "crypto/cipher_extra/test/aes_256_cbc_sha1_ssl3_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-256-cbc-sha1-tls", "crypto/cipher_extra/test/aes_256_cbc_sha1_tls_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-256-cbc-sha1-tls-implicit-iv", "crypto/cipher_extra/test/aes_256_cbc_sha1_tls_implicit_iv_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-256-cbc-sha256-tls", "crypto/cipher_extra/test/aes_256_cbc_sha256_tls_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-256-cbc-sha384-tls", "crypto/cipher_extra/test/aes_256_cbc_sha384_tls_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-256-ctr-hmac-sha256", "crypto/cipher_extra/test/aes_256_ctr_hmac_sha256.txt"],
-	["crypto/cipher_extra/aead_test", "aes-256-gcm", "crypto/cipher_extra/test/aes_256_gcm_tests.txt"],
-	["crypto/cipher_extra/aead_test", "aes-256-gcm", "crypto/cipher_extra/test/nist_cavp/aes_256_gcm.txt"],
-	["crypto/cipher_extra/aead_test", "aes-256-gcm-siv", "crypto/cipher_extra/test/aes_256_gcm_siv_tests.txt"],
-	["crypto/cipher_extra/aead_test", "chacha20-poly1305", "crypto/cipher_extra/test/chacha20_poly1305_tests.txt"],
-	["crypto/cipher_extra/aead_test", "des-ede3-cbc-sha1-ssl3", "crypto/cipher_extra/test/des_ede3_cbc_sha1_ssl3_tests.txt"],
-	["crypto/cipher_extra/aead_test", "des-ede3-cbc-sha1-tls", "crypto/cipher_extra/test/des_ede3_cbc_sha1_tls_tests.txt"],
-	["crypto/cipher_extra/aead_test", "des-ede3-cbc-sha1-tls-implicit-iv", "crypto/cipher_extra/test/des_ede3_cbc_sha1_tls_implicit_iv_tests.txt"],
-	["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/cipher_tests.txt"],
-	["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_128_cbc.txt"],
-	["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_128_ctr.txt"],
-	["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_192_cbc.txt"],
-	["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_192_ctr.txt"],
-	["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_256_cbc.txt"],
-	["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/aes_256_ctr.txt"],
-	["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/tdes_cbc.txt"],
-	["crypto/cipher_extra/cipher_test", "crypto/cipher_extra/test/nist_cavp/tdes_ecb.txt"],
 	["crypto/crypto_test"],
-	["crypto/ecdh/ecdh_test", "crypto/ecdh/ecdh_tests.txt"],
 	["crypto/evp/evp_test", "crypto/evp/evp_tests.txt"],
 	["crypto/fipsmodule/bn_test", "crypto/fipsmodule/bn/bn_tests.txt"],
-	["crypto/fipsmodule/ctrdrbg_vector_test", "crypto/fipsmodule/rand/ctrdrbg_vectors.txt"],
 	["crypto/fipsmodule/ecdsa_sign_test", "crypto/fipsmodule/ecdsa/ecdsa_sign_tests.txt"],
 	["crypto/fipsmodule/ecdsa_test"],
 	["crypto/fipsmodule/ecdsa_verify_test", "crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt"],
 	["crypto/fipsmodule/example_mul"],
-	["crypto/fipsmodule/gcm_test"],
 	["crypto/fipsmodule/p256-x86_64_test", "crypto/fipsmodule/ec/p256-x86_64_tests.txt"],
-	["crypto/hmac_extra/hmac_test", "crypto/hmac_extra/hmac_tests.txt"],
 	["crypto/obj/obj_test"],
 	["crypto/pkcs7/pkcs7_test"],
 	["crypto/pkcs8/pkcs12_test"],
 	["crypto/pkcs8/pkcs8_test"],
-	["crypto/poly1305/poly1305_test", "crypto/poly1305/poly1305_tests.txt"],
 	["crypto/thread_test"],
 	["crypto/x509v3/tab_test"],
 	["crypto/x509v3/v3name_test"],