blob: ad9fea1a09847cb9e5ef6342c5ee57d430cc9791 [file] [log] [blame]
Bence Békybac04052022-04-07 15:44:29 -04001// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "quiche/quic/tools/simple_ticket_crypter.h"
6
vasilvvdaa2fda2022-04-11 14:08:36 -07007#include "openssl/aead.h"
8#include "openssl/rand.h"
Bence Békybac04052022-04-07 15:44:29 -04009
10namespace quic {
11
12namespace {
13
14constexpr QuicTime::Delta kTicketKeyLifetime =
15 QuicTime::Delta::FromSeconds(60 * 60 * 24 * 7);
16
17// The format of an encrypted ticket is 1 byte for the key epoch, followed by
18// 16 bytes of IV, followed by the output from the AES-GCM Seal operation. The
19// seal operation has an overhead of 16 bytes for its auth tag.
20constexpr size_t kEpochSize = 1;
21constexpr size_t kIVSize = 16;
22constexpr size_t kAuthTagSize = 16;
23
24// Offsets into the ciphertext to make message parsing easier.
25constexpr size_t kIVOffset = kEpochSize;
26constexpr size_t kMessageOffset = kIVOffset + kIVSize;
27
28} // namespace
29
30SimpleTicketCrypter::SimpleTicketCrypter(QuicClock* clock) : clock_(clock) {
31 RAND_bytes(&key_epoch_, 1);
32 current_key_ = NewKey();
33}
34
35SimpleTicketCrypter::~SimpleTicketCrypter() = default;
36
37size_t SimpleTicketCrypter::MaxOverhead() {
38 return kEpochSize + kIVSize + kAuthTagSize;
39}
40
41std::vector<uint8_t> SimpleTicketCrypter::Encrypt(
42 absl::string_view in, absl::string_view encryption_key) {
43 // This class is only used in Chromium, in which the |encryption_key| argument
44 // will never be populated and an internally-cached key should be used for
45 // encrypting tickets.
46 QUICHE_DCHECK(encryption_key.empty());
47 MaybeRotateKeys();
48 std::vector<uint8_t> out(in.size() + MaxOverhead());
49 out[0] = key_epoch_;
50 RAND_bytes(out.data() + kIVOffset, kIVSize);
51 size_t out_len;
52 const EVP_AEAD_CTX* ctx = current_key_->aead_ctx.get();
53 if (!EVP_AEAD_CTX_seal(ctx, out.data() + kMessageOffset, &out_len,
54 out.size() - kMessageOffset, out.data() + kIVOffset,
55 kIVSize, reinterpret_cast<const uint8_t*>(in.data()),
56 in.size(), nullptr, 0)) {
57 return std::vector<uint8_t>();
58 }
59 out.resize(out_len + kMessageOffset);
60 return out;
61}
62
63std::vector<uint8_t> SimpleTicketCrypter::Decrypt(absl::string_view in) {
64 MaybeRotateKeys();
65 if (in.size() < kMessageOffset) {
66 return std::vector<uint8_t>();
67 }
68 const uint8_t* input = reinterpret_cast<const uint8_t*>(in.data());
69 std::vector<uint8_t> out(in.size() - kMessageOffset);
70 size_t out_len;
71 const EVP_AEAD_CTX* ctx = current_key_->aead_ctx.get();
72 if (input[0] != key_epoch_) {
73 if (input[0] == static_cast<uint8_t>(key_epoch_ - 1) && previous_key_) {
74 ctx = previous_key_->aead_ctx.get();
75 } else {
76 return std::vector<uint8_t>();
77 }
78 }
79 if (!EVP_AEAD_CTX_open(ctx, out.data(), &out_len, out.size(),
80 input + kIVOffset, kIVSize, input + kMessageOffset,
81 in.size() - kMessageOffset, nullptr, 0)) {
82 return std::vector<uint8_t>();
83 }
84 out.resize(out_len);
85 return out;
86}
87
88void SimpleTicketCrypter::Decrypt(
89 absl::string_view in,
QUICHE team5fab28c2022-05-10 12:08:49 -070090 std::shared_ptr<quic::ProofSource::DecryptCallback> callback) {
Bence Békybac04052022-04-07 15:44:29 -040091 callback->Run(Decrypt(in));
92}
93
94void SimpleTicketCrypter::MaybeRotateKeys() {
95 QuicTime now = clock_->ApproximateNow();
96 if (current_key_->expiration < now) {
97 previous_key_ = std::move(current_key_);
98 current_key_ = NewKey();
99 key_epoch_++;
100 }
101}
102
103std::unique_ptr<SimpleTicketCrypter::Key> SimpleTicketCrypter::NewKey() {
104 auto key = std::make_unique<SimpleTicketCrypter::Key>();
105 RAND_bytes(key->key, kKeySize);
106 EVP_AEAD_CTX_init(key->aead_ctx.get(), EVP_aead_aes_128_gcm(), key->key,
107 kKeySize, EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr);
108 key->expiration = clock_->ApproximateNow() + kTicketKeyLifetime;
109 return key;
110}
111
112} // namespace quic