Run EVP_CIPHER tests in-place.

I had a bug that was only caught in ssl_test. This would have caught it
in crypto_test (although only via Wycheproof test vectors; our
EVP_CIPHER CBC test vectors are all short.)

Change-Id: I8dc1457796cb6a8c0be808639657ce74967225ad
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/39205
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/cipher_extra/cipher_test.cc b/crypto/cipher_extra/cipher_test.cc
index a28e6e3..5ff308c 100644
--- a/crypto/cipher_extra/cipher_test.cc
+++ b/crypto/cipher_extra/cipher_test.cc
@@ -118,7 +118,8 @@
 }
 
 static bool DoCipher(EVP_CIPHER_CTX *ctx, std::vector<uint8_t> *out,
-                     bssl::Span<const uint8_t> in, size_t chunk) {
+                     bssl::Span<const uint8_t> in, size_t chunk,
+                     bool in_place) {
   size_t max_out = in.size();
   if ((EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_NO_PADDING) == 0 &&
       EVP_CIPHER_CTX_encrypting(ctx)) {
@@ -126,6 +127,10 @@
     max_out += block_size - (max_out % block_size);
   }
   out->resize(max_out);
+  if (in_place) {
+    std::copy(in.begin(), in.end(), out->begin());
+    in = bssl::MakeConstSpan(out->data(), in.size());
+  }
 
   size_t total = 0;
   int len;
@@ -150,7 +155,7 @@
 }
 
 static void TestOperation(FileTest *t, const EVP_CIPHER *cipher, bool encrypt,
-                          bool copy, size_t chunk_size,
+                          bool copy, bool in_place, size_t chunk_size,
                           const std::vector<uint8_t> &key,
                           const std::vector<uint8_t> &iv,
                           const std::vector<uint8_t> &plaintext,
@@ -207,7 +212,7 @@
   }
   ASSERT_TRUE(EVP_CIPHER_CTX_set_padding(ctx, 0));
   std::vector<uint8_t> result;
-  ASSERT_TRUE(DoCipher(ctx, &result, *in, chunk_size));
+  ASSERT_TRUE(DoCipher(ctx, &result, *in, chunk_size, in_place));
   EXPECT_EQ(Bytes(*out), Bytes(result));
   if (encrypt && is_aead) {
     uint8_t rtag[16];
@@ -257,21 +262,24 @@
 
   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) {
-      SCOPED_TRACE("encrypt");
-      TestOperation(t, cipher, true /* encrypt */, false /* no copy */,
-                    chunk_size, key, iv, plaintext, ciphertext, aad, tag);
-      TestOperation(t, cipher, true /* encrypt */, true /* copy */, chunk_size,
-                    key, iv, plaintext, ciphertext, aad, tag);
-    }
+    for (bool copy : {false, true}) {
+      SCOPED_TRACE(copy);
+      for (bool in_place : {false, true}) {
+        SCOPED_TRACE(in_place);
+        // By default, both directions are run, unless overridden by the
+        // operation.
+        if (operation != kDecrypt) {
+          SCOPED_TRACE("encrypt");
+          TestOperation(t, cipher, true /* encrypt */, copy, in_place,
+                        chunk_size, key, iv, plaintext, ciphertext, aad, tag);
+        }
 
-    if (operation != kEncrypt) {
-      SCOPED_TRACE("decrypt");
-      TestOperation(t, cipher, false /* decrypt */, false /* no copy */,
-                    chunk_size, key, iv, plaintext, ciphertext, aad, tag);
-      TestOperation(t, cipher, false /* decrypt */, true /* copy */, chunk_size,
-                    key, iv, plaintext, ciphertext, aad, tag);
+        if (operation != kEncrypt) {
+          SCOPED_TRACE("decrypt");
+          TestOperation(t, cipher, false /* decrypt */, copy, in_place,
+                        chunk_size, key, iv, plaintext, ciphertext, aad, tag);
+        }
+      }
     }
   }
 }
@@ -319,59 +327,63 @@
 }
 
 TEST(CipherTest, WycheproofAESCBC) {
-  FileTestGTest("third_party/wycheproof_testvectors/aes_cbc_pkcs5_test.txt",
-                [](FileTest *t) {
-    t->IgnoreInstruction("type");
-    t->IgnoreInstruction("ivSize");
+  FileTestGTest(
+      "third_party/wycheproof_testvectors/aes_cbc_pkcs5_test.txt",
+      [](FileTest *t) {
+        t->IgnoreInstruction("type");
+        t->IgnoreInstruction("ivSize");
 
-    std::string key_size;
-    ASSERT_TRUE(t->GetInstruction(&key_size, "keySize"));
-    const EVP_CIPHER *cipher;
-    switch (atoi(key_size.c_str())) {
-      case 128:
-        cipher = EVP_aes_128_cbc();
-        break;
-      case 192:
-        cipher = EVP_aes_192_cbc();
-        break;
-      case 256:
-        cipher = EVP_aes_256_cbc();
-        break;
-      default:
-        FAIL() << "Unsupported key size: " << key_size;
-    }
+        std::string key_size;
+        ASSERT_TRUE(t->GetInstruction(&key_size, "keySize"));
+        const EVP_CIPHER *cipher;
+        switch (atoi(key_size.c_str())) {
+          case 128:
+            cipher = EVP_aes_128_cbc();
+            break;
+          case 192:
+            cipher = EVP_aes_192_cbc();
+            break;
+          case 256:
+            cipher = EVP_aes_256_cbc();
+            break;
+          default:
+            FAIL() << "Unsupported key size: " << key_size;
+        }
 
-    std::vector<uint8_t> key, iv, msg, ct;
-    ASSERT_TRUE(t->GetBytes(&key, "key"));
-    ASSERT_TRUE(t->GetBytes(&iv, "iv"));
-    ASSERT_TRUE(t->GetBytes(&msg, "msg"));
-    ASSERT_TRUE(t->GetBytes(&ct, "ct"));
-    ASSERT_EQ(EVP_CIPHER_key_length(cipher), key.size());
-    ASSERT_EQ(EVP_CIPHER_iv_length(cipher), iv.size());
-    WycheproofResult result;
-    ASSERT_TRUE(GetWycheproofResult(t, &result));
+        std::vector<uint8_t> key, iv, msg, ct;
+        ASSERT_TRUE(t->GetBytes(&key, "key"));
+        ASSERT_TRUE(t->GetBytes(&iv, "iv"));
+        ASSERT_TRUE(t->GetBytes(&msg, "msg"));
+        ASSERT_TRUE(t->GetBytes(&ct, "ct"));
+        ASSERT_EQ(EVP_CIPHER_key_length(cipher), key.size());
+        ASSERT_EQ(EVP_CIPHER_iv_length(cipher), iv.size());
+        WycheproofResult result;
+        ASSERT_TRUE(GetWycheproofResult(t, &result));
 
-    bssl::ScopedEVP_CIPHER_CTX ctx;
-    std::vector<uint8_t> out;
-    const std::vector<size_t> chunk_sizes = {0,  1,  2,  5,  7,  8,  9,  15, 16,
-                                             17, 31, 32, 33, 63, 64, 65, 512};
-    for (size_t chunk : chunk_sizes) {
-      SCOPED_TRACE(chunk);
-      if (result.IsValid()) {
-        ASSERT_TRUE(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(),
-                                       iv.data()));
-        ASSERT_TRUE(DoCipher(ctx.get(), &out, ct, chunk));
-        EXPECT_EQ(Bytes(msg), Bytes(out));
+        bssl::ScopedEVP_CIPHER_CTX ctx;
+        std::vector<uint8_t> out;
+        const std::vector<size_t> chunk_sizes = {
+            0, 1, 2, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 512};
+        for (size_t chunk : chunk_sizes) {
+          SCOPED_TRACE(chunk);
+          for (bool in_place : {false, true}) {
+            SCOPED_TRACE(in_place);
+            if (result.IsValid()) {
+              ASSERT_TRUE(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr,
+                                             key.data(), iv.data()));
+              ASSERT_TRUE(DoCipher(ctx.get(), &out, ct, chunk, in_place));
+              EXPECT_EQ(Bytes(msg), Bytes(out));
 
-        ASSERT_TRUE(EVP_EncryptInit_ex(ctx.get(), cipher, nullptr, key.data(),
-                                       iv.data()));
-        ASSERT_TRUE(DoCipher(ctx.get(), &out, msg, chunk));
-        EXPECT_EQ(Bytes(ct), Bytes(out));
-      } else {
-        ASSERT_TRUE(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(),
-                                       iv.data()));
-        EXPECT_FALSE(DoCipher(ctx.get(), &out, ct, chunk));
-      }
-    }
-  });
+              ASSERT_TRUE(EVP_EncryptInit_ex(ctx.get(), cipher, nullptr,
+                                             key.data(), iv.data()));
+              ASSERT_TRUE(DoCipher(ctx.get(), &out, msg, chunk, in_place));
+              EXPECT_EQ(Bytes(ct), Bytes(out));
+            } else {
+              ASSERT_TRUE(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr,
+                                             key.data(), iv.data()));
+              EXPECT_FALSE(DoCipher(ctx.get(), &out, ct, chunk, in_place));
+            }
+          }
+        }
+      });
 }