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)); + } + } + } + }); }