blob: 0399047703ec314e872cc5fd6c18757f6693f18b [file] [log] [blame]
// 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 "quiche/quic/tools/simple_ticket_crypter.h"
#include "quiche/quic/platform/api/quic_test.h"
#include "quiche/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