xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/tools/simple_ticket_crypter.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // 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 
7 #include "openssl/aead.h"
8 #include "openssl/rand.h"
9 
10 namespace quic {
11 
12 namespace {
13 
14 constexpr 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.
20 constexpr size_t kEpochSize = 1;
21 constexpr size_t kIVSize = 16;
22 constexpr size_t kAuthTagSize = 16;
23 
24 // Offsets into the ciphertext to make message parsing easier.
25 constexpr size_t kIVOffset = kEpochSize;
26 constexpr size_t kMessageOffset = kIVOffset + kIVSize;
27 
28 }  // namespace
29 
SimpleTicketCrypter(QuicClock * clock)30 SimpleTicketCrypter::SimpleTicketCrypter(QuicClock* clock) : clock_(clock) {
31   RAND_bytes(&key_epoch_, 1);
32   current_key_ = NewKey();
33 }
34 
35 SimpleTicketCrypter::~SimpleTicketCrypter() = default;
36 
MaxOverhead()37 size_t SimpleTicketCrypter::MaxOverhead() {
38   return kEpochSize + kIVSize + kAuthTagSize;
39 }
40 
Encrypt(absl::string_view in,absl::string_view encryption_key)41 std::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 
Decrypt(absl::string_view in)63 std::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 
Decrypt(absl::string_view in,std::shared_ptr<quic::ProofSource::DecryptCallback> callback)88 void SimpleTicketCrypter::Decrypt(
89     absl::string_view in,
90     std::shared_ptr<quic::ProofSource::DecryptCallback> callback) {
91   callback->Run(Decrypt(in));
92 }
93 
MaybeRotateKeys()94 void 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 
NewKey()103 std::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
113