diff --git a/crypto/fipsmodule/modes/xts_test.cc b/crypto/fipsmodule/modes/xts_test.cc index 2f6aebb395e..07d9eebf84d 100644 --- a/crypto/fipsmodule/modes/xts_test.cc +++ b/crypto/fipsmodule/modes/xts_test.cc @@ -14,6 +14,7 @@ #include #include +#include #include @@ -23,6 +24,8 @@ #include "internal.h" #include "../../test/test_util.h" +static constexpr size_t AESXTS_RAND_MSG_MAX_LEN = 8192; + #if defined(OPENSSL_LINUX) #include #endif @@ -1202,7 +1205,7 @@ TEST(XTSTest, TestVectors) { in_p = in.get(); out_p = out.get(); #endif - for (bool in_place : {false, true}) { + for (bool in_place : {false, true}) { SCOPED_TRACE(in_place); // Test encryption. @@ -1240,6 +1243,106 @@ TEST(XTSTest, TestVectors) { #endif } +TEST(XTSTest, EncryptDecryptRand) { +#if defined(OPENSSL_LINUX) + int pagesize = sysconf(_SC_PAGE_SIZE); + ASSERT_GE(pagesize, 0); + uint8_t *in_buffer_beg = get_buffer_beg(pagesize); + uint8_t *out_buffer_beg = get_buffer_beg(pagesize); + uint8_t *in_buffer_end = in_buffer_beg + pagesize; + uint8_t *out_buffer_end = out_buffer_beg + pagesize; +#endif + + const EVP_CIPHER *cipher = EVP_aes_256_xts(); + bssl::ScopedEVP_CIPHER_CTX ctx; + std::vector key(EVP_CIPHER_key_length(cipher)), iv(EVP_CIPHER_iv_length(cipher)); + + // Test AESXTS Encrypt and Decrypt with random messages of incremental lenghts + for (size_t msg_len = 16; msg_len < AESXTS_RAND_MSG_MAX_LEN; msg_len += 1) { + + std::vector plaintext(msg_len); + RAND_bytes(plaintext.data(), msg_len); + + SCOPED_TRACE(plaintext.size()); + + int len = 0; + uint8_t *in_p = nullptr, *out_p = nullptr; + #if defined(OPENSSL_LINUX) + std::unique_ptr in, out; + + for (bool beg: {false, true}) { + if (pagesize < (int)plaintext.size() && !beg) { + // For small page sizes skip page bound edge cases + in.reset(new uint8_t[plaintext.size()]); + out.reset(new uint8_t[plaintext.size()]); + in_p = in.get(); + out_p = out.get(); + } else if (pagesize < (int)plaintext.size() && beg) { + // Skip second iteration for small page sizes since it would use + // identical allocation for |in_p| and |out_p| buffers + continue; + } else { + if (!beg) { + in_p = in_buffer_end - plaintext.size(); + out_p = out_buffer_end - plaintext.size(); + } else { + in_p = in_buffer_end - pagesize; + out_p = out_buffer_end - pagesize; + } + OPENSSL_memset(in_p, 0x00, plaintext.size()); + OPENSSL_memset(out_p, 0x00, plaintext.size()); + } + #else + std::unique_ptr in(new uint8_t[plaintext.size()]); + std::unique_ptr out(new uint8_t[plaintext.size()]); + in_p = in.get(); + out_p = out.get(); + #endif + for (bool in_place : {false, true}) { + SCOPED_TRACE(in_place); + + // Generate random key and iv for each encryption test + RAND_bytes(key.data(), EVP_CIPHER_key_length(cipher)); + RAND_bytes(iv.data(), EVP_CIPHER_iv_length(cipher)); + + // Test encryption. + + OPENSSL_memcpy(in_p, plaintext.data(), plaintext.size()); + if (in_place) { + out_p = in_p; + } + + ctx.Reset(); + len = 0; + ASSERT_TRUE(EVP_EncryptInit_ex(ctx.get(), cipher, nullptr, key.data(), + iv.data())); + ASSERT_TRUE( + EVP_EncryptUpdate(ctx.get(), out_p, &len, in_p, plaintext.size())); + ASSERT_EQ(static_cast(len), plaintext.size()); + + // Test decryption. + + if (!in_place) { + OPENSSL_memset(in_p, 0, len); + } + + ctx.Reset(); + len = 0; + ASSERT_TRUE(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(), + iv.data())); + ASSERT_TRUE( + EVP_DecryptUpdate(ctx.get(), in_p, &len, out_p, plaintext.size())); + ASSERT_EQ(static_cast(len), plaintext.size()); + EXPECT_EQ(Bytes(plaintext), Bytes(in_p, static_cast(len))); + } + } +#if defined(OPENSSL_LINUX) + } + free_memory(in_buffer_end, pagesize); + free_memory(out_buffer_end, pagesize); +#endif +} + // Negative test for key1 = key2 TEST(XTSTest, DuplicateKey) {