|  | // 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 "net/third_party/quiche/src/quic/tools/simple_ticket_crypter.h" | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | 
|  | #include "net/third_party/quiche/src/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<uint8_t>* out) : out_(out) {} | 
|  |  | 
|  | void Run(std::vector<uint8_t> plaintext) override { *out_ = plaintext; } | 
|  |  | 
|  | private: | 
|  | std::vector<uint8_t>* out_; | 
|  | }; | 
|  |  | 
|  | absl::string_view StringPiece(const std::vector<uint8_t>& in) { | 
|  | return absl::string_view(reinterpret_cast<const char*>(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<uint8_t> plaintext = {1, 2, 3, 4, 5}; | 
|  | std::vector<uint8_t> ciphertext = | 
|  | ticket_crypter_.Encrypt(StringPiece(plaintext)); | 
|  | EXPECT_NE(plaintext, ciphertext); | 
|  |  | 
|  | std::vector<uint8_t> out_plaintext; | 
|  | ticket_crypter_.Decrypt(StringPiece(ciphertext), | 
|  | std::make_unique<DecryptCallback>(&out_plaintext)); | 
|  | EXPECT_EQ(out_plaintext, plaintext); | 
|  | } | 
|  |  | 
|  | TEST_F(SimpleTicketCrypterTest, CiphertextsDiffer) { | 
|  | std::vector<uint8_t> plaintext = {1, 2, 3, 4, 5}; | 
|  | std::vector<uint8_t> ciphertext1 = | 
|  | ticket_crypter_.Encrypt(StringPiece(plaintext)); | 
|  | std::vector<uint8_t> ciphertext2 = | 
|  | ticket_crypter_.Encrypt(StringPiece(plaintext)); | 
|  | EXPECT_NE(ciphertext1, ciphertext2); | 
|  | } | 
|  |  | 
|  | TEST_F(SimpleTicketCrypterTest, DecryptionFailureWithModifiedCiphertext) { | 
|  | std::vector<uint8_t> plaintext = {1, 2, 3, 4, 5}; | 
|  | std::vector<uint8_t> 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<uint8_t> munged_ciphertext = ciphertext; | 
|  | munged_ciphertext[i] ^= 1; | 
|  | std::vector<uint8_t> out_plaintext; | 
|  | ticket_crypter_.Decrypt(StringPiece(munged_ciphertext), | 
|  | std::make_unique<DecryptCallback>(&out_plaintext)); | 
|  | EXPECT_TRUE(out_plaintext.empty()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(SimpleTicketCrypterTest, DecryptionFailureWithEmptyCiphertext) { | 
|  | std::vector<uint8_t> out_plaintext; | 
|  | ticket_crypter_.Decrypt(absl::string_view(), | 
|  | std::make_unique<DecryptCallback>(&out_plaintext)); | 
|  | EXPECT_TRUE(out_plaintext.empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(SimpleTicketCrypterTest, KeyRotation) { | 
|  | std::vector<uint8_t> plaintext = {1, 2, 3}; | 
|  | std::vector<uint8_t> 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<uint8_t> out_plaintext; | 
|  | ticket_crypter_.Decrypt(StringPiece(ciphertext), | 
|  | std::make_unique<DecryptCallback>(&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<DecryptCallback>(&out_plaintext)); | 
|  | EXPECT_TRUE(out_plaintext.empty()); | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace quic |