Don't delay-initialize legacy AEADs.

Instead, add a separate init_with_direction hook. Normal AEADs ignore the
direction, while legacy AEADs must be initialized with it. This avoids
maintaining extra state to support the delayed initialization.

Change-Id: I25271f0e56ee2783a2fd4d4026434154d58dc0a8
Reviewed-on: https://boringssl-review.googlesource.com/3731
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/cipher/aead.c b/crypto/cipher/aead.c
index 263e398..daf8c52 100644
--- a/crypto/cipher/aead.c
+++ b/crypto/cipher/aead.c
@@ -33,12 +33,29 @@
 int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
                       const uint8_t *key, size_t key_len, size_t tag_len,
                       ENGINE *impl) {
-  ctx->aead = aead;
-  if (key_len != aead->key_len) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_AEAD_CTX_init, CIPHER_R_UNSUPPORTED_KEY_SIZE);
+  if (!aead->init) {
+    OPENSSL_PUT_ERROR(CIPHER, EVP_AEAD_CTX_init, CIPHER_R_NO_DIRECTION_SET);
     return 0;
   }
-  return aead->init(ctx, key, key_len, tag_len);
+  return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len,
+                                          evp_aead_open);
+}
+
+int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
+                                     const uint8_t *key, size_t key_len,
+                                     size_t tag_len,
+                                     enum evp_aead_direction_t dir) {
+  ctx->aead = aead;
+  if (key_len != aead->key_len) {
+    OPENSSL_PUT_ERROR(CIPHER, EVP_AEAD_CTX_init_with_direction,
+                      CIPHER_R_UNSUPPORTED_KEY_SIZE);
+    return 0;
+  }
+  if (aead->init) {
+    return aead->init(ctx, key, key_len, tag_len);
+  } else {
+    return aead->init_with_direction(ctx, key, key_len, tag_len, dir);
+  }
 }
 
 void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) {
diff --git a/crypto/cipher/aead_test.c b/crypto/cipher/aead_test.c
index 310c90c..33e260a 100644
--- a/crypto/cipher/aead_test.c
+++ b/crypto/cipher/aead_test.c
@@ -85,8 +85,8 @@
    * smaller by at least tag length. */
   uint8_t out2[sizeof(out)];
 
-  if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
-                         NULL)) {
+  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bufs[KEY], lengths[KEY],
+                                        lengths[TAG], evp_aead_seal)) {
     fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
     return 0;
   }
@@ -123,8 +123,8 @@
   /* The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
    * reset after each operation. */
   EVP_AEAD_CTX_cleanup(&ctx);
-  if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
-                         NULL)) {
+  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bufs[KEY], lengths[KEY],
+                                        lengths[TAG], evp_aead_open)) {
     fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
     return 0;
   }
@@ -153,8 +153,8 @@
     /* The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
      * reset after each operation. */
     EVP_AEAD_CTX_cleanup(&ctx);
-    if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
-                           NULL)) {
+    if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bufs[KEY], lengths[KEY],
+                                          lengths[TAG], evp_aead_open)) {
       fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
       return 0;
     }
@@ -172,8 +172,8 @@
     /* The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
      * reset after each operation. */
     EVP_AEAD_CTX_cleanup(&ctx);
-    if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
-                           NULL)) {
+    if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bufs[KEY], lengths[KEY],
+                                          lengths[TAG], evp_aead_open)) {
       fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
       return 0;
     }
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
index 01c2d7d..e431e0b 100644
--- a/crypto/cipher/e_aes.c
+++ b/crypto/cipher/e_aes.c
@@ -1071,8 +1071,11 @@
     12,                       /* nonce len */
     EVP_AEAD_AES_GCM_TAG_LEN, /* overhead */
     EVP_AEAD_AES_GCM_TAG_LEN, /* max tag length */
-    aead_aes_gcm_init,        aead_aes_gcm_cleanup,
-    aead_aes_gcm_seal,        aead_aes_gcm_open,
+    aead_aes_gcm_init,
+    NULL, /* init_with_direction */
+    aead_aes_gcm_cleanup,
+    aead_aes_gcm_seal,
+    aead_aes_gcm_open,
 };
 
 static const EVP_AEAD aead_aes_256_gcm = {
@@ -1080,8 +1083,11 @@
     12,                       /* nonce len */
     EVP_AEAD_AES_GCM_TAG_LEN, /* overhead */
     EVP_AEAD_AES_GCM_TAG_LEN, /* max tag length */
-    aead_aes_gcm_init,        aead_aes_gcm_cleanup,
-    aead_aes_gcm_seal,        aead_aes_gcm_open,
+    aead_aes_gcm_init,
+    NULL, /* init_with_direction */
+    aead_aes_gcm_cleanup,
+    aead_aes_gcm_seal,
+    aead_aes_gcm_open,
 };
 
 const EVP_AEAD *EVP_aead_aes_128_gcm(void) { return &aead_aes_128_gcm; }
@@ -1335,8 +1341,11 @@
     8,  /* nonce len */
     8,  /* overhead */
     8,  /* max tag length */
-    aead_aes_key_wrap_init, aead_aes_key_wrap_cleanup,
-    aead_aes_key_wrap_seal, aead_aes_key_wrap_open,
+    aead_aes_key_wrap_init,
+    NULL, /* init_with_direction */
+    aead_aes_key_wrap_cleanup,
+    aead_aes_key_wrap_seal,
+    aead_aes_key_wrap_open,
 };
 
 static const EVP_AEAD aead_aes_256_key_wrap = {
@@ -1344,8 +1353,11 @@
     8,  /* nonce len */
     8,  /* overhead */
     8,  /* max tag length */
-    aead_aes_key_wrap_init, aead_aes_key_wrap_cleanup,
-    aead_aes_key_wrap_seal, aead_aes_key_wrap_open,
+    aead_aes_key_wrap_init,
+    NULL, /* init_with_direction */
+    aead_aes_key_wrap_cleanup,
+    aead_aes_key_wrap_seal,
+    aead_aes_key_wrap_open,
 };
 
 const EVP_AEAD *EVP_aead_aes_128_key_wrap(void) { return &aead_aes_128_key_wrap; }
diff --git a/crypto/cipher/e_chacha20poly1305.c b/crypto/cipher/e_chacha20poly1305.c
index 1cdcbca..e360904 100644
--- a/crypto/cipher/e_chacha20poly1305.c
+++ b/crypto/cipher/e_chacha20poly1305.c
@@ -209,8 +209,11 @@
     CHACHA20_NONCE_LEN, /* nonce len */
     POLY1305_TAG_LEN,   /* overhead */
     POLY1305_TAG_LEN,   /* max tag length */
-    aead_chacha20_poly1305_init, aead_chacha20_poly1305_cleanup,
-    aead_chacha20_poly1305_seal, aead_chacha20_poly1305_open,
+    aead_chacha20_poly1305_init,
+    NULL, /* init_with_direction */
+    aead_chacha20_poly1305_cleanup,
+    aead_chacha20_poly1305_seal,
+    aead_chacha20_poly1305_open,
 };
 
 const EVP_AEAD *EVP_aead_chacha20_poly1305(void) {
diff --git a/crypto/cipher/e_rc4.c b/crypto/cipher/e_rc4.c
index 04ddcb6..52856f9 100644
--- a/crypto/cipher/e_rc4.c
+++ b/crypto/cipher/e_rc4.c
@@ -377,8 +377,11 @@
     0,                      /* nonce len */
     MD5_DIGEST_LENGTH,      /* overhead */
     MD5_DIGEST_LENGTH,      /* max tag length */
-    aead_rc4_md5_tls_init,  aead_rc4_md5_tls_cleanup,
-    aead_rc4_md5_tls_seal,  aead_rc4_md5_tls_open,
+    aead_rc4_md5_tls_init,
+    NULL, /* init_with_direction */
+    aead_rc4_md5_tls_cleanup,
+    aead_rc4_md5_tls_seal,
+    aead_rc4_md5_tls_open,
 };
 
 const EVP_AEAD *EVP_aead_rc4_md5_tls(void) { return &aead_rc4_md5_tls; }
diff --git a/crypto/cipher/e_ssl3.c b/crypto/cipher/e_ssl3.c
index d9dec68..1faf5fa 100644
--- a/crypto/cipher/e_ssl3.c
+++ b/crypto/cipher/e_ssl3.c
@@ -30,17 +30,6 @@
 typedef struct {
   EVP_CIPHER_CTX cipher_ctx;
   EVP_MD_CTX md_ctx;
-  /* enc_key is the portion of the key used for the stream or block cipher. It
-   * is retained separately to allow the EVP_CIPHER_CTX to be initialized once
-   * the direction is known. */
-  uint8_t enc_key[EVP_MAX_KEY_LENGTH];
-  uint8_t enc_key_len;
-  /* iv is the portion of the key used for the fixed IV. It is retained
-   * separately to allow the EVP_CIPHER_CTX to be initialized once the direction
-   * is known. */
-  uint8_t iv[EVP_MAX_IV_LENGTH];
-  uint8_t iv_len;
-  char initialized;
 } AEAD_SSL3_CTX;
 
 static int ssl3_mac(AEAD_SSL3_CTX *ssl3_ctx, uint8_t *out, unsigned *out_len,
@@ -87,15 +76,13 @@
   AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
   EVP_CIPHER_CTX_cleanup(&ssl3_ctx->cipher_ctx);
   EVP_MD_CTX_cleanup(&ssl3_ctx->md_ctx);
-  OPENSSL_cleanse(&ssl3_ctx->enc_key, sizeof(ssl3_ctx->enc_key));
-  OPENSSL_cleanse(&ssl3_ctx->iv, sizeof(ssl3_ctx->iv));
   OPENSSL_free(ssl3_ctx);
   ctx->aead_state = NULL;
 }
 
 static int aead_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len,
-                          size_t tag_len, const EVP_CIPHER *cipher,
-                          const EVP_MD *md) {
+                          size_t tag_len, enum evp_aead_direction_t dir,
+                          const EVP_CIPHER *cipher, const EVP_MD *md) {
   if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH &&
       tag_len != EVP_MD_size(md)) {
     OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_init, CIPHER_R_UNSUPPORTED_TAG_SIZE);
@@ -109,11 +96,7 @@
 
   size_t mac_key_len = EVP_MD_size(md);
   size_t enc_key_len = EVP_CIPHER_key_length(cipher);
-  size_t iv_len = EVP_CIPHER_iv_length(cipher);
-  assert(mac_key_len + enc_key_len + iv_len == key_len);
-  assert(mac_key_len < 256);
-  assert(enc_key_len < 256);
-  assert(iv_len < 256);
+  assert(mac_key_len + enc_key_len + EVP_CIPHER_iv_length(cipher) == key_len);
   /* Although EVP_rc4() is a variable-length cipher, the default key size is
    * correct for SSL3. */
 
@@ -124,14 +107,11 @@
   }
   EVP_CIPHER_CTX_init(&ssl3_ctx->cipher_ctx);
   EVP_MD_CTX_init(&ssl3_ctx->md_ctx);
-  memcpy(ssl3_ctx->enc_key, &key[mac_key_len], enc_key_len);
-  ssl3_ctx->enc_key_len = (uint8_t)enc_key_len;
-  memcpy(ssl3_ctx->iv, &key[mac_key_len + enc_key_len], iv_len);
-  ssl3_ctx->iv_len = (uint8_t)iv_len;
-  ssl3_ctx->initialized = 0;
 
   ctx->aead_state = ssl3_ctx;
-  if (!EVP_CipherInit_ex(&ssl3_ctx->cipher_ctx, cipher, NULL, NULL, NULL, 0) ||
+  if (!EVP_CipherInit_ex(&ssl3_ctx->cipher_ctx, cipher, NULL, &key[mac_key_len],
+                         &key[mac_key_len + enc_key_len],
+                         dir == evp_aead_seal) ||
       !EVP_DigestInit_ex(&ssl3_ctx->md_ctx, md, NULL) ||
       !EVP_DigestUpdate(&ssl3_ctx->md_ctx, key, mac_key_len)) {
     aead_ssl3_cleanup(ctx);
@@ -142,31 +122,6 @@
   return 1;
 }
 
-/* aead_ssl3_ensure_cipher_init initializes |ssl3_ctx| for encryption (or
- * decryption, if |encrypt| is zero). If it has already been initialized, it
- * ensures the direction matches and fails otherwise. It returns one on success
- * and zero on failure.
- *
- * Note that, unlike normal AEADs, legacy SSL3 AEADs may not be used concurrently
- * due to this (and bulk-cipher-internal) statefulness. */
-static int aead_ssl3_ensure_cipher_init(AEAD_SSL3_CTX *ssl3_ctx, int encrypt) {
-  if (!ssl3_ctx->initialized) {
-    /* Finish initializing the EVP_CIPHER_CTX now that the direction is
-     * known. */
-    if (!EVP_CipherInit_ex(&ssl3_ctx->cipher_ctx, NULL, NULL, ssl3_ctx->enc_key,
-                           ssl3_ctx->iv, encrypt)) {
-      return 0;
-    }
-    ssl3_ctx->initialized = 1;
-  } else if (ssl3_ctx->cipher_ctx.encrypt != encrypt) {
-    /* Unlike a normal AEAD, using an SSL3 AEAD once freezes the direction. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_ensure_cipher_init,
-                      CIPHER_R_INVALID_OPERATION);
-    return 0;
-  }
-  return 1;
-}
-
 static int aead_ssl3_seal(const EVP_AEAD_CTX *ctx, uint8_t *out,
                          size_t *out_len, size_t max_out_len,
                          const uint8_t *nonce, size_t nonce_len,
@@ -175,6 +130,12 @@
   AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
   size_t total = 0;
 
+  if (!ssl3_ctx->cipher_ctx.encrypt) {
+    /* Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction. */
+    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_seal, CIPHER_R_INVALID_OPERATION);
+    return 0;
+  }
+
   if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len ||
       in_len > INT_MAX) {
     /* EVP_CIPHER takes int as input. */
@@ -197,10 +158,6 @@
     return 0;
   }
 
-  if (!aead_ssl3_ensure_cipher_init(ssl3_ctx, 1)) {
-    return 0;
-  }
-
   /* Compute the MAC. This must be first in case the operation is being done
    * in-place. */
   uint8_t mac[EVP_MAX_MD_SIZE];
@@ -257,6 +214,12 @@
                          const uint8_t *ad, size_t ad_len) {
   AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
 
+  if (ssl3_ctx->cipher_ctx.encrypt) {
+    /* Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction. */
+    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_INVALID_OPERATION);
+    return 0;
+  }
+
   size_t mac_len = EVP_MD_CTX_size(&ssl3_ctx->md_ctx);
   if (in_len < mac_len) {
     OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_BAD_DECRYPT);
@@ -286,10 +249,6 @@
     return 0;
   }
 
-  if (!aead_ssl3_ensure_cipher_init(ssl3_ctx, 0)) {
-    return 0;
-  }
-
   /* Decrypt to get the plaintext + MAC + padding. */
   size_t total = 0;
   int len;
@@ -338,30 +297,35 @@
 }
 
 static int aead_rc4_md5_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
-                                  size_t key_len, size_t tag_len) {
-  return aead_ssl3_init(ctx, key, key_len, tag_len, EVP_rc4(), EVP_md5());
+                                  size_t key_len, size_t tag_len,
+                                  enum evp_aead_direction_t dir) {
+  return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_md5());
 }
 
 static int aead_rc4_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
-                                  size_t key_len, size_t tag_len) {
-  return aead_ssl3_init(ctx, key, key_len, tag_len, EVP_rc4(), EVP_sha1());
+                                   size_t key_len, size_t tag_len,
+                                   enum evp_aead_direction_t dir) {
+  return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_sha1());
 }
 
 static int aead_aes_128_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
-                                          size_t key_len, size_t tag_len) {
-  return aead_ssl3_init(ctx, key, key_len, tag_len, EVP_aes_128_cbc(),
+                                           size_t key_len, size_t tag_len,
+                                           enum evp_aead_direction_t dir) {
+  return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(),
                         EVP_sha1());
 }
 
 static int aead_aes_256_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
-                                          size_t key_len, size_t tag_len) {
-  return aead_ssl3_init(ctx, key, key_len, tag_len, EVP_aes_256_cbc(),
+                                           size_t key_len, size_t tag_len,
+                                           enum evp_aead_direction_t dir) {
+  return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(),
                         EVP_sha1());
 }
 static int aead_des_ede3_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx,
-                                           const uint8_t *key, size_t key_len,
-                                           size_t tag_len) {
-  return aead_ssl3_init(ctx, key, key_len, tag_len, EVP_des_ede3_cbc(),
+                                            const uint8_t *key, size_t key_len,
+                                            size_t tag_len,
+                                            enum evp_aead_direction_t dir) {
+  return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(),
                         EVP_sha1());
 }
 
@@ -370,6 +334,7 @@
     0,                      /* nonce len */
     MD5_DIGEST_LENGTH,      /* overhead */
     MD5_DIGEST_LENGTH,      /* max tag length */
+    NULL, /* init */
     aead_rc4_md5_ssl3_init,
     aead_ssl3_cleanup,
     aead_ssl3_seal,
@@ -381,6 +346,7 @@
     0,                      /* nonce len */
     SHA_DIGEST_LENGTH,      /* overhead */
     SHA_DIGEST_LENGTH,      /* max tag length */
+    NULL, /* init */
     aead_rc4_sha1_ssl3_init,
     aead_ssl3_cleanup,
     aead_ssl3_seal,
@@ -392,6 +358,7 @@
     0,                           /* nonce len */
     16 + SHA_DIGEST_LENGTH,      /* overhead (padding + SHA1) */
     SHA_DIGEST_LENGTH,           /* max tag length */
+    NULL, /* init */
     aead_aes_128_cbc_sha1_ssl3_init,
     aead_ssl3_cleanup,
     aead_ssl3_seal,
@@ -403,6 +370,7 @@
     0,                           /* nonce len */
     16 + SHA_DIGEST_LENGTH,      /* overhead (padding + SHA1) */
     SHA_DIGEST_LENGTH,           /* max tag length */
+    NULL, /* init */
     aead_aes_256_cbc_sha1_ssl3_init,
     aead_ssl3_cleanup,
     aead_ssl3_seal,
@@ -414,6 +382,7 @@
     0,                          /* nonce len */
     8 + SHA_DIGEST_LENGTH,      /* overhead (padding + SHA1) */
     SHA_DIGEST_LENGTH,          /* max tag length */
+    NULL, /* init */
     aead_des_ede3_cbc_sha1_ssl3_init,
     aead_ssl3_cleanup,
     aead_ssl3_seal,
diff --git a/crypto/cipher/e_tls.c b/crypto/cipher/e_tls.c
index 8ac1aae..284d56a 100644
--- a/crypto/cipher/e_tls.c
+++ b/crypto/cipher/e_tls.c
@@ -22,6 +22,7 @@
 #include <openssl/hmac.h>
 #include <openssl/mem.h>
 #include <openssl/sha.h>
+#include <openssl/type_check.h>
 
 #include "../crypto/internal.h"
 #include "internal.h"
@@ -34,37 +35,26 @@
    * separately for the constant-time CBC code. */
   uint8_t mac_key[EVP_MAX_MD_SIZE];
   uint8_t mac_key_len;
-  /* enc_key is the portion of the key used for the stream or block
-   * cipher. It is retained separately to allow the EVP_CIPHER_CTX to be
-   * initialized once the direction is known. */
-  uint8_t enc_key[EVP_MAX_KEY_LENGTH];
-  uint8_t enc_key_len;
-  /* iv is the portion of the key used for the fixed IV. It is retained
-   * separately to allow the EVP_CIPHER_CTX to be initialized once the direction
-   * is known. */
-  uint8_t iv[EVP_MAX_IV_LENGTH];
-  uint8_t iv_len;
   /* implicit_iv is one iff this is a pre-TLS-1.1 CBC cipher without an explicit
    * IV. */
   char implicit_iv;
-  char initialized;
 } AEAD_TLS_CTX;
 
+OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE < 256, mac_key_len_fits_in_uint8_t);
 
 static void aead_tls_cleanup(EVP_AEAD_CTX *ctx) {
   AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;
   EVP_CIPHER_CTX_cleanup(&tls_ctx->cipher_ctx);
   HMAC_CTX_cleanup(&tls_ctx->hmac_ctx);
   OPENSSL_cleanse(&tls_ctx->mac_key, sizeof(tls_ctx->mac_key));
-  OPENSSL_cleanse(&tls_ctx->enc_key, sizeof(tls_ctx->enc_key));
-  OPENSSL_cleanse(&tls_ctx->iv, sizeof(tls_ctx->iv));
   OPENSSL_free(tls_ctx);
   ctx->aead_state = NULL;
 }
 
 static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len,
-                         size_t tag_len, const EVP_CIPHER *cipher,
-                         const EVP_MD *md, char implicit_iv) {
+                         size_t tag_len, enum evp_aead_direction_t dir,
+			 const EVP_CIPHER *cipher, const EVP_MD *md,
+			 char implicit_iv) {
   if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH &&
       tag_len != EVP_MD_size(md)) {
     OPENSSL_PUT_ERROR(CIPHER, aead_tls_init, CIPHER_R_UNSUPPORTED_TAG_SIZE);
@@ -78,11 +68,8 @@
 
   size_t mac_key_len = EVP_MD_size(md);
   size_t enc_key_len = EVP_CIPHER_key_length(cipher);
-  size_t iv_len = implicit_iv ? EVP_CIPHER_iv_length(cipher) : 0;
-  assert(mac_key_len + enc_key_len + iv_len == key_len);
-  assert(mac_key_len < 256);
-  assert(enc_key_len < 256);
-  assert(iv_len < 256);
+  assert(mac_key_len + enc_key_len +
+         (implicit_iv ? EVP_CIPHER_iv_length(cipher) : 0) == key_len);
   /* Although EVP_rc4() is a variable-length cipher, the default key size is
    * correct for TLS. */
 
@@ -93,17 +80,15 @@
   }
   EVP_CIPHER_CTX_init(&tls_ctx->cipher_ctx);
   HMAC_CTX_init(&tls_ctx->hmac_ctx);
+  assert(mac_key_len <= EVP_MAX_MD_SIZE);
   memcpy(tls_ctx->mac_key, key, mac_key_len);
   tls_ctx->mac_key_len = (uint8_t)mac_key_len;
-  memcpy(tls_ctx->enc_key, &key[mac_key_len], enc_key_len);
-  tls_ctx->enc_key_len = (uint8_t)enc_key_len;
-  memcpy(tls_ctx->iv, &key[mac_key_len + enc_key_len], iv_len);
-  tls_ctx->iv_len = (uint8_t)iv_len;
   tls_ctx->implicit_iv = implicit_iv;
-  tls_ctx->initialized = 0;
 
   ctx->aead_state = tls_ctx;
-  if (!EVP_CipherInit_ex(&tls_ctx->cipher_ctx, cipher, NULL, NULL, NULL, 0) ||
+  if (!EVP_CipherInit_ex(&tls_ctx->cipher_ctx, cipher, NULL, &key[mac_key_len],
+                         implicit_iv ? &key[mac_key_len + enc_key_len] : NULL,
+                         dir == evp_aead_seal) ||
       !HMAC_Init_ex(&tls_ctx->hmac_ctx, key, mac_key_len, md, NULL)) {
     aead_tls_cleanup(ctx);
     return 0;
@@ -113,32 +98,6 @@
   return 1;
 }
 
-/* aead_tls_ensure_cipher_init initializes |tls_ctx| for encryption (or
- * decryption, if |encrypt| is zero). If it has already been initialized, it
- * ensures the direction matches and fails otherwise. It returns one on success
- * and zero on failure.
- *
- * Note that, unlike normal AEADs, legacy TLS AEADs may not be used concurrently
- * due to this (and bulk-cipher-internal) statefulness. */
-static int aead_tls_ensure_cipher_init(AEAD_TLS_CTX *tls_ctx, int encrypt) {
-  if (!tls_ctx->initialized) {
-    /* Finish initializing the EVP_CIPHER_CTX now that the direction is
-     * known. */
-    if (!EVP_CipherInit_ex(&tls_ctx->cipher_ctx, NULL, NULL, tls_ctx->enc_key,
-                           tls_ctx->implicit_iv ? tls_ctx->iv : NULL,
-                           encrypt)) {
-      return 0;
-    }
-    tls_ctx->initialized = 1;
-  } else if (tls_ctx->cipher_ctx.encrypt != encrypt) {
-    /* Unlike a normal AEAD, using a TLS AEAD once freezes the direction. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_ensure_cipher_init,
-                      CIPHER_R_INVALID_OPERATION);
-    return 0;
-  }
-  return 1;
-}
-
 static int aead_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out,
                          size_t *out_len, size_t max_out_len,
                          const uint8_t *nonce, size_t nonce_len,
@@ -147,6 +106,13 @@
   AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;
   size_t total = 0;
 
+  if (!tls_ctx->cipher_ctx.encrypt) {
+    /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */
+    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_INVALID_OPERATION);
+    return 0;
+
+  }
+
   if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len ||
       in_len > INT_MAX) {
     /* EVP_CIPHER takes int as input. */
@@ -169,10 +135,6 @@
     return 0;
   }
 
-  if (!aead_tls_ensure_cipher_init(tls_ctx, 1)) {
-    return 0;
-  }
-
   /* To allow for CBC mode which changes cipher length, |ad| doesn't include the
    * length for legacy ciphers. */
   uint8_t ad_extra[2];
@@ -249,6 +211,13 @@
                          const uint8_t *ad, size_t ad_len) {
   AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;
 
+  if (tls_ctx->cipher_ctx.encrypt) {
+    /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */
+    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_INVALID_OPERATION);
+    return 0;
+
+  }
+
   if (in_len < HMAC_size(&tls_ctx->hmac_ctx)) {
     OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT);
     return 0;
@@ -277,10 +246,6 @@
     return 0;
   }
 
-  if (!aead_tls_ensure_cipher_init(tls_ctx, 0)) {
-    return 0;
-  }
-
   /* Configure the explicit IV. */
   if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE &&
       !tls_ctx->implicit_iv &&
@@ -394,71 +359,76 @@
 }
 
 static int aead_rc4_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
-                                  size_t key_len, size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_rc4(), EVP_sha1(), 0);
+                                  size_t key_len, size_t tag_len,
+                                  enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_sha1(),
+                       0);
 }
 
 static int aead_aes_128_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
-                                          size_t key_len, size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_128_cbc(),
+                                          size_t key_len, size_t tag_len,
+                                          enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(),
                        EVP_sha1(), 0);
 }
 
-static int aead_aes_128_cbc_sha1_tls_implicit_iv_init(EVP_AEAD_CTX *ctx,
-                                                      const uint8_t *key,
-                                                      size_t key_len,
-                                                      size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_128_cbc(),
+static int aead_aes_128_cbc_sha1_tls_implicit_iv_init(
+    EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len,
+    enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(),
                        EVP_sha1(), 1);
 }
 
 static int aead_aes_128_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx,
                                             const uint8_t *key, size_t key_len,
-                                            size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_128_cbc(),
+                                            size_t tag_len,
+                                            enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(),
                        EVP_sha256(), 0);
 }
 
 static int aead_aes_256_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
-                                          size_t key_len, size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_256_cbc(),
+                                          size_t key_len, size_t tag_len,
+                                          enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(),
                        EVP_sha1(), 0);
 }
 
-static int aead_aes_256_cbc_sha1_tls_implicit_iv_init(EVP_AEAD_CTX *ctx,
-                                                      const uint8_t *key,
-                                                      size_t key_len,
-                                                      size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_256_cbc(),
+static int aead_aes_256_cbc_sha1_tls_implicit_iv_init(
+    EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len,
+    enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(),
                        EVP_sha1(), 1);
 }
 
 static int aead_aes_256_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx,
                                             const uint8_t *key, size_t key_len,
-                                            size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_256_cbc(),
+                                            size_t tag_len,
+                                            enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(),
                        EVP_sha256(), 0);
 }
 
 static int aead_aes_256_cbc_sha384_tls_init(EVP_AEAD_CTX *ctx,
                                             const uint8_t *key, size_t key_len,
-                                            size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_aes_256_cbc(),
+                                            size_t tag_len,
+                                            enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(),
                        EVP_sha384(), 0);
 }
 
 static int aead_des_ede3_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx,
                                            const uint8_t *key, size_t key_len,
-                                           size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_des_ede3_cbc(),
+                                           size_t tag_len,
+                                           enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(),
                        EVP_sha1(), 0);
 }
 
-static int aead_des_ede3_cbc_sha1_tls_implicit_iv_init(EVP_AEAD_CTX *ctx,
-                                                       const uint8_t *key,
-                                                       size_t key_len,
-                                                       size_t tag_len) {
-  return aead_tls_init(ctx, key, key_len, tag_len, EVP_des_ede3_cbc(),
+static int aead_des_ede3_cbc_sha1_tls_implicit_iv_init(
+    EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len,
+    enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(),
                        EVP_sha1(), 1);
 }
 
@@ -467,6 +437,7 @@
     0,                      /* nonce len */
     SHA_DIGEST_LENGTH,      /* overhead */
     SHA_DIGEST_LENGTH,      /* max tag length */
+    NULL, /* init */
     aead_rc4_sha1_tls_init,
     aead_tls_cleanup,
     aead_tls_seal,
@@ -478,6 +449,7 @@
     16,                     /* nonce len (IV) */
     16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */
     SHA_DIGEST_LENGTH,      /* max tag length */
+    NULL, /* init */
     aead_aes_128_cbc_sha1_tls_init,
     aead_tls_cleanup,
     aead_tls_seal,
@@ -489,6 +461,7 @@
     0,                           /* nonce len */
     16 + SHA_DIGEST_LENGTH,      /* overhead (padding + SHA1) */
     SHA_DIGEST_LENGTH,           /* max tag length */
+    NULL, /* init */
     aead_aes_128_cbc_sha1_tls_implicit_iv_init,
     aead_tls_cleanup,
     aead_tls_seal,
@@ -500,6 +473,7 @@
     16,                        /* nonce len (IV) */
     16 + SHA256_DIGEST_LENGTH, /* overhead (padding + SHA256) */
     SHA_DIGEST_LENGTH,         /* max tag length */
+    NULL, /* init */
     aead_aes_128_cbc_sha256_tls_init,
     aead_tls_cleanup,
     aead_tls_seal,
@@ -511,6 +485,7 @@
     16,                     /* nonce len (IV) */
     16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */
     SHA_DIGEST_LENGTH,      /* max tag length */
+    NULL, /* init */
     aead_aes_256_cbc_sha1_tls_init,
     aead_tls_cleanup,
     aead_tls_seal,
@@ -522,6 +497,7 @@
     0,                           /* nonce len */
     16 + SHA_DIGEST_LENGTH,      /* overhead (padding + SHA1) */
     SHA_DIGEST_LENGTH,           /* max tag length */
+    NULL, /* init */
     aead_aes_256_cbc_sha1_tls_implicit_iv_init,
     aead_tls_cleanup,
     aead_tls_seal,
@@ -533,6 +509,7 @@
     16,                        /* nonce len (IV) */
     16 + SHA256_DIGEST_LENGTH, /* overhead (padding + SHA256) */
     SHA_DIGEST_LENGTH,         /* max tag length */
+    NULL, /* init */
     aead_aes_256_cbc_sha256_tls_init,
     aead_tls_cleanup,
     aead_tls_seal,
@@ -544,6 +521,7 @@
     16,                        /* nonce len (IV) */
     16 + SHA384_DIGEST_LENGTH, /* overhead (padding + SHA384) */
     SHA_DIGEST_LENGTH,         /* max tag length */
+    NULL, /* init */
     aead_aes_256_cbc_sha384_tls_init,
     aead_tls_cleanup,
     aead_tls_seal,
@@ -555,6 +533,7 @@
     8,                      /* nonce len (IV) */
     8 + SHA_DIGEST_LENGTH,  /* overhead (padding + SHA1) */
     SHA_DIGEST_LENGTH,      /* max tag length */
+    NULL, /* init */
     aead_des_ede3_cbc_sha1_tls_init,
     aead_tls_cleanup,
     aead_tls_seal,
@@ -566,6 +545,7 @@
     0,                          /* nonce len */
     8 + SHA_DIGEST_LENGTH,      /* overhead (padding + SHA1) */
     SHA_DIGEST_LENGTH,          /* max tag length */
+    NULL, /* init */
     aead_des_ede3_cbc_sha1_tls_implicit_iv_init,
     aead_tls_cleanup,
     aead_tls_seal,
diff --git a/crypto/cipher/internal.h b/crypto/cipher/internal.h
index f28fd4c..2130a69 100644
--- a/crypto/cipher/internal.h
+++ b/crypto/cipher/internal.h
@@ -59,6 +59,7 @@
 
 #include <openssl/base.h>
 
+#include <openssl/aead.h>
 #include <openssl/asn1t.h>
 
 #if defined(__cplusplus)
@@ -117,6 +118,9 @@
 
   int (*init)(struct evp_aead_ctx_st *, const uint8_t *key,
               size_t key_len, size_t tag_len);
+  int (*init_with_direction)(struct evp_aead_ctx_st *, const uint8_t *key,
+			     size_t key_len, size_t tag_len,
+			     enum evp_aead_direction_t dir);
   void (*cleanup)(struct evp_aead_ctx_st *);
 
   int (*seal)(const struct evp_aead_ctx_st *ctx, uint8_t *out,
diff --git a/crypto/err/cipher.errordata b/crypto/err/cipher.errordata
index ac6a3fe..bc7666e 100644
--- a/crypto/err/cipher.errordata
+++ b/crypto/err/cipher.errordata
@@ -1,4 +1,5 @@
 CIPHER,function,100,EVP_AEAD_CTX_init
+CIPHER,function,131,EVP_AEAD_CTX_init_with_direction
 CIPHER,function,101,EVP_AEAD_CTX_open
 CIPHER,function,102,EVP_AEAD_CTX_seal
 CIPHER,function,103,EVP_CIPHER_CTX_copy
@@ -44,6 +45,7 @@
 CIPHER,reason,112,INVALID_OPERATION
 CIPHER,reason,113,IV_TOO_LARGE
 CIPHER,reason,114,NO_CIPHER_SET
+CIPHER,reason,124,NO_DIRECTION_SET
 CIPHER,reason,115,OUTPUT_ALIASES_INPUT
 CIPHER,reason,116,TAG_TOO_LARGE
 CIPHER,reason,117,TOO_LARGE
diff --git a/crypto/err/err_data.h b/crypto/err/err_data.h
index 1a68170..8297997 100644
--- a/crypto/err/err_data.h
+++ b/crypto/err/err_data.h
@@ -78,192 +78,192 @@
     0xc3d0679,
     0xc3d8681,
     0xc3e068c,
-    0x10321723,
-    0x1032973a,
-    0x10331753,
-    0x10339769,
-    0x10341779,
-    0x1034978c,
-    0x1035179a,
-    0x103597a9,
-    0x103617c9,
-    0x103697e8,
-    0x10371805,
-    0x10379822,
-    0x10381837,
-    0x10389859,
-    0x10391878,
-    0x10399897,
-    0x103a18ae,
-    0x103a98c5,
-    0x103b18ce,
-    0x103b98d9,
-    0x103c18f3,
-    0x103c98fb,
-    0x103d1903,
-    0x103d990a,
-    0x103e191d,
-    0x103e992f,
-    0x103f1942,
-    0x103f994b,
-    0x143209aa,
-    0x143289b8,
-    0x143309c4,
-    0x143389d1,
-    0x18320fea,
-    0x18329002,
-    0x18331024,
-    0x18339036,
-    0x18341047,
-    0x18349060,
-    0x18351071,
-    0x18359087,
-    0x18361097,
-    0x183690ac,
-    0x183710c5,
-    0x183790d6,
-    0x183810ec,
-    0x183890fd,
-    0x1839110f,
-    0x18399124,
-    0x183a1136,
-    0x183a9146,
-    0x183b115b,
-    0x183b9168,
-    0x183c117a,
-    0x183c9188,
-    0x183d119b,
-    0x183d91ab,
-    0x183e11c0,
-    0x183e91d1,
-    0x183f11e4,
-    0x183f91f3,
-    0x18401203,
-    0x18409210,
-    0x1841121f,
-    0x18419230,
-    0x18421243,
-    0x18429255,
-    0x18431267,
-    0x18439278,
-    0x18441289,
-    0x1844929a,
-    0x184512ab,
-    0x184592b8,
-    0x184612c6,
-    0x184692d9,
-    0x184712ed,
-    0x184792fa,
-    0x18481309,
-    0x18489318,
-    0x18491329,
-    0x18499336,
-    0x184a1344,
-    0x184a9355,
-    0x184b1366,
-    0x184b9374,
-    0x184c1384,
-    0x184c93aa,
-    0x184d13b9,
-    0x184d93c9,
-    0x184e13d9,
-    0x184e93e8,
+    0x10321744,
+    0x1032975b,
+    0x10331774,
+    0x1033978a,
+    0x1034179a,
+    0x103497ad,
+    0x103517bb,
+    0x103597ca,
+    0x103617ea,
+    0x10369809,
+    0x10371826,
+    0x10379843,
+    0x10381858,
+    0x1038987a,
+    0x10391899,
+    0x103998b8,
+    0x103a18cf,
+    0x103a98e6,
+    0x103b18ef,
+    0x103b98fa,
+    0x103c1914,
+    0x103c991c,
+    0x103d1924,
+    0x103d992b,
+    0x103e193e,
+    0x103e9950,
+    0x103f1963,
+    0x103f996c,
+    0x143209cb,
+    0x143289d9,
+    0x143309e5,
+    0x143389f2,
+    0x1832100b,
+    0x18329023,
+    0x18331045,
+    0x18339057,
+    0x18341068,
+    0x18349081,
+    0x18351092,
+    0x183590a8,
+    0x183610b8,
+    0x183690cd,
+    0x183710e6,
+    0x183790f7,
+    0x1838110d,
+    0x1838911e,
+    0x18391130,
+    0x18399145,
+    0x183a1157,
+    0x183a9167,
+    0x183b117c,
+    0x183b9189,
+    0x183c119b,
+    0x183c91a9,
+    0x183d11bc,
+    0x183d91cc,
+    0x183e11e1,
+    0x183e91f2,
+    0x183f1205,
+    0x183f9214,
+    0x18401224,
+    0x18409231,
+    0x18411240,
+    0x18419251,
+    0x18421264,
+    0x18429276,
+    0x18431288,
+    0x18439299,
+    0x184412aa,
+    0x184492bb,
+    0x184512cc,
+    0x184592d9,
+    0x184612e7,
+    0x184692fa,
+    0x1847130e,
+    0x1847931b,
+    0x1848132a,
+    0x18489339,
+    0x1849134a,
+    0x18499357,
+    0x184a1365,
+    0x184a9376,
+    0x184b1387,
+    0x184b9395,
+    0x184c13a5,
+    0x184c93cb,
+    0x184d13da,
+    0x184d93ea,
+    0x184e13fa,
+    0x184e9409,
     0x1c320699,
     0x1c3286a5,
     0x1c3306b0,
     0x1c3386bc,
-    0x203213fc,
-    0x20329407,
-    0x2033140f,
-    0x2033941b,
-    0x24321427,
-    0x24329435,
-    0x24331447,
-    0x24339456,
-    0x24341469,
-    0x2434947c,
-    0x24351493,
-    0x243594ab,
-    0x243614b9,
-    0x243694d1,
-    0x243714da,
-    0x243794ec,
-    0x24381500,
-    0x2438950d,
-    0x24391523,
-    0x2439953b,
-    0x243a1553,
-    0x243a955d,
-    0x243b1572,
-    0x243b9580,
-    0x243c1598,
-    0x243c95af,
-    0x243d15ba,
-    0x243d95c8,
-    0x28320a0a,
-    0x28328a19,
-    0x28330a24,
-    0x28338a29,
-    0x28340a34,
-    0x2c3227e7,
-    0x2c32a7f3,
-    0x2c332806,
-    0x2c33a817,
-    0x2c342830,
-    0x2c34a858,
-    0x2c35286f,
-    0x2c35a88c,
-    0x2c3628a9,
-    0x2c36a8c6,
-    0x2c3728df,
-    0x2c37a8f8,
-    0x2c38290e,
-    0x2c38a91c,
-    0x2c39292e,
-    0x2c39a94b,
-    0x2c3a2968,
-    0x2c3aa976,
-    0x2c3b2994,
-    0x2c3ba9b2,
-    0x2c3c29cd,
-    0x2c3ca9e1,
-    0x2c3d29f3,
-    0x2c3daa03,
-    0x2c3e2a11,
-    0x2c3eaa21,
-    0x2c3f2a31,
-    0x2c3faa4c,
-    0x2c402a5d,
-    0x2c40aa78,
-    0x2c412a8c,
-    0x2c41aa9f,
-    0x2c422abe,
-    0x2c42aad2,
-    0x2c432ae5,
-    0x2c43aaf4,
-    0x2c442b03,
-    0x2c44ab1a,
-    0x2c452b35,
-    0x2c45ab4d,
-    0x2c462b61,
-    0x2c46ab74,
-    0x2c472b85,
-    0x2c47ab96,
-    0x2c482ba7,
-    0x2c48abb8,
-    0x2c492bc7,
-    0x2c49abd4,
-    0x2c4a2be1,
-    0x2c4aabee,
-    0x2c4b2bf7,
-    0x2c4bac0b,
-    0x2c4c2c1a,
-    0x2c4cac28,
-    0x2c4d2c4a,
-    0x2c4dac5b,
-    0x2c4e2c6c,
-    0x2c4eac37,
-    0x2c4f2849,
+    0x2032141d,
+    0x20329428,
+    0x20331430,
+    0x2033943c,
+    0x24321448,
+    0x24329456,
+    0x24331468,
+    0x24339477,
+    0x2434148a,
+    0x2434949d,
+    0x243514b4,
+    0x243594cc,
+    0x243614da,
+    0x243694f2,
+    0x243714fb,
+    0x2437950d,
+    0x24381521,
+    0x2438952e,
+    0x24391544,
+    0x2439955c,
+    0x243a1574,
+    0x243a957e,
+    0x243b1593,
+    0x243b95a1,
+    0x243c15b9,
+    0x243c95d0,
+    0x243d15db,
+    0x243d95e9,
+    0x28320a2b,
+    0x28328a3a,
+    0x28330a45,
+    0x28338a4a,
+    0x28340a55,
+    0x2c322808,
+    0x2c32a814,
+    0x2c332827,
+    0x2c33a838,
+    0x2c342851,
+    0x2c34a879,
+    0x2c352890,
+    0x2c35a8ad,
+    0x2c3628ca,
+    0x2c36a8e7,
+    0x2c372900,
+    0x2c37a919,
+    0x2c38292f,
+    0x2c38a93d,
+    0x2c39294f,
+    0x2c39a96c,
+    0x2c3a2989,
+    0x2c3aa997,
+    0x2c3b29b5,
+    0x2c3ba9d3,
+    0x2c3c29ee,
+    0x2c3caa02,
+    0x2c3d2a14,
+    0x2c3daa24,
+    0x2c3e2a32,
+    0x2c3eaa42,
+    0x2c3f2a52,
+    0x2c3faa6d,
+    0x2c402a7e,
+    0x2c40aa99,
+    0x2c412aad,
+    0x2c41aac0,
+    0x2c422adf,
+    0x2c42aaf3,
+    0x2c432b06,
+    0x2c43ab15,
+    0x2c442b24,
+    0x2c44ab3b,
+    0x2c452b56,
+    0x2c45ab6e,
+    0x2c462b82,
+    0x2c46ab95,
+    0x2c472ba6,
+    0x2c47abb7,
+    0x2c482bc8,
+    0x2c48abd9,
+    0x2c492be8,
+    0x2c49abf5,
+    0x2c4a2c02,
+    0x2c4aac0f,
+    0x2c4b2c18,
+    0x2c4bac2c,
+    0x2c4c2c3b,
+    0x2c4cac49,
+    0x2c4d2c6b,
+    0x2c4dac7c,
+    0x2c4e2c8d,
+    0x2c4eac58,
+    0x2c4f286a,
     0x30320000,
     0x30328018,
     0x3033002c,
@@ -328,236 +328,236 @@
     0x30508404,
     0x30510413,
     0x3051841c,
-    0x3432093c,
-    0x3432894c,
-    0x34330957,
-    0x34338964,
-    0x3832096d,
-    0x38328980,
-    0x3833098a,
-    0x3833899c,
-    0x3c320a3b,
-    0x3c328a49,
-    0x3c330a60,
-    0x3c338a74,
-    0x3c340a8f,
-    0x3c348aa0,
-    0x3c350aac,
-    0x3c358ac0,
-    0x3c360ad2,
-    0x3c368afb,
-    0x3c370b08,
-    0x3c378b15,
-    0x3c380b23,
-    0x3c388b30,
-    0x3c390b3d,
-    0x3c398b61,
-    0x3c3a0b71,
-    0x3c3a8b89,
-    0x3c3b0b9e,
-    0x3c3b8bb3,
-    0x3c3c0bc0,
-    0x3c3c8bd3,
-    0x3c3d0be6,
-    0x3c3d8c0a,
-    0x3c3e0c32,
-    0x3c3e8c4b,
-    0x3c3f0c61,
-    0x3c3f8c6e,
-    0x3c400c81,
-    0x3c408c92,
-    0x3c410ca3,
-    0x3c418cbc,
-    0x3c420cd5,
-    0x3c428ceb,
-    0x3c430d08,
-    0x3c438d1e,
-    0x3c440d3a,
-    0x3c448d61,
-    0x3c450d7f,
-    0x3c458d99,
-    0x3c460db1,
-    0x3c468dc9,
-    0x3c470df4,
-    0x3c478e1f,
-    0x3c480e40,
-    0x3c488e69,
-    0x3c490e84,
-    0x3c498e9f,
-    0x3c4a0eac,
-    0x3c4a8ec3,
-    0x3c4b0eda,
-    0x3c4b8f03,
-    0x3c4c0f13,
-    0x3c4c8f1f,
-    0x3c4d0f37,
-    0x3c4d8f4a,
-    0x3c4e0f5b,
-    0x3c4e8f6c,
-    0x3c4f0f7c,
-    0x40321956,
-    0x40329970,
-    0x4033197c,
-    0x40339994,
-    0x403419b2,
-    0x403499d1,
-    0x403519e8,
-    0x40359a04,
-    0x40361a20,
-    0x40369a3a,
-    0x40371a59,
-    0x40379a78,
-    0x40381a90,
-    0x40389aad,
-    0x40391ad0,
-    0x40399aed,
-    0x403a1b0b,
-    0x403a9b1b,
-    0x403b1b30,
-    0x403b9b4c,
-    0x403c1b66,
-    0x403c9b71,
-    0x403d1b94,
-    0x403d9bb8,
-    0x403e1bce,
-    0x403e9bd8,
-    0x403f1be4,
-    0x403f9bf5,
-    0x40401c0d,
-    0x40409c15,
-    0x40411c1e,
-    0x40419c27,
-    0x40421c37,
-    0x40429c4b,
-    0x40431c56,
-    0x40439c62,
-    0x40441c7d,
-    0x40449c89,
-    0x40451c96,
-    0x40459ca9,
-    0x40461cc1,
-    0x40469cd9,
-    0x40471cef,
-    0x40479d0a,
-    0x40481d25,
-    0x40489d39,
-    0x40491d52,
-    0x40499d6b,
-    0x404a1d85,
-    0x404a9d8f,
-    0x404b1d9f,
-    0x404b9dc0,
-    0x404c1ddb,
-    0x404c9de9,
-    0x404d1df6,
-    0x404d9e0a,
-    0x404e1e22,
-    0x404e9e30,
-    0x404f1e3f,
-    0x404f9e56,
-    0x40501e68,
-    0x40509e83,
-    0x40511e9d,
-    0x40519eb2,
-    0x40521ec3,
-    0x40529ee3,
-    0x40531efe,
-    0x40539f0e,
-    0x40541f1a,
-    0x40549f2d,
-    0x40551f43,
-    0x40559f61,
-    0x40561f6e,
-    0x40569f78,
-    0x40571f86,
-    0x40579fa1,
-    0x40581fbc,
-    0x40589fdb,
-    0x40591ff0,
-    0x4059a005,
-    0x405a2022,
-    0x405aa036,
-    0x405b2052,
-    0x405ba068,
-    0x405c2085,
-    0x405ca097,
-    0x405d20ae,
-    0x405da0bf,
-    0x405e20db,
-    0x405ea0ef,
-    0x405f20ff,
-    0x405fa11b,
-    0x40602130,
-    0x4060a146,
-    0x40612163,
-    0x4061a17c,
-    0x4062218f,
-    0x4062a198,
-    0x406321a8,
-    0x4063a1b4,
-    0x406421ca,
-    0x4064a1e8,
-    0x406521fd,
-    0x4065a21a,
-    0x40662231,
-    0x4066a24f,
-    0x4067226c,
-    0x4067a283,
-    0x406822a1,
-    0x4068a2b8,
-    0x406922d0,
-    0x4069a2e1,
-    0x406a22f4,
-    0x406aa307,
-    0x406b231b,
-    0x406ba33f,
-    0x406c235a,
-    0x406ca37b,
-    0x406d239f,
-    0x406da3ba,
-    0x406e23db,
-    0x406ea3f0,
-    0x406f2409,
-    0x406fa416,
-    0x40702424,
-    0x4070a431,
-    0x4071244e,
-    0x4071a46e,
-    0x40722489,
-    0x4072a4a2,
-    0x407324b9,
-    0x4073a4d3,
-    0x407424f7,
-    0x4074a50d,
-    0x40752521,
-    0x4075a536,
-    0x40762550,
-    0x4076a562,
-    0x40772577,
-    0x4077a59d,
-    0x407825ba,
-    0x4078a5dd,
-    0x40792603,
-    0x4079a620,
-    0x407a2643,
-    0x407aa65f,
-    0x407b267b,
-    0x407ba68d,
-    0x407c269a,
-    0x407ca6a7,
-    0x407d26c4,
-    0x407da6db,
-    0x407e26f7,
-    0x407ea70d,
-    0x407f2725,
-    0x407fa738,
-    0x4080274d,
-    0x4080a766,
-    0x40812784,
-    0x4081a7a4,
-    0x408227ad,
-    0x4082a7c9,
-    0x408327d2,
+    0x3432095d,
+    0x3432896d,
+    0x34330978,
+    0x34338985,
+    0x3832098e,
+    0x383289a1,
+    0x383309ab,
+    0x383389bd,
+    0x3c320a5c,
+    0x3c328a6a,
+    0x3c330a81,
+    0x3c338a95,
+    0x3c340ab0,
+    0x3c348ac1,
+    0x3c350acd,
+    0x3c358ae1,
+    0x3c360af3,
+    0x3c368b1c,
+    0x3c370b29,
+    0x3c378b36,
+    0x3c380b44,
+    0x3c388b51,
+    0x3c390b5e,
+    0x3c398b82,
+    0x3c3a0b92,
+    0x3c3a8baa,
+    0x3c3b0bbf,
+    0x3c3b8bd4,
+    0x3c3c0be1,
+    0x3c3c8bf4,
+    0x3c3d0c07,
+    0x3c3d8c2b,
+    0x3c3e0c53,
+    0x3c3e8c6c,
+    0x3c3f0c82,
+    0x3c3f8c8f,
+    0x3c400ca2,
+    0x3c408cb3,
+    0x3c410cc4,
+    0x3c418cdd,
+    0x3c420cf6,
+    0x3c428d0c,
+    0x3c430d29,
+    0x3c438d3f,
+    0x3c440d5b,
+    0x3c448d82,
+    0x3c450da0,
+    0x3c458dba,
+    0x3c460dd2,
+    0x3c468dea,
+    0x3c470e15,
+    0x3c478e40,
+    0x3c480e61,
+    0x3c488e8a,
+    0x3c490ea5,
+    0x3c498ec0,
+    0x3c4a0ecd,
+    0x3c4a8ee4,
+    0x3c4b0efb,
+    0x3c4b8f24,
+    0x3c4c0f34,
+    0x3c4c8f40,
+    0x3c4d0f58,
+    0x3c4d8f6b,
+    0x3c4e0f7c,
+    0x3c4e8f8d,
+    0x3c4f0f9d,
+    0x40321977,
+    0x40329991,
+    0x4033199d,
+    0x403399b5,
+    0x403419d3,
+    0x403499f2,
+    0x40351a09,
+    0x40359a25,
+    0x40361a41,
+    0x40369a5b,
+    0x40371a7a,
+    0x40379a99,
+    0x40381ab1,
+    0x40389ace,
+    0x40391af1,
+    0x40399b0e,
+    0x403a1b2c,
+    0x403a9b3c,
+    0x403b1b51,
+    0x403b9b6d,
+    0x403c1b87,
+    0x403c9b92,
+    0x403d1bb5,
+    0x403d9bd9,
+    0x403e1bef,
+    0x403e9bf9,
+    0x403f1c05,
+    0x403f9c16,
+    0x40401c2e,
+    0x40409c36,
+    0x40411c3f,
+    0x40419c48,
+    0x40421c58,
+    0x40429c6c,
+    0x40431c77,
+    0x40439c83,
+    0x40441c9e,
+    0x40449caa,
+    0x40451cb7,
+    0x40459cca,
+    0x40461ce2,
+    0x40469cfa,
+    0x40471d10,
+    0x40479d2b,
+    0x40481d46,
+    0x40489d5a,
+    0x40491d73,
+    0x40499d8c,
+    0x404a1da6,
+    0x404a9db0,
+    0x404b1dc0,
+    0x404b9de1,
+    0x404c1dfc,
+    0x404c9e0a,
+    0x404d1e17,
+    0x404d9e2b,
+    0x404e1e43,
+    0x404e9e51,
+    0x404f1e60,
+    0x404f9e77,
+    0x40501e89,
+    0x40509ea4,
+    0x40511ebe,
+    0x40519ed3,
+    0x40521ee4,
+    0x40529f04,
+    0x40531f1f,
+    0x40539f2f,
+    0x40541f3b,
+    0x40549f4e,
+    0x40551f64,
+    0x40559f82,
+    0x40561f8f,
+    0x40569f99,
+    0x40571fa7,
+    0x40579fc2,
+    0x40581fdd,
+    0x40589ffc,
+    0x40592011,
+    0x4059a026,
+    0x405a2043,
+    0x405aa057,
+    0x405b2073,
+    0x405ba089,
+    0x405c20a6,
+    0x405ca0b8,
+    0x405d20cf,
+    0x405da0e0,
+    0x405e20fc,
+    0x405ea110,
+    0x405f2120,
+    0x405fa13c,
+    0x40602151,
+    0x4060a167,
+    0x40612184,
+    0x4061a19d,
+    0x406221b0,
+    0x4062a1b9,
+    0x406321c9,
+    0x4063a1d5,
+    0x406421eb,
+    0x4064a209,
+    0x4065221e,
+    0x4065a23b,
+    0x40662252,
+    0x4066a270,
+    0x4067228d,
+    0x4067a2a4,
+    0x406822c2,
+    0x4068a2d9,
+    0x406922f1,
+    0x4069a302,
+    0x406a2315,
+    0x406aa328,
+    0x406b233c,
+    0x406ba360,
+    0x406c237b,
+    0x406ca39c,
+    0x406d23c0,
+    0x406da3db,
+    0x406e23fc,
+    0x406ea411,
+    0x406f242a,
+    0x406fa437,
+    0x40702445,
+    0x4070a452,
+    0x4071246f,
+    0x4071a48f,
+    0x407224aa,
+    0x4072a4c3,
+    0x407324da,
+    0x4073a4f4,
+    0x40742518,
+    0x4074a52e,
+    0x40752542,
+    0x4075a557,
+    0x40762571,
+    0x4076a583,
+    0x40772598,
+    0x4077a5be,
+    0x407825db,
+    0x4078a5fe,
+    0x40792624,
+    0x4079a641,
+    0x407a2664,
+    0x407aa680,
+    0x407b269c,
+    0x407ba6ae,
+    0x407c26bb,
+    0x407ca6c8,
+    0x407d26e5,
+    0x407da6fc,
+    0x407e2718,
+    0x407ea72e,
+    0x407f2746,
+    0x407fa759,
+    0x4080276e,
+    0x4080a787,
+    0x408127a5,
+    0x4081a7c5,
+    0x408227ce,
+    0x4082a7ea,
+    0x408327f3,
     0x4432042a,
     0x4432843c,
     0x44330445,
@@ -576,121 +576,122 @@
     0x44398522,
     0x443a052c,
     0x443a8536,
-    0x4c3215d0,
-    0x4c3295df,
-    0x4c3315ee,
-    0x4c339607,
-    0x4c341622,
-    0x4c34963e,
-    0x4c351650,
-    0x4c35965e,
-    0x4c361673,
-    0x4c369684,
-    0x4c371692,
-    0x4c3796a0,
-    0x4c3816b2,
-    0x4c3896c2,
-    0x4c3916cc,
-    0x4c3996e4,
-    0x4c3a16fc,
-    0x4c3a970f,
-    0x50322c7d,
-    0x5032ac92,
-    0x50332ca3,
-    0x5033acb6,
-    0x50342cc7,
-    0x5034acda,
-    0x50352ce9,
-    0x5035acfe,
-    0x50362d0e,
-    0x5036ad1d,
-    0x50372d2e,
-    0x5037ad3e,
-    0x50382d4f,
-    0x5038ad62,
-    0x50392d74,
-    0x5039ad8a,
-    0x503a2d9c,
-    0x503aadad,
-    0x503b2dbe,
-    0x503badcf,
-    0x503c2dda,
-    0x503cade6,
-    0x503d2df1,
-    0x503dadfc,
-    0x503e2e09,
-    0x503eae1e,
-    0x503f2e2c,
-    0x503fae40,
-    0x50402e53,
-    0x5040ae64,
-    0x50412e7e,
-    0x5041ae8d,
-    0x50422e96,
-    0x5042aea5,
-    0x50432eb7,
-    0x5043aec3,
-    0x50442ecb,
-    0x5044aede,
-    0x50452eef,
-    0x5045af05,
-    0x50462f11,
-    0x5046af25,
-    0x50472f33,
-    0x5047af47,
-    0x50482f61,
-    0x5048af75,
-    0x50492f8b,
-    0x5049afa2,
-    0x504a2fb4,
-    0x504aafc8,
-    0x504b2fdd,
-    0x504baff4,
-    0x504c3008,
-    0x504cb011,
-    0x504d3019,
-    0x504db028,
-    0x504e3038,
-    0x68320f9d,
-    0x68328fae,
-    0x68330fbe,
-    0x68338fcc,
-    0x68340fd9,
-    0x6c320f8c,
-    0x743209e5,
-    0x743289f7,
+    0x4c3215f1,
+    0x4c329600,
+    0x4c33160f,
+    0x4c339628,
+    0x4c341643,
+    0x4c34965f,
+    0x4c351671,
+    0x4c35967f,
+    0x4c361694,
+    0x4c3696a5,
+    0x4c3716b3,
+    0x4c3796c1,
+    0x4c3816d3,
+    0x4c3896e3,
+    0x4c3916ed,
+    0x4c399705,
+    0x4c3a171d,
+    0x4c3a9730,
+    0x50322c9e,
+    0x5032acb3,
+    0x50332cc4,
+    0x5033acd7,
+    0x50342ce8,
+    0x5034acfb,
+    0x50352d0a,
+    0x5035ad1f,
+    0x50362d2f,
+    0x5036ad3e,
+    0x50372d4f,
+    0x5037ad5f,
+    0x50382d70,
+    0x5038ad83,
+    0x50392d95,
+    0x5039adab,
+    0x503a2dbd,
+    0x503aadce,
+    0x503b2ddf,
+    0x503badf0,
+    0x503c2dfb,
+    0x503cae07,
+    0x503d2e12,
+    0x503dae1d,
+    0x503e2e2a,
+    0x503eae3f,
+    0x503f2e4d,
+    0x503fae61,
+    0x50402e74,
+    0x5040ae85,
+    0x50412e9f,
+    0x5041aeae,
+    0x50422eb7,
+    0x5042aec6,
+    0x50432ed8,
+    0x5043aee4,
+    0x50442eec,
+    0x5044aeff,
+    0x50452f10,
+    0x5045af26,
+    0x50462f32,
+    0x5046af46,
+    0x50472f54,
+    0x5047af68,
+    0x50482f82,
+    0x5048af96,
+    0x50492fac,
+    0x5049afc3,
+    0x504a2fd5,
+    0x504aafe9,
+    0x504b2ffe,
+    0x504bb015,
+    0x504c3029,
+    0x504cb032,
+    0x504d303a,
+    0x504db049,
+    0x504e3059,
+    0x68320fbe,
+    0x68328fcf,
+    0x68330fdf,
+    0x68338fed,
+    0x68340ffa,
+    0x6c320fad,
+    0x74320a06,
+    0x74328a18,
     0x783206c9,
-    0x783286db,
-    0x783306ed,
-    0x783386ff,
-    0x78340713,
-    0x78348727,
-    0x78350745,
-    0x78358757,
-    0x7836076b,
-    0x7836877f,
-    0x78370791,
-    0x783787a3,
-    0x783807b5,
-    0x783887cc,
-    0x783907e3,
-    0x783987fa,
-    0x783a0816,
-    0x783a8832,
-    0x783b084e,
-    0x783b8864,
-    0x783c087a,
-    0x783c8890,
-    0x783d08ad,
-    0x783d88bc,
-    0x783e08cb,
-    0x783e88da,
-    0x783f08f6,
-    0x783f8904,
-    0x78400912,
-    0x78408920,
-    0x7841092d,
-    0x803213f7,
+    0x783286fc,
+    0x7833070e,
+    0x78338720,
+    0x78340734,
+    0x78348748,
+    0x78350766,
+    0x78358778,
+    0x7836078c,
+    0x783687a0,
+    0x783707b2,
+    0x783787c4,
+    0x783807d6,
+    0x783887ed,
+    0x78390804,
+    0x7839881b,
+    0x783a0837,
+    0x783a8853,
+    0x783b086f,
+    0x783b8885,
+    0x783c089b,
+    0x783c88b1,
+    0x783d08ce,
+    0x783d88dd,
+    0x783e08ec,
+    0x783e88fb,
+    0x783f0917,
+    0x783f8925,
+    0x78400933,
+    0x78408941,
+    0x7841094e,
+    0x784186db,
+    0x80321418,
 };
 
 static const char kFunctionStringData[] =
@@ -806,6 +807,7 @@
     "BUF_strndup\0"
     "buf_mem_grow\0"
     "EVP_AEAD_CTX_init\0"
+    "EVP_AEAD_CTX_init_with_direction\0"
     "EVP_AEAD_CTX_open\0"
     "EVP_AEAD_CTX_seal\0"
     "EVP_CIPHER_CTX_copy\0"
@@ -1352,152 +1354,152 @@
     0xc3908a5,
     0xc3988b4,
     0xc3a08c8,
-    0x10321406,
-    0x10329412,
-    0x1033142b,
-    0x1033943e,
-    0x10340d98,
-    0x10349451,
-    0x10351466,
-    0x10359479,
-    0x10361492,
-    0x103694a7,
-    0x103714c5,
-    0x103794d4,
-    0x103814f0,
-    0x1038950b,
-    0x1039151a,
-    0x10399536,
-    0x103a1551,
-    0x103a9568,
-    0x103b1579,
-    0x103b958d,
-    0x103c15ac,
-    0x103c95bb,
-    0x103d15d2,
-    0x103d95e5,
-    0x103e0b4e,
-    0x103e95f8,
-    0x103f160b,
-    0x103f9625,
-    0x10401635,
-    0x10409649,
-    0x1041165f,
-    0x10419677,
-    0x1042168c,
-    0x104296a0,
-    0x104316b2,
+    0x10321417,
+    0x10329423,
+    0x1033143c,
+    0x1033944f,
+    0x10340da9,
+    0x10349462,
+    0x10351477,
+    0x1035948a,
+    0x103614a3,
+    0x103694b8,
+    0x103714d6,
+    0x103794e5,
+    0x10381501,
+    0x1038951c,
+    0x1039152b,
+    0x10399547,
+    0x103a1562,
+    0x103a9579,
+    0x103b158a,
+    0x103b959e,
+    0x103c15bd,
+    0x103c95cc,
+    0x103d15e3,
+    0x103d95f6,
+    0x103e0b5f,
+    0x103e9609,
+    0x103f161c,
+    0x103f9636,
+    0x10401646,
+    0x1040965a,
+    0x10411670,
+    0x10419688,
+    0x1042169d,
+    0x104296b1,
+    0x104316c3,
     0x104385d0,
     0x104408b4,
-    0x104496c7,
-    0x104516de,
-    0x104596f3,
-    0x10461701,
-    0x14320b31,
-    0x14328b3f,
-    0x14330b4e,
-    0x14338b60,
+    0x104496d8,
+    0x104516ef,
+    0x10459704,
+    0x10461712,
+    0x14320b42,
+    0x14328b50,
+    0x14330b5f,
+    0x14338b71,
     0x18320083,
-    0x18328dee,
-    0x18330e04,
+    0x18328dff,
+    0x18330e15,
     0x18338094,
-    0x18340e1c,
-    0x18348e30,
-    0x18350e45,
-    0x18358e67,
-    0x18360e7f,
-    0x18368e94,
-    0x18370ea7,
-    0x18378ebb,
-    0x18380edf,
-    0x18388eed,
-    0x18390f03,
-    0x18398f17,
-    0x183a0f27,
+    0x18340e2d,
+    0x18348e41,
+    0x18350e56,
+    0x18358e78,
+    0x18360e90,
+    0x18368ea5,
+    0x18370eb8,
+    0x18378ecc,
+    0x18380ef0,
+    0x18388efe,
+    0x18390f14,
+    0x18398f28,
+    0x183a0f38,
     0x183a89cc,
-    0x183b0f37,
-    0x183b8f4c,
-    0x183c0f63,
-    0x183c8f77,
-    0x183d0f8b,
-    0x183d8f9b,
-    0x183e0b7d,
-    0x183e8fa8,
-    0x183f0fba,
-    0x183f8fc5,
-    0x18400fd5,
-    0x18408fe6,
-    0x18410ff7,
-    0x18419009,
-    0x18421032,
-    0x1842904b,
-    0x1843105a,
-    0x1843906e,
-    0x1844108f,
-    0x184490a7,
-    0x184510c3,
-    0x184590d9,
-    0x184610f4,
+    0x183b0f48,
+    0x183b8f5d,
+    0x183c0f74,
+    0x183c8f88,
+    0x183d0f9c,
+    0x183d8fac,
+    0x183e0b8e,
+    0x183e8fb9,
+    0x183f0fcb,
+    0x183f8fd6,
+    0x18400fe6,
+    0x18408ff7,
+    0x18411008,
+    0x1841901a,
+    0x18421043,
+    0x1842905c,
+    0x1843106b,
+    0x1843907f,
+    0x184410a0,
+    0x184490b8,
+    0x184510d4,
+    0x184590ea,
+    0x18461105,
     0x1846866b,
-    0x1847110f,
-    0x1847912a,
-    0x20321151,
-    0x2432115d,
+    0x18471120,
+    0x1847913b,
+    0x20321162,
+    0x2432116e,
     0x243288fa,
-    0x2433116f,
-    0x2433917c,
-    0x24341189,
-    0x2434919b,
-    0x243511aa,
-    0x243591c7,
-    0x243611d4,
-    0x243691e2,
-    0x243711f0,
-    0x243791fe,
-    0x24381207,
-    0x24389214,
-    0x24391227,
-    0x28320b71,
-    0x28328b7d,
-    0x28330b4e,
-    0x28338b90,
-    0x2c3229af,
-    0x2c32a9bd,
-    0x2c3329cf,
-    0x2c33a9e1,
-    0x2c3429f5,
-    0x2c34aa07,
-    0x2c352a22,
-    0x2c35aa34,
-    0x2c362a47,
+    0x24331180,
+    0x2433918d,
+    0x2434119a,
+    0x243491ac,
+    0x243511bb,
+    0x243591d8,
+    0x243611e5,
+    0x243691f3,
+    0x24371201,
+    0x2437920f,
+    0x24381218,
+    0x24389225,
+    0x24391238,
+    0x28320b82,
+    0x28328b8e,
+    0x28330b5f,
+    0x28338ba1,
+    0x2c3229c0,
+    0x2c32a9ce,
+    0x2c3329e0,
+    0x2c33a9f2,
+    0x2c342a06,
+    0x2c34aa18,
+    0x2c352a33,
+    0x2c35aa45,
+    0x2c362a58,
     0x2c3682f3,
-    0x2c372a54,
-    0x2c37aa66,
-    0x2c382a79,
-    0x2c38aa87,
-    0x2c392a97,
-    0x2c39aaa9,
-    0x2c3a2abd,
-    0x2c3aaace,
-    0x2c3b12e7,
-    0x2c3baadf,
-    0x2c3c2af3,
-    0x2c3cab09,
-    0x2c3d2b22,
-    0x2c3dab50,
-    0x2c3e2b5e,
-    0x2c3eab76,
-    0x2c3f2b8e,
-    0x2c3fab9b,
-    0x2c402bbe,
-    0x2c40abdd,
-    0x2c411151,
-    0x2c41abee,
-    0x2c422c01,
-    0x2c4290c3,
-    0x2c432c12,
+    0x2c372a65,
+    0x2c37aa77,
+    0x2c382a8a,
+    0x2c38aa98,
+    0x2c392aa8,
+    0x2c39aaba,
+    0x2c3a2ace,
+    0x2c3aaadf,
+    0x2c3b12f8,
+    0x2c3baaf0,
+    0x2c3c2b04,
+    0x2c3cab1a,
+    0x2c3d2b33,
+    0x2c3dab61,
+    0x2c3e2b6f,
+    0x2c3eab87,
+    0x2c3f2b9f,
+    0x2c3fabac,
+    0x2c402bcf,
+    0x2c40abee,
+    0x2c411162,
+    0x2c41abff,
+    0x2c422c12,
+    0x2c4290d4,
+    0x2c432c23,
     0x2c4386a2,
-    0x2c442b3f,
+    0x2c442b50,
     0x30320000,
     0x30328015,
     0x3033001f,
@@ -1586,239 +1588,239 @@
     0x305c8687,
     0x305d0698,
     0x305d86a2,
-    0x34320aab,
-    0x34328abf,
-    0x34330adc,
-    0x34338aef,
-    0x34340afe,
-    0x34348b1b,
+    0x34320abc,
+    0x34328ad0,
+    0x34330aed,
+    0x34338b00,
+    0x34340b0f,
+    0x34348b2c,
     0x3c320083,
-    0x3c328ba6,
-    0x3c330bbf,
-    0x3c338bda,
-    0x3c340bf7,
-    0x3c348c12,
-    0x3c350c2d,
-    0x3c358c42,
-    0x3c360c5b,
-    0x3c368c73,
-    0x3c370c84,
-    0x3c378c92,
-    0x3c380c9f,
-    0x3c388cb3,
-    0x3c390b7d,
-    0x3c398cc7,
-    0x3c3a0cdb,
+    0x3c328bb7,
+    0x3c330bd0,
+    0x3c338beb,
+    0x3c340c08,
+    0x3c348c23,
+    0x3c350c3e,
+    0x3c358c53,
+    0x3c360c6c,
+    0x3c368c84,
+    0x3c370c95,
+    0x3c378ca3,
+    0x3c380cb0,
+    0x3c388cc4,
+    0x3c390b8e,
+    0x3c398cd8,
+    0x3c3a0cec,
     0x3c3a8874,
-    0x3c3b0ceb,
-    0x3c3b8d06,
-    0x3c3c0d18,
-    0x3c3c8d2e,
-    0x3c3d0d38,
-    0x3c3d8d4c,
-    0x3c3e0d5a,
-    0x3c3e8d68,
-    0x40321718,
-    0x4032972e,
-    0x4033175c,
-    0x40339766,
-    0x4034177d,
-    0x4034979b,
-    0x403517ab,
-    0x403597bd,
-    0x403617ca,
-    0x403697d6,
-    0x403717eb,
-    0x40379800,
-    0x40381812,
-    0x4038981d,
-    0x4039182f,
-    0x40398d98,
-    0x403a183f,
-    0x403a9852,
-    0x403b1873,
-    0x403b9884,
-    0x403c1894,
+    0x3c3b0cfc,
+    0x3c3b8d17,
+    0x3c3c0d29,
+    0x3c3c8d3f,
+    0x3c3d0d49,
+    0x3c3d8d5d,
+    0x3c3e0d6b,
+    0x3c3e8d79,
+    0x40321729,
+    0x4032973f,
+    0x4033176d,
+    0x40339777,
+    0x4034178e,
+    0x403497ac,
+    0x403517bc,
+    0x403597ce,
+    0x403617db,
+    0x403697e7,
+    0x403717fc,
+    0x40379811,
+    0x40381823,
+    0x4038982e,
+    0x40391840,
+    0x40398da9,
+    0x403a1850,
+    0x403a9863,
+    0x403b1884,
+    0x403b9895,
+    0x403c18a5,
     0x403c8064,
-    0x403d18a0,
-    0x403d98bc,
-    0x403e18d2,
-    0x403e98e1,
-    0x403f18f4,
-    0x403f990e,
-    0x4040191c,
-    0x40409931,
-    0x40411945,
-    0x40419962,
-    0x4042197b,
-    0x40429996,
-    0x404319af,
-    0x404399c2,
-    0x404419d6,
-    0x404499ee,
-    0x404519fe,
-    0x40459a0c,
-    0x40461a2a,
+    0x403d18b1,
+    0x403d98cd,
+    0x403e18e3,
+    0x403e98f2,
+    0x403f1905,
+    0x403f991f,
+    0x4040192d,
+    0x40409942,
+    0x40411956,
+    0x40419973,
+    0x4042198c,
+    0x404299a7,
+    0x404319c0,
+    0x404399d3,
+    0x404419e7,
+    0x404499ff,
+    0x40451a0f,
+    0x40459a1d,
+    0x40461a3b,
     0x40468094,
-    0x40471a3f,
-    0x40479a51,
-    0x40481a75,
-    0x40489a95,
-    0x40491aa9,
-    0x40499abe,
-    0x404a1ad7,
-    0x404a9afa,
-    0x404b1b14,
-    0x404b9b32,
-    0x404c1b4d,
-    0x404c9b67,
-    0x404d1b7e,
-    0x404d9b94,
-    0x404e1bab,
-    0x404e9bc7,
-    0x404f1be3,
-    0x404f9c04,
-    0x40501c26,
-    0x40509c42,
-    0x40511c56,
-    0x40519c63,
-    0x40521c7a,
-    0x40529c8a,
-    0x40531c9a,
-    0x40539cae,
-    0x40541cc9,
-    0x40549cd9,
-    0x40551cf0,
-    0x40559cff,
-    0x40561d1a,
-    0x40569d32,
-    0x40571d4e,
-    0x40579d67,
-    0x40581d7a,
-    0x40589d8f,
-    0x40591db2,
-    0x40599dc0,
-    0x405a1dcd,
-    0x405a9de6,
-    0x405b1dfe,
-    0x405b9e11,
-    0x405c1e26,
-    0x405c9e38,
-    0x405d1e4d,
-    0x405d9e5d,
-    0x405e1e76,
-    0x405e9e8a,
-    0x405f1e9a,
-    0x405f9eb2,
-    0x40601ec3,
-    0x40609ed6,
-    0x40611ee7,
-    0x40619f05,
-    0x40621f16,
-    0x40629f23,
-    0x40631f3a,
-    0x40639f5a,
-    0x40641f71,
-    0x40649f7e,
-    0x40651f8c,
-    0x40659fae,
-    0x40661fd6,
-    0x40669feb,
-    0x40672002,
-    0x4067a013,
-    0x40682024,
-    0x4068a035,
-    0x4069204a,
-    0x4069a061,
-    0x406a2072,
-    0x406aa08b,
-    0x406b20a6,
-    0x406ba0bd,
-    0x406c20d5,
-    0x406ca0f6,
-    0x406d2109,
-    0x406da12a,
-    0x406e2145,
-    0x406ea160,
-    0x406f2181,
-    0x406fa1a7,
-    0x407021c7,
-    0x4070a1e3,
-    0x40712370,
-    0x4071a393,
-    0x407223a9,
-    0x4072a3c8,
-    0x407323e0,
-    0x4073a400,
-    0x4074262a,
-    0x4074a64f,
-    0x4075266a,
-    0x4075a689,
-    0x407626b8,
-    0x4076a6e0,
-    0x407726f9,
-    0x4077a718,
-    0x4078273d,
-    0x4078a754,
-    0x40792767,
-    0x4079a784,
+    0x40471a50,
+    0x40479a62,
+    0x40481a86,
+    0x40489aa6,
+    0x40491aba,
+    0x40499acf,
+    0x404a1ae8,
+    0x404a9b0b,
+    0x404b1b25,
+    0x404b9b43,
+    0x404c1b5e,
+    0x404c9b78,
+    0x404d1b8f,
+    0x404d9ba5,
+    0x404e1bbc,
+    0x404e9bd8,
+    0x404f1bf4,
+    0x404f9c15,
+    0x40501c37,
+    0x40509c53,
+    0x40511c67,
+    0x40519c74,
+    0x40521c8b,
+    0x40529c9b,
+    0x40531cab,
+    0x40539cbf,
+    0x40541cda,
+    0x40549cea,
+    0x40551d01,
+    0x40559d10,
+    0x40561d2b,
+    0x40569d43,
+    0x40571d5f,
+    0x40579d78,
+    0x40581d8b,
+    0x40589da0,
+    0x40591dc3,
+    0x40599dd1,
+    0x405a1dde,
+    0x405a9df7,
+    0x405b1e0f,
+    0x405b9e22,
+    0x405c1e37,
+    0x405c9e49,
+    0x405d1e5e,
+    0x405d9e6e,
+    0x405e1e87,
+    0x405e9e9b,
+    0x405f1eab,
+    0x405f9ec3,
+    0x40601ed4,
+    0x40609ee7,
+    0x40611ef8,
+    0x40619f16,
+    0x40621f27,
+    0x40629f34,
+    0x40631f4b,
+    0x40639f6b,
+    0x40641f82,
+    0x40649f8f,
+    0x40651f9d,
+    0x40659fbf,
+    0x40661fe7,
+    0x40669ffc,
+    0x40672013,
+    0x4067a024,
+    0x40682035,
+    0x4068a046,
+    0x4069205b,
+    0x4069a072,
+    0x406a2083,
+    0x406aa09c,
+    0x406b20b7,
+    0x406ba0ce,
+    0x406c20e6,
+    0x406ca107,
+    0x406d211a,
+    0x406da13b,
+    0x406e2156,
+    0x406ea171,
+    0x406f2192,
+    0x406fa1b8,
+    0x407021d8,
+    0x4070a1f4,
+    0x40712381,
+    0x4071a3a4,
+    0x407223ba,
+    0x4072a3d9,
+    0x407323f1,
+    0x4073a411,
+    0x4074263b,
+    0x4074a660,
+    0x4075267b,
+    0x4075a69a,
+    0x407626c9,
+    0x4076a6f1,
+    0x4077270a,
+    0x4077a729,
+    0x4078274e,
+    0x4078a765,
+    0x40792778,
+    0x4079a795,
     0x407a0782,
-    0x407aa796,
-    0x407b27a9,
-    0x407ba7c2,
-    0x407c27da,
-    0x407c904b,
-    0x407d27ee,
-    0x407da808,
-    0x407e2819,
-    0x407ea82d,
-    0x407f283b,
-    0x407fa856,
-    0x40801214,
-    0x4080a87b,
-    0x4081289d,
-    0x4081a8b8,
-    0x408228cd,
-    0x4082a8e5,
-    0x408328fd,
-    0x4083a914,
-    0x4084292a,
-    0x4084a936,
-    0x40852949,
-    0x4085a95e,
-    0x40862970,
-    0x4086a985,
-    0x4087298e,
-    0x41f4229b,
-    0x41f9232d,
-    0x41fe2220,
-    0x41fea451,
-    0x41ff2542,
-    0x420322b4,
-    0x420822d6,
-    0x4208a312,
-    0x42092204,
-    0x4209a34c,
-    0x420a225b,
-    0x420aa23b,
-    0x420b227b,
-    0x420ba2f4,
-    0x420c255e,
-    0x420ca41e,
-    0x420d2438,
-    0x420da46f,
-    0x42122489,
-    0x42172525,
-    0x4217a4cb,
-    0x421c24ed,
-    0x421f24a8,
-    0x42212575,
-    0x42262508,
-    0x422b260e,
-    0x422ba5d7,
-    0x422c25f6,
-    0x422ca5b1,
-    0x422d2590,
+    0x407aa7a7,
+    0x407b27ba,
+    0x407ba7d3,
+    0x407c27eb,
+    0x407c905c,
+    0x407d27ff,
+    0x407da819,
+    0x407e282a,
+    0x407ea83e,
+    0x407f284c,
+    0x407fa867,
+    0x40801225,
+    0x4080a88c,
+    0x408128ae,
+    0x4081a8c9,
+    0x408228de,
+    0x4082a8f6,
+    0x4083290e,
+    0x4083a925,
+    0x4084293b,
+    0x4084a947,
+    0x4085295a,
+    0x4085a96f,
+    0x40862981,
+    0x4086a996,
+    0x4087299f,
+    0x41f422ac,
+    0x41f9233e,
+    0x41fe2231,
+    0x41fea462,
+    0x41ff2553,
+    0x420322c5,
+    0x420822e7,
+    0x4208a323,
+    0x42092215,
+    0x4209a35d,
+    0x420a226c,
+    0x420aa24c,
+    0x420b228c,
+    0x420ba305,
+    0x420c256f,
+    0x420ca42f,
+    0x420d2449,
+    0x420da480,
+    0x4212249a,
+    0x42172536,
+    0x4217a4dc,
+    0x421c24fe,
+    0x421f24b9,
+    0x42212586,
+    0x42262519,
+    0x422b261f,
+    0x422ba5e8,
+    0x422c2607,
+    0x422ca5c2,
+    0x422d25a1,
     0x443206ad,
     0x443286bc,
     0x443306c8,
@@ -1836,103 +1838,103 @@
     0x44390782,
     0x44398790,
     0x443a07a3,
-    0x4c32123e,
-    0x4c32924e,
-    0x4c331261,
-    0x4c339281,
+    0x4c32124f,
+    0x4c32925f,
+    0x4c331272,
+    0x4c339292,
     0x4c340094,
     0x4c3480b0,
-    0x4c35128d,
-    0x4c35929b,
-    0x4c3612b7,
-    0x4c3692ca,
-    0x4c3712d9,
-    0x4c3792e7,
-    0x4c3812fc,
-    0x4c389308,
-    0x4c391328,
-    0x4c399352,
-    0x4c3a136b,
-    0x4c3a9384,
+    0x4c35129e,
+    0x4c3592ac,
+    0x4c3612c8,
+    0x4c3692db,
+    0x4c3712ea,
+    0x4c3792f8,
+    0x4c38130d,
+    0x4c389319,
+    0x4c391339,
+    0x4c399363,
+    0x4c3a137c,
+    0x4c3a9395,
     0x4c3b05d0,
-    0x4c3b939d,
-    0x4c3c13af,
-    0x4c3c93be,
-    0x4c3d104b,
-    0x4c3d93d7,
-    0x4c3e13e4,
-    0x50322c24,
-    0x5032ac33,
-    0x50332c3e,
-    0x5033ac4e,
-    0x50342c67,
-    0x5034ac81,
-    0x50352c8f,
-    0x5035aca5,
-    0x50362cb7,
-    0x5036accd,
-    0x50372ce6,
-    0x5037acf9,
-    0x50382d11,
-    0x5038ad22,
-    0x50392d37,
-    0x5039ad4b,
-    0x503a2d6b,
-    0x503aad81,
-    0x503b2d99,
-    0x503badab,
-    0x503c2dc7,
-    0x503cadde,
-    0x503d2df7,
-    0x503dae0d,
-    0x503e2e1a,
-    0x503eae30,
-    0x503f2e42,
+    0x4c3b93ae,
+    0x4c3c13c0,
+    0x4c3c93cf,
+    0x4c3d105c,
+    0x4c3d93e8,
+    0x4c3e13f5,
+    0x50322c35,
+    0x5032ac44,
+    0x50332c4f,
+    0x5033ac5f,
+    0x50342c78,
+    0x5034ac92,
+    0x50352ca0,
+    0x5035acb6,
+    0x50362cc8,
+    0x5036acde,
+    0x50372cf7,
+    0x5037ad0a,
+    0x50382d22,
+    0x5038ad33,
+    0x50392d48,
+    0x5039ad5c,
+    0x503a2d7c,
+    0x503aad92,
+    0x503b2daa,
+    0x503badbc,
+    0x503c2dd8,
+    0x503cadef,
+    0x503d2e08,
+    0x503dae1e,
+    0x503e2e2b,
+    0x503eae41,
+    0x503f2e53,
     0x503f8348,
-    0x50402e55,
-    0x5040ae65,
-    0x50412e7f,
-    0x5041ae8e,
-    0x50422ea8,
-    0x5042aec5,
-    0x50432ed5,
-    0x5043aee5,
-    0x50442ef4,
+    0x50402e66,
+    0x5040ae76,
+    0x50412e90,
+    0x5041ae9f,
+    0x50422eb9,
+    0x5042aed6,
+    0x50432ee6,
+    0x5043aef6,
+    0x50442f05,
     0x50448414,
-    0x50452f08,
-    0x5045af26,
-    0x50462f39,
-    0x5046af4f,
-    0x50472f61,
-    0x5047af76,
-    0x50482f9c,
-    0x5048afaa,
-    0x50492fbd,
-    0x5049afd2,
-    0x504a2fe8,
-    0x504aaff8,
-    0x504b3018,
-    0x504bb02b,
-    0x504c304e,
-    0x504cb07c,
-    0x504d308e,
-    0x504db0ab,
-    0x504e30c6,
-    0x504eb0e2,
-    0x504f30f4,
-    0x504fb10b,
-    0x5050311a,
+    0x50452f19,
+    0x5045af37,
+    0x50462f4a,
+    0x5046af60,
+    0x50472f72,
+    0x5047af87,
+    0x50482fad,
+    0x5048afbb,
+    0x50492fce,
+    0x5049afe3,
+    0x504a2ff9,
+    0x504ab009,
+    0x504b3029,
+    0x504bb03c,
+    0x504c305f,
+    0x504cb08d,
+    0x504d309f,
+    0x504db0bc,
+    0x504e30d7,
+    0x504eb0f3,
+    0x504f3105,
+    0x504fb11c,
+    0x5050312b,
     0x50508687,
-    0x5051312d,
-    0x58320dd6,
-    0x68320d98,
-    0x68328b7d,
-    0x68330b90,
-    0x68338da6,
-    0x68340db6,
-    0x6c320d74,
-    0x6c328b60,
-    0x6c330d7f,
+    0x5051313e,
+    0x58320de7,
+    0x68320da9,
+    0x68328b8e,
+    0x68330ba1,
+    0x68338db7,
+    0x68340dc7,
+    0x6c320d85,
+    0x6c328b71,
+    0x6c330d90,
     0x74320980,
     0x783208e5,
     0x783288fa,
@@ -1949,16 +1951,17 @@
     0x783809cc,
     0x783889de,
     0x783909eb,
-    0x783989f9,
-    0x783a0a0e,
-    0x783a8a1c,
-    0x783b0a26,
-    0x783b8a3a,
-    0x783c0a51,
-    0x783c8a66,
-    0x783d0a7d,
-    0x783d8a92,
-    0x80321140,
+    0x78398a0a,
+    0x783a0a1f,
+    0x783a8a2d,
+    0x783b0a37,
+    0x783b8a4b,
+    0x783c0a62,
+    0x783c8a77,
+    0x783d0a8e,
+    0x783d8aa3,
+    0x783e09f9,
+    0x80321151,
 };
 
 static const char kReasonStringData[] =
@@ -2098,6 +2101,7 @@
     "INVALID_OPERATION\0"
     "IV_TOO_LARGE\0"
     "NO_CIPHER_SET\0"
+    "NO_DIRECTION_SET\0"
     "OUTPUT_ALIASES_INPUT\0"
     "TAG_TOO_LARGE\0"
     "TOO_LARGE\0"
diff --git a/include/openssl/aead.h b/include/openssl/aead.h
index 6fd8116..861de99 100644
--- a/include/openssl/aead.h
+++ b/include/openssl/aead.h
@@ -205,7 +205,13 @@
  * be used. */
 #define EVP_AEAD_DEFAULT_TAG_LENGTH 0
 
-/* EVP_AEAD_init initializes |ctx| for the given AEAD algorithm from |impl|.
+/* evp_aead_direction_t denotes the direction of an AEAD operation. */
+enum evp_aead_direction_t {
+  evp_aead_open,
+  evp_aead_seal,
+};
+
+/* EVP_AEAD_CTX_init initializes |ctx| for the given AEAD algorithm from |impl|.
  * The |impl| argument may be NULL to choose the default implementation.
  * Authentication tags may be truncated by passing a size as |tag_len|. A
  * |tag_len| of zero indicates the default tag length and this is defined as
@@ -215,6 +221,13 @@
                                      const uint8_t *key, size_t key_len,
                                      size_t tag_len, ENGINE *impl);
 
+/* EVP_AEAD_CTX_init_with_direction calls |EVP_AEAD_CTX_init| for normal
+ * AEADs. For TLS-specific and SSL3-specific AEADs, it initializes |ctx| for a
+ * given direction. */
+OPENSSL_EXPORT int EVP_AEAD_CTX_init_with_direction(
+    EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, const uint8_t *key, size_t key_len,
+    size_t tag_len, enum evp_aead_direction_t dir);
+
 /* EVP_AEAD_CTX_cleanup frees any data allocated by |ctx|. */
 OPENSSL_EXPORT void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx);
 
diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h
index 97bf096..43b6cd5 100644
--- a/include/openssl/cipher.h
+++ b/include/openssl/cipher.h
@@ -530,6 +530,7 @@
 #define CIPHER_F_aead_tls_seal 128
 #define CIPHER_F_aes_init_key 129
 #define CIPHER_F_aesni_init_key 130
+#define CIPHER_F_EVP_AEAD_CTX_init_with_direction 131
 #define CIPHER_R_AES_KEY_SETUP_FAILED 100
 #define CIPHER_R_BAD_DECRYPT 101
 #define CIPHER_R_BAD_KEY_LENGTH 102
@@ -554,5 +555,6 @@
 #define CIPHER_R_UNSUPPORTED_NONCE_SIZE 121
 #define CIPHER_R_UNSUPPORTED_TAG_SIZE 122
 #define CIPHER_R_WRONG_FINAL_BLOCK_LENGTH 123
+#define CIPHER_R_NO_DIRECTION_SET 124
 
 #endif  /* OPENSSL_HEADER_CIPHER_H */
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index a3d8925..7ee810f 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -353,8 +353,9 @@
     aead_ctx = s->aead_write_ctx;
   }
 
-  if (!EVP_AEAD_CTX_init(&aead_ctx->ctx, aead, key, key_len,
-                         EVP_AEAD_DEFAULT_TAG_LENGTH, NULL /* engine */)) {
+  if (!EVP_AEAD_CTX_init_with_direction(
+          &aead_ctx->ctx, aead, key, key_len, EVP_AEAD_DEFAULT_TAG_LENGTH,
+          is_read ? evp_aead_open : evp_aead_seal)) {
     OPENSSL_free(aead_ctx);
     if (is_read) {
       s->aead_read_ctx = NULL;