// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "quic/tools/simple_ticket_crypter.h" #include "quic/platform/api/quic_test.h" #include "quic/test_tools/mock_clock.h" namespace quic { namespace test { namespace { constexpr QuicTime::Delta kOneDay = QuicTime::Delta::FromSeconds(60 * 60 * 24); } // namespace class DecryptCallback : public quic::ProofSource::DecryptCallback { public: explicit DecryptCallback(std::vector* out) : out_(out) {} void Run(std::vector plaintext) override { *out_ = plaintext; } private: std::vector* out_; }; absl::string_view StringPiece(const std::vector& in) { return absl::string_view(reinterpret_cast(in.data()), in.size()); } class SimpleTicketCrypterTest : public QuicTest { public: SimpleTicketCrypterTest() : ticket_crypter_(&mock_clock_) {} protected: MockClock mock_clock_; SimpleTicketCrypter ticket_crypter_; }; TEST_F(SimpleTicketCrypterTest, EncryptDecrypt) { std::vector plaintext = {1, 2, 3, 4, 5}; std::vector ciphertext = ticket_crypter_.Encrypt(StringPiece(plaintext)); EXPECT_NE(plaintext, ciphertext); std::vector out_plaintext; ticket_crypter_.Decrypt(StringPiece(ciphertext), std::make_unique(&out_plaintext)); EXPECT_EQ(out_plaintext, plaintext); } TEST_F(SimpleTicketCrypterTest, CiphertextsDiffer) { std::vector plaintext = {1, 2, 3, 4, 5}; std::vector ciphertext1 = ticket_crypter_.Encrypt(StringPiece(plaintext)); std::vector ciphertext2 = ticket_crypter_.Encrypt(StringPiece(plaintext)); EXPECT_NE(ciphertext1, ciphertext2); } TEST_F(SimpleTicketCrypterTest, DecryptionFailureWithModifiedCiphertext) { std::vector plaintext = {1, 2, 3, 4, 5}; std::vector ciphertext = ticket_crypter_.Encrypt(StringPiece(plaintext)); EXPECT_NE(plaintext, ciphertext); // Check that a bit flip in any byte will cause a decryption failure. for (size_t i = 0; i < ciphertext.size(); i++) { SCOPED_TRACE(i); std::vector munged_ciphertext = ciphertext; munged_ciphertext[i] ^= 1; std::vector out_plaintext; ticket_crypter_.Decrypt(StringPiece(munged_ciphertext), std::make_unique(&out_plaintext)); EXPECT_TRUE(out_plaintext.empty()); } } TEST_F(SimpleTicketCrypterTest, DecryptionFailureWithEmptyCiphertext) { std::vector out_plaintext; ticket_crypter_.Decrypt(absl::string_view(), std::make_unique(&out_plaintext)); EXPECT_TRUE(out_plaintext.empty()); } TEST_F(SimpleTicketCrypterTest, KeyRotation) { std::vector plaintext = {1, 2, 3}; std::vector ciphertext = ticket_crypter_.Encrypt(StringPiece(plaintext)); EXPECT_FALSE(ciphertext.empty()); // Advance the clock 8 days, so the key used for |ciphertext| is now the // previous key. Check that decryption still works. mock_clock_.AdvanceTime(kOneDay * 8); std::vector out_plaintext; ticket_crypter_.Decrypt(StringPiece(ciphertext), std::make_unique(&out_plaintext)); EXPECT_EQ(out_plaintext, plaintext); // Advance the clock 8 more days. Now the original key should be expired and // decryption should fail. mock_clock_.AdvanceTime(kOneDay * 8); ticket_crypter_.Decrypt(StringPiece(ciphertext), std::make_unique(&out_plaintext)); EXPECT_TRUE(out_plaintext.empty()); } } // namespace test } // namespace quic