// Copyright 2021 Google LLC. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // /////////////////////////////////////////////////////////////////////////////// #include "tink/aead/internal/ssl_aead.h" #include #include #include #include #include #include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/container/flat_hash_set.h" #include "absl/status/status.h" #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "tink/aead/internal/wycheproof_aead.h" #include "tink/internal/fips_utils.h" #include "tink/internal/ssl_util.h" #include "tink/subtle/subtle_util.h" #include "tink/util/secret_data.h" #include "tink/util/statusor.h" #include "tink/util/test_matchers.h" namespace crypto { namespace tink { namespace internal { namespace { using ::crypto::tink::test::IsOk; using ::crypto::tink::test::StatusIs; using ::testing::AllOf; using ::testing::Eq; using ::testing::Not; using ::testing::TestParamInfo; using ::testing::TestWithParam; using ::testing::ValuesIn; constexpr absl::string_view kMessage = "Some data to encrypt."; constexpr absl::string_view kAssociatedData = "Some associated data."; // 128 bits key. constexpr absl::string_view k128Key = "000102030405060708090a0b0c0d0e0f"; // 256 bits key. constexpr absl::string_view k256Key = "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"; // 12 bytes IV. constexpr absl::string_view kAesGcmIvHex = "0123456789012345678901234"; // 24 bytes IV. constexpr absl::string_view kXchacha20Poly1305IvHex = "012345678901234567890123456789012345678901234567"; enum CipherType { kAesGcm, kAesGcmSiv, kXchacha20Poly1305, }; struct SslOneShotAeadTestParams { std::string test_name; CipherType cipher; int tag_size; absl::string_view iv_hex; absl::string_view key_hex; }; // Returns a SslOneShotAead from `cipher_name` and `key`. util::StatusOr> CipherFromName( CipherType cipher, const util::SecretData& key) { switch (cipher) { case CipherType::kAesGcm: { return CreateAesGcmOneShotCrypter(key); } case CipherType::kAesGcmSiv: { return CreateAesGcmSivOneShotCrypter(key); } case CipherType::kXchacha20Poly1305: { return CreateXchacha20Poly1305OneShotCrypter(key); } } } using SslOneShotAeadTest = TestWithParam; TEST_P(SslOneShotAeadTest, CiphertextPlaintextSize) { SslOneShotAeadTestParams test_param = GetParam(); util::StatusOr> aead = CipherFromName( test_param.cipher, util::SecretDataFromStringView( absl::HexStringToBytes(test_param.key_hex))); ASSERT_THAT(aead, IsOk()); EXPECT_EQ((*aead)->CiphertextSize(kMessage.size()), kMessage.size() + test_param.tag_size); EXPECT_EQ((*aead)->PlaintextSize(kMessage.size() + test_param.tag_size), kMessage.size()); // Minimum size. EXPECT_EQ((*aead)->PlaintextSize(test_param.tag_size), 0); // Smaller than the minumum. EXPECT_EQ((*aead)->PlaintextSize(0), 0); } // Tests that encryption of `message` with `associated_data`, and `iv` succeeds; // writes the result in `ciphertext_buffer`. void DoTestEncrypt(SslOneShotAead* aead, absl::string_view message, absl::string_view associated_data, size_t tag_size, absl::string_view iv, absl::Span ciphertext_buffer) { ASSERT_GE(ciphertext_buffer.size(), message.size() + tag_size); util::StatusOr res = aead->Encrypt( message, associated_data, iv, absl::MakeSpan(ciphertext_buffer)); ASSERT_THAT(res, IsOk()); EXPECT_EQ(*res, message.size() + tag_size); } // Tests that decryption of `ciphertext_buffer` with `associated_data` and `iv` // succeeds and equals `message`. void DoTestDecrypt(SslOneShotAead* aead, absl::string_view message, absl::string_view associated_data, absl::string_view iv, absl::string_view ciphertext_buffer) { std::string plaintext_buff; subtle::ResizeStringUninitialized(&plaintext_buff, message.size()); util::StatusOr written_bytes = aead->Decrypt( ciphertext_buffer, associated_data, iv, absl::MakeSpan(plaintext_buff)); ASSERT_THAT(written_bytes, IsOk()); EXPECT_EQ(*written_bytes, message.size()); EXPECT_EQ(plaintext_buff, message); } TEST_P(SslOneShotAeadTest, EncryptDecrypt) { SslOneShotAeadTestParams test_param = GetParam(); util::StatusOr> aead = CipherFromName( test_param.cipher, util::SecretDataFromStringView( absl::HexStringToBytes(test_param.key_hex))); ASSERT_THAT(aead, IsOk()); std::string iv = absl::HexStringToBytes(test_param.iv_hex); std::string ciphertext_buffer; // Length of the message + tag. subtle::ResizeStringUninitialized(&ciphertext_buffer, (*aead)->CiphertextSize(kMessage.size())); DoTestEncrypt(aead->get(), kMessage, kAssociatedData, test_param.tag_size, iv, absl::MakeSpan(ciphertext_buffer)); DoTestDecrypt(aead->get(), kMessage, kAssociatedData, iv, ciphertext_buffer); } // Calculates a new string with the `position`'s byte modified. std::string ModifyString(absl::string_view input_str, int position) { std::string modified(input_str.data(), input_str.size()); modified[position / 8] ^= 1 << (position % 8); return modified; } // Tests encryption/decryption with a modified ciphertext. void DoTestEncryptDecryptWithModifiedCiphertext(SslOneShotAead* aead, size_t tag_size, absl::string_view iv) { std::string ciphertext_buffer; // Length of the message + tag. subtle::ResizeStringUninitialized(&ciphertext_buffer, kMessage.size() + tag_size); util::StatusOr written_bytes = aead->Encrypt( kMessage, kAssociatedData, iv, absl::MakeSpan(ciphertext_buffer)); ASSERT_THAT(written_bytes, IsOk()); EXPECT_EQ(*written_bytes, kMessage.size() + tag_size); std::string plaintext_buffer; subtle::ResizeStringUninitialized(&plaintext_buffer, kMessage.size()); // Modify the ciphertext. for (size_t i = 0; i < ciphertext_buffer.size() * 8; i++) { EXPECT_THAT( aead->Decrypt(ModifyString(ciphertext_buffer, i), kAssociatedData, iv, absl::MakeSpan(plaintext_buffer)) .status(), Not(IsOk())) << i; } // Modify the associated data. for (size_t i = 0; i < kAssociatedData.size() * 8; i++) { EXPECT_THAT( aead->Decrypt(ciphertext_buffer, ModifyString(kAssociatedData, i), iv, absl::MakeSpan(plaintext_buffer)) .status(), Not(IsOk())) << i; } // Truncate the ciphertext. for (size_t i = 0; i < ciphertext_buffer.size(); i++) { std::string truncated_ct(ciphertext_buffer, 0, i); EXPECT_THAT(aead->Decrypt(truncated_ct, kAssociatedData, iv, absl::MakeSpan(plaintext_buffer)) .status(), Not(IsOk())) << i; } } TEST_P(SslOneShotAeadTest, TestModification) { if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } SslOneShotAeadTestParams test_param = GetParam(); util::StatusOr> aead = CipherFromName( test_param.cipher, util::SecretDataFromStringView( absl::HexStringToBytes(test_param.key_hex))); ASSERT_THAT(aead, IsOk()); DoTestEncryptDecryptWithModifiedCiphertext( aead->get(), test_param.tag_size, absl::HexStringToBytes(test_param.iv_hex)); } // Make sure that the buffer passed in to the Decrypt routine is cleared if // decryption fails. TEST_P(SslOneShotAeadTest, TestBufferClearsIfDecryptionFails) { if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } SslOneShotAeadTestParams test_param = GetParam(); util::StatusOr> aead = CipherFromName( test_param.cipher, util::SecretDataFromStringView( absl::HexStringToBytes(test_param.key_hex))); ASSERT_THAT(aead, IsOk()); const int64_t kCiphertextSize = kMessage.size() + test_param.tag_size; std::string ciphertext_buffer; // Length of the message + tag. subtle::ResizeStringUninitialized(&ciphertext_buffer, kCiphertextSize); std::string iv = absl::HexStringToBytes(test_param.iv_hex); util::StatusOr written_bytes = (*aead)->Encrypt( kMessage, kAssociatedData, iv, absl::MakeSpan(ciphertext_buffer)); ASSERT_THAT(written_bytes, IsOk()); EXPECT_EQ(*written_bytes, kCiphertextSize); std::string plaintext_buffer; subtle::ResizeStringUninitialized(&plaintext_buffer, kMessage.size()); const std::string kExpectedClearedPlaintext(plaintext_buffer.size(), '\0'); // Alter the tag. for (int i = kCiphertextSize - test_param.tag_size; i < kCiphertextSize; i++) { std::string modified_ciphertext = ModifyString(ciphertext_buffer, i); EXPECT_THAT((*aead) ->Decrypt(modified_ciphertext, kAssociatedData, iv, absl::MakeSpan(plaintext_buffer)) .status(), Not(IsOk())); EXPECT_EQ(plaintext_buffer, kExpectedClearedPlaintext); } } void TestDecryptWithEmptyAssociatedData(SslOneShotAead* aead, absl::string_view ciphertext, absl::string_view iv) { if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } std::string plaintext_buffer; subtle::ResizeStringUninitialized(&plaintext_buffer, kMessage.size()); const absl::string_view empty_associated_data; std::vector values = {empty_associated_data, absl::string_view(), ""}; for (auto& associated_data : values) { DoTestDecrypt(aead, kMessage, associated_data, iv, ciphertext); } } void DoTestWithEmptyAssociatedData(SslOneShotAead* aead, absl::string_view iv, size_t tag_size) { const absl::string_view empty_associated_data; std::vector values = {empty_associated_data, absl::string_view(), ""}; for (auto& associated_data : values) { std::string ciphertext_buffer; subtle::ResizeStringUninitialized(&ciphertext_buffer, kMessage.size() + tag_size); DoTestEncrypt(aead, kMessage, associated_data, tag_size, iv, absl::MakeSpan(ciphertext_buffer)); TestDecryptWithEmptyAssociatedData(aead, ciphertext_buffer, iv); } } TEST_P(SslOneShotAeadTest, EmptyAssociatedData) { if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } SslOneShotAeadTestParams test_param = GetParam(); util::StatusOr> aead = CipherFromName( test_param.cipher, util::SecretDataFromStringView( absl::HexStringToBytes(test_param.key_hex))); ASSERT_THAT(aead, IsOk()); DoTestWithEmptyAssociatedData(aead->get(), absl::HexStringToBytes(test_param.iv_hex), test_param.tag_size); } // string_views, with `iv` and `associated_data`. void DoTestEmptyMessageEncryptDecrypt( SslOneShotAead* aead, absl::string_view iv, size_t tag_size, absl::string_view associated_data = kAssociatedData) { std::string ciphertext_buffer; subtle::ResizeStringUninitialized(&ciphertext_buffer, tag_size); { // Message is a null string_view. const absl::string_view message; DoTestEncrypt(aead, message, associated_data, tag_size, iv, absl::MakeSpan(ciphertext_buffer)); DoTestDecrypt(aead, "", associated_data, iv, ciphertext_buffer); } { // Message is an empty string. const std::string message = ""; DoTestEncrypt(aead, message, associated_data, tag_size, iv, absl::MakeSpan(ciphertext_buffer)); DoTestDecrypt(aead, "", associated_data, iv, ciphertext_buffer); } { // Message is a default-constructed string_view. DoTestEncrypt(aead, absl::string_view(), associated_data, tag_size, iv, absl::MakeSpan(ciphertext_buffer)); DoTestDecrypt(aead, "", associated_data, iv, ciphertext_buffer); } } TEST_P(SslOneShotAeadTest, EmptyMessage) { if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } SslOneShotAeadTestParams test_param = GetParam(); util::StatusOr> aead = CipherFromName( test_param.cipher, util::SecretDataFromStringView( absl::HexStringToBytes(test_param.key_hex))); ASSERT_THAT(aead, IsOk()); std::string iv = absl::HexStringToBytes(test_param.iv_hex); DoTestEmptyMessageEncryptDecrypt(aead->get(), iv, test_param.tag_size); } TEST_P(SslOneShotAeadTest, EmptyMessageAndAssociatedData) { if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } SslOneShotAeadTestParams test_param = GetParam(); util::StatusOr> aead = CipherFromName( test_param.cipher, util::SecretDataFromStringView( absl::HexStringToBytes(test_param.key_hex))); ASSERT_THAT(aead, IsOk()); std::string iv = absl::HexStringToBytes(test_param.iv_hex); const absl::string_view default_associated_data; const absl::string_view empty_associated_data = ""; DoTestEmptyMessageEncryptDecrypt(aead->get(), iv, test_param.tag_size, default_associated_data); DoTestEmptyMessageEncryptDecrypt(aead->get(), iv, test_param.tag_size, /*associated_data=*/absl::string_view()); DoTestEmptyMessageEncryptDecrypt(aead->get(), iv, test_param.tag_size, empty_associated_data); } TEST_P(SslOneShotAeadTest, BufferOverlapEncryptFails) { SslOneShotAeadTestParams test_param = GetParam(); util::StatusOr> aead = CipherFromName( test_param.cipher, util::SecretDataFromStringView( absl::HexStringToBytes(test_param.key_hex))); ASSERT_THAT(aead, IsOk()); std::string ciphertext_buffer(kMessage.data(), kMessage.size()); subtle::ResizeStringUninitialized(&ciphertext_buffer, (*aead)->CiphertextSize(kMessage.size())); EXPECT_THAT( (*aead) ->Encrypt( absl::string_view(ciphertext_buffer).substr(0, kMessage.size()), kAssociatedData, test_param.iv_hex, absl::MakeSpan(ciphertext_buffer)) .status(), StatusIs(absl::StatusCode::kInvalidArgument)); } TEST_P(SslOneShotAeadTest, BufferOverlapDecryptFails) { SslOneShotAeadTestParams test_param = GetParam(); util::StatusOr> aead = CipherFromName( test_param.cipher, util::SecretDataFromStringView( absl::HexStringToBytes(test_param.key_hex))); ASSERT_THAT(aead, IsOk()); std::string iv = absl::HexStringToBytes(test_param.iv_hex); std::string ciphertext_buffer; // Length of the message + tag. subtle::ResizeStringUninitialized(&ciphertext_buffer, (*aead)->CiphertextSize(kMessage.size())); DoTestEncrypt(aead->get(), kMessage, kAssociatedData, test_param.tag_size, iv, absl::MakeSpan(ciphertext_buffer)); EXPECT_THAT( (*aead) ->Decrypt( ciphertext_buffer, kAssociatedData, iv, absl::MakeSpan(ciphertext_buffer).subspan(0, kMessage.size())) .status(), StatusIs(absl::StatusCode::kInvalidArgument)); } std::vector GetSslOneShotAeadTestParams() { std::vector params = { {/*test_name=*/"AesGcm256", /*cipher=*/CipherType::kAesGcm, /*tag_size=*/kAesGcmTagSizeInBytes, /*iv_hex=*/kAesGcmIvHex, /*key_hex=*/k256Key}, {/*test_name=*/"AesGcm128", /*cipher=*/CipherType::kAesGcm, /*tag_size=*/kAesGcmTagSizeInBytes, /*iv_hex=*/kAesGcmIvHex, /*key_hex=*/k128Key}}; if (IsBoringSsl()) { params.push_back({/*test_name=*/"AesGcmSiv256", /*cipher=*/CipherType::kAesGcmSiv, /*tag_size=*/kAesGcmTagSizeInBytes, /*iv_hex=*/kAesGcmIvHex, /*key_hex=*/k256Key}); params.push_back({/*test_name=*/"AesGcmSiv128", /*cipher=*/CipherType::kAesGcmSiv, /*tag_size=*/kAesGcmTagSizeInBytes, /*iv_hex=*/kAesGcmIvHex, /*key_hex=*/k128Key}); params.push_back({/*test_name=*/"Xchacha20Poly1305", /*cipher=*/CipherType::kXchacha20Poly1305, /*tag_size=*/kXchacha20Poly1305TagSizeInBytes, /*iv_hex=*/kXchacha20Poly1305IvHex, /*key_hex=*/k256Key}); } return params; } INSTANTIATE_TEST_SUITE_P( SslOneShotAeadTests, SslOneShotAeadTest, testing::ValuesIn(GetSslOneShotAeadTestParams()), [](const TestParamInfo& info) { return info.param.test_name; }); TEST(SslOneShotAeadTest, AesGcmTestInvalidKeySizes) { if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } for (int keysize = 0; keysize < 65; keysize++) { util::SecretData key(keysize, 'x'); util::StatusOr> aead = CreateAesGcmOneShotCrypter(key); if (keysize == 16 || keysize == 32) { EXPECT_THAT(aead, IsOk()) << "with key size " << keysize; } else { EXPECT_THAT(aead, Not(IsOk())) << "with key size " << keysize; } } } TEST(SslOneShotAeadTest, AesGcmSivTestInvalidKeySizes) { if (!IsBoringSsl()) { GTEST_SKIP() << "AES-GCM-SIV not supported with OpenSSL"; } if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } for (int keysize = 0; keysize < 65; keysize++) { util::SecretData key(keysize, 'x'); util::StatusOr> aead = CreateAesGcmSivOneShotCrypter(key); if (keysize == 16 || keysize == 32) { EXPECT_THAT(aead, IsOk()) << "with key size " << keysize; } else { EXPECT_THAT(aead, Not(IsOk())) << "with key size " << keysize; } } } TEST(SslOneShotAeadTest, Xchacha20Poly1305TestInvalidKeySizes) { if (!IsBoringSsl()) { GTEST_SKIP() << "Xchacha20-Poly1305 not supported with OpenSSL"; } if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } for (int keysize = 0; keysize < 65; keysize++) { util::SecretData key(keysize, 'x'); util::StatusOr> aead = CreateXchacha20Poly1305OneShotCrypter(key); if (keysize == 32) { EXPECT_THAT(aead, IsOk()) << "with key size " << keysize; } else { EXPECT_THAT(aead, Not(IsOk())) << "with key size " << keysize; } } } TEST(SslOneShotAeadTest, Xchacha20Poly1305TestFipsOnly) { if (!IsBoringSsl()) { GTEST_SKIP() << "Xchacha20-Poly1305 not supported with OpenSSL"; } if (!IsFipsModeEnabled()) { GTEST_SKIP() << "Only supported in FIPS-only mode"; } util::StatusOr> aead = CreateXchacha20Poly1305OneShotCrypter( util::SecretDataFromStringView(absl::HexStringToBytes(k256Key))); EXPECT_THAT(aead.status(), StatusIs(absl::StatusCode::kInternal)); } TEST(SslOneShotAeadTest, AesGcmTestFipsOnly) { if (IsFipsModeEnabled() && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Test should not run in FIPS mode when BoringCrypto is " "unavailable."; } util::SecretData key_128 = util::SecretDataFromStringView(absl::HexStringToBytes(k128Key)); util::SecretData key_256 = util::SecretDataFromStringView(absl::HexStringToBytes(k256Key)); EXPECT_THAT(CreateAesGcmOneShotCrypter(key_128), IsOk()); EXPECT_THAT(CreateAesGcmOneShotCrypter(key_256), IsOk()); } TEST(SslOneShotAeadTest, AesGcmTestTestFipsFailWithoutBoringCrypto) { if (!IsFipsModeEnabled() || IsFipsEnabledInSsl()) { GTEST_SKIP() << "Test assumes kOnlyUseFips but BoringCrypto is unavailable."; } util::SecretData key_128 = util::SecretDataFromStringView(absl::HexStringToBytes(k128Key)); util::SecretData key_256 = util::SecretDataFromStringView(absl::HexStringToBytes(k256Key)); EXPECT_THAT(CreateAesGcmOneShotCrypter(key_128).status(), StatusIs(absl::StatusCode::kInternal)); EXPECT_THAT(CreateAesGcmOneShotCrypter(key_256).status(), StatusIs(absl::StatusCode::kInternal)); } TEST(AesGcmSivBoringSslTest, AesGcmTestSivTestFipsOnly) { if (!IsFipsModeEnabled()) { GTEST_SKIP() << "Only supported in FIPS-only mode"; } util::SecretData key_128 = util::SecretDataFromStringView(absl::HexStringToBytes(k128Key)); util::SecretData key_256 = util::SecretDataFromStringView(absl::HexStringToBytes(k256Key)); EXPECT_THAT(CreateAesGcmSivOneShotCrypter(key_128).status(), StatusIs(absl::StatusCode::kInternal)); EXPECT_THAT(CreateAesGcmSivOneShotCrypter(key_256).status(), StatusIs(absl::StatusCode::kInternal)); } // Parameters for SslOneShotAeadWycheproofTest. struct SslOneShotAeadWycheproofTestParams { std::string test_name; CipherType cipher; int nonce_size; int tag_size; absl::flat_hash_set key_sizes; WycheproofTestVector test_vector; }; class SslOneShotAeadWycheproofTest : public TestWithParam { public: void SetUp() override { if (IsFipsModeEnabled()) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } SslOneShotAeadWycheproofTestParams params = GetParam(); const WycheproofTestVector& test_vector = params.test_vector; if (!params.key_sizes.contains(test_vector.key.size()) || test_vector.nonce.size() != params.nonce_size || test_vector.tag.size() != params.tag_size) { GTEST_SKIP() << "Unsupported parameters; key size: " << test_vector.key.size() << " nonce size: " << test_vector.nonce.size() << " tag size: " << test_vector.tag.size(); } } }; TEST_P(SslOneShotAeadWycheproofTest, Encrypt) { SslOneShotAeadWycheproofTestParams params = GetParam(); const WycheproofTestVector& test_vector = params.test_vector; util::SecretData key = util::SecretDataFromStringView(test_vector.key); util::StatusOr> aead = CipherFromName(params.cipher, key); ASSERT_THAT(aead, IsOk()); std::string ciphertext_and_tag = absl::StrCat(test_vector.ct, test_vector.tag); std::string ciphertext_buffer; subtle::ResizeStringUninitialized( &ciphertext_buffer, (*aead)->CiphertextSize(test_vector.msg.size())); util::StatusOr written_bytes = (*aead)->Encrypt(test_vector.msg, test_vector.aad, test_vector.nonce, absl::MakeSpan(ciphertext_buffer)); std::string expected_ciphertext = absl::StrCat(test_vector.ct, test_vector.tag); std::cout << test_vector.expected << "\n"; if (test_vector.expected == "valid" || test_vector.expected == "acceptable") { ASSERT_THAT(written_bytes, IsOk()); EXPECT_EQ(ciphertext_buffer, expected_ciphertext); } else { // invalid. // In this case, if the resulting ciphertext/tag are different, the // testcase is correct. if (written_bytes.ok()) { EXPECT_THAT(ciphertext_buffer, Not(Eq(expected_ciphertext))); } else { GTEST_SUCCEED(); } } } TEST_P(SslOneShotAeadWycheproofTest, Decrypt) { SslOneShotAeadWycheproofTestParams params = GetParam(); const WycheproofTestVector& test_vector = params.test_vector; util::SecretData key = util::SecretDataFromStringView(test_vector.key); util::StatusOr> aead = CipherFromName(params.cipher, key); ASSERT_THAT(aead, IsOk()); std::string ciphertext_and_tag = absl::StrCat(test_vector.ct, test_vector.tag); std::string plaintext_buffer; subtle::ResizeStringUninitialized( &plaintext_buffer, (*aead)->PlaintextSize(ciphertext_and_tag.size())); util::StatusOr written_bytes = (*aead)->Decrypt( absl::StrCat(test_vector.ct, test_vector.tag), test_vector.aad, test_vector.nonce, absl::MakeSpan(plaintext_buffer)); if (written_bytes.ok()) { EXPECT_NE(test_vector.expected, "invalid"); EXPECT_EQ(plaintext_buffer, test_vector.msg); } else { EXPECT_THAT(test_vector.expected, Not(AllOf(Eq("valid"), Eq("acceptable")))) << "Could not decrypt valid/acceptable tId: " << test_vector.id << " iv_size: " << test_vector.nonce.size() << " tag_size: " << test_vector.tag.size() << " key_size: " << key.size() << "; error: " << written_bytes.status(); } } std::vector GetWycheproofTestParams() { std::vector params; for (const WycheproofTestVector& test_vector : ReadWycheproofTestVectors("aes_gcm_test.json")) { params.push_back({/*test_name=*/"AesGcm", /*cipher_name=*/CipherType::kAesGcm, /*nonce_size=*/12, /*tag_size=*/16, /*key_sizes=*/{16, 32}, test_vector}); } if (IsBoringSsl()) { for (const WycheproofTestVector& test_vector : ReadWycheproofTestVectors("aes_gcm_siv_test.json")) { params.push_back({/*test_name=*/"AesGcmSiv", /*cipher_name=*/CipherType::kAesGcmSiv, /*nonce_size=*/12, /*tag_size=*/16, /*key_sizes=*/{16, 32}, test_vector}); } for (const WycheproofTestVector& test_vector : ReadWycheproofTestVectors("xchacha20_poly1305_test.json")) { params.push_back({/*test_name=*/"Xchacha20Poly1305", /*cipher_name=*/CipherType::kXchacha20Poly1305, /*nonce_size=*/24, /*tag_size=*/16, /*key_sizes=*/{32}, test_vector}); } } return params; } INSTANTIATE_TEST_SUITE_P( SslOneShotAeadWycheproofTests, SslOneShotAeadWycheproofTest, ValuesIn(GetWycheproofTestParams()), [](const TestParamInfo& info) { return absl::StrCat(info.param.test_name, "Tid", info.param.test_vector.id); }); } // namespace } // namespace internal } // namespace tink } // namespace crypto