/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include "NSSRandomAccessCipherStrategy.h" #include "gtest/gtest.h" namespace mozilla::dom::quota::test { constexpr uint64_t kBlockNumber = 8; template std::array MakeTestData(uint8_t aInitialValue = 1) { auto data = std::array{}; std::iota(data.begin(), data.end(), aInitialValue); return data; } std::array MakeTestKey(uint8_t aInitialValue = 1) { return MakeTestData<32>(aInitialValue); } std::array MakeTestNonce(uint8_t aInitialValue = 1) { return MakeTestData<12>(aInitialValue); } std::array MakeTestAad(uint8_t aInitialValue = 1) { return MakeTestData<32 + 8>(aInitialValue); } std::array MakeTestPlaintext(uint8_t aInitialValue = 1) { return MakeTestData<4032>(aInitialValue); } struct EncryptionTestData { std::array mKey; std::array mNonce; std::array mAad; std::array mPlaintext; std::array mCipherText; std::array mTag; }; EncryptionTestData MakeEncryptionTestData() { return {MakeTestKey(), MakeTestNonce(), MakeTestAad(), MakeTestPlaintext(), std::array{}, std::array{}}; } TEST(EncryptedNSSRandomAccessCipherStrategyTest, cipherTextIsDifferentFromOriginalPayload) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res = cipherStrategy.Encrypt(encryptionInput, encryptionOutput); ASSERT_EQ(res, NS_OK); ASSERT_NE(Span(data.mPlaintext), Span(data.mCipherText)); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, payloadRoundTrip) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput, encryptionOutput); ASSERT_EQ(res1, NS_OK); auto decryptionInput = NSSRandomAccessCipherStrategy::DecryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mCipherText), Span(data.mAad), Span(data.mTag)}; auto decryptedText = std::array{}; auto decryptionOutput = NSSRandomAccessCipherStrategy::DecryptionOutput{ Span(decryptedText)}; auto res2 = cipherStrategy.Decrypt(decryptionInput, decryptionOutput); ASSERT_EQ(res2, NS_OK); ASSERT_EQ(Span(data.mPlaintext), Span(decryptedText)); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, failureOfDecryptionOfBlockWithWrongBlockNumber) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput, encryptionOutput); ASSERT_EQ(res1, NS_OK); auto decryptionInput = NSSRandomAccessCipherStrategy::DecryptionInput{ data.mKey, kBlockNumber + 1, Span(data.mNonce), Span(data.mCipherText), Span(data.mAad), Span(data.mTag)}; auto decryptedText = std::array{}; auto decryptionOutput = NSSRandomAccessCipherStrategy::DecryptionOutput{ Span(decryptedText)}; auto res2 = cipherStrategy.Decrypt(decryptionInput, decryptionOutput); ASSERT_NE(res2, NS_OK); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, failureOfDecryptionOfBlockWithWrongAAD) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput, encryptionOutput); ASSERT_EQ(res1, NS_OK); auto wrongAad = MakeTestAad(2); auto decryptionInput = NSSRandomAccessCipherStrategy::DecryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mCipherText), Span(wrongAad), Span(data.mTag)}; auto decryptedText = std::array{}; auto decryptionOutput = NSSRandomAccessCipherStrategy::DecryptionOutput{ Span(decryptedText)}; auto res2 = cipherStrategy.Decrypt(decryptionInput, decryptionOutput); ASSERT_NE(res2, NS_OK); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, failureOfDecryptionOfBlockWithWrongKey) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput, encryptionOutput); ASSERT_EQ(res1, NS_OK); auto wrongKey = data.mKey; wrongKey[0] ^= 0xFF; auto decryptionInput = NSSRandomAccessCipherStrategy::DecryptionInput{ wrongKey, kBlockNumber, Span(data.mNonce), Span(data.mCipherText), Span(data.mAad), Span(data.mTag)}; auto decryptedText = std::array{}; auto decryptionOutput = NSSRandomAccessCipherStrategy::DecryptionOutput{ Span(decryptedText)}; auto res2 = cipherStrategy.Decrypt(decryptionInput, decryptionOutput); ASSERT_NE(res2, NS_OK); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, failureOfDecryptionOfBlockWithWrongNonce) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput, encryptionOutput); ASSERT_EQ(res1, NS_OK); auto wrongNonce = MakeTestNonce(2); auto decryptionInput = NSSRandomAccessCipherStrategy::DecryptionInput{ data.mKey, kBlockNumber, Span(wrongNonce), Span(data.mCipherText), Span(data.mAad), Span(data.mTag)}; auto decryptedText = std::array{}; auto decryptionOutput = NSSRandomAccessCipherStrategy::DecryptionOutput{ Span(decryptedText)}; auto res2 = cipherStrategy.Decrypt(decryptionInput, decryptionOutput); ASSERT_NE(res2, NS_OK); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, failureOfDecryptionOfBlockWithWrongTag) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput, encryptionOutput); ASSERT_EQ(res1, NS_OK); auto wrongTag = MakeTestData<16>(2); auto decryptionInput = NSSRandomAccessCipherStrategy::DecryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mCipherText), Span(data.mAad), Span(wrongTag)}; auto decryptedText = std::array{}; auto decryptionOutput = NSSRandomAccessCipherStrategy::DecryptionOutput{ Span(decryptedText)}; auto res2 = cipherStrategy.Decrypt(decryptionInput, decryptionOutput); ASSERT_NE(res2, NS_OK); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, failureOfDecryptionOfBlockWithTweakedCipherText) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput, encryptionOutput); ASSERT_EQ(res1, NS_OK); auto tweakedCipherText = data.mCipherText; tweakedCipherText[0] ^= 0xFF; auto decryptionInput = NSSRandomAccessCipherStrategy::DecryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(tweakedCipherText), Span(data.mAad), Span(data.mTag)}; auto decryptedText = std::array{}; auto decryptionOutput = NSSRandomAccessCipherStrategy::DecryptionOutput{ Span(decryptedText)}; auto res2 = cipherStrategy.Decrypt(decryptionInput, decryptionOutput); ASSERT_NE(res2, NS_OK); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, differentNonceLeadsToDifferentCipherText) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput1 = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput1 = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput1, encryptionOutput1); ASSERT_EQ(res1, NS_OK); auto data2 = MakeEncryptionTestData(); data2.mNonce = MakeTestNonce(2); auto encryptionInput2 = NSSRandomAccessCipherStrategy::EncryptionInput{ data2.mKey, kBlockNumber, Span(data2.mNonce), Span(data2.mPlaintext), Span(data2.mAad)}; auto encryptionOutput2 = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data2.mCipherText), Span(data2.mTag)}; auto res2 = cipherStrategy.Encrypt(encryptionInput2, encryptionOutput2); ASSERT_EQ(res2, NS_OK); ASSERT_NE(Span(data.mCipherText), Span(data2.mCipherText)); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, differentBlockNumberLeadsToDifferentCipherText) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput1 = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput1 = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput1, encryptionOutput1); ASSERT_EQ(res1, NS_OK); auto data2 = MakeEncryptionTestData(); auto encryptionInput2 = NSSRandomAccessCipherStrategy::EncryptionInput{ data2.mKey, kBlockNumber + 1, Span(data2.mNonce), Span(data2.mPlaintext), Span(data2.mAad)}; auto encryptionOutput2 = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data2.mCipherText), Span(data2.mTag)}; auto res2 = cipherStrategy.Encrypt(encryptionInput2, encryptionOutput2); ASSERT_EQ(res2, NS_OK); ASSERT_NE(Span(data.mCipherText), Span(data2.mCipherText)); } TEST(EncryptedNSSRandomAccessCipherStrategyTest, differentKeyLeadsToDifferentCipherText) { NSSRandomAccessCipherStrategy cipherStrategy; cipherStrategy.Init(); auto data = MakeEncryptionTestData(); auto encryptionInput1 = NSSRandomAccessCipherStrategy::EncryptionInput{ data.mKey, kBlockNumber, Span(data.mNonce), Span(data.mPlaintext), Span(data.mAad)}; auto encryptionOutput1 = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data.mCipherText), Span(data.mTag)}; auto res1 = cipherStrategy.Encrypt(encryptionInput1, encryptionOutput1); ASSERT_EQ(res1, NS_OK); auto data2 = MakeEncryptionTestData(); data2.mKey[0] ^= 0xFF; auto encryptionInput2 = NSSRandomAccessCipherStrategy::EncryptionInput{ data2.mKey, kBlockNumber, Span(data2.mNonce), Span(data2.mPlaintext), Span(data2.mAad)}; auto encryptionOutput2 = NSSRandomAccessCipherStrategy::EncryptionOutput{ Span(data2.mCipherText), Span(data2.mTag)}; auto res2 = cipherStrategy.Encrypt(encryptionInput2, encryptionOutput2); ASSERT_EQ(res2, NS_OK); ASSERT_NE(Span(data.mCipherText), Span(data2.mCipherText)); } } // namespace mozilla::dom::quota::test