blob: 405292ea0837da2253fa7eeae25925636fcc6cfe [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2013 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 "net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.h"
6
7#include "third_party/boringssl/src/include/openssl/crypto.h"
8#include "third_party/boringssl/src/include/openssl/err.h"
9#include "third_party/boringssl/src/include/openssl/evp.h"
10#include "net/third_party/quiche/src/quic/core/quic_utils.h"
11#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h"
12#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
13#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
14#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
15
16namespace quic {
17
18namespace {
19
20// In debug builds only, log OpenSSL error stack. Then clear OpenSSL error
21// stack.
22void DLogOpenSslErrors() {
23#ifdef NDEBUG
24 while (ERR_get_error()) {
25 }
26#else
27 while (unsigned long error = ERR_get_error()) {
28 char buf[120];
29 ERR_error_string_n(error, buf, QUIC_ARRAYSIZE(buf));
30 QUIC_DLOG(ERROR) << "OpenSSL error: " << buf;
31 }
32#endif
33}
34
35const EVP_AEAD* InitAndCall(const EVP_AEAD* (*aead_getter)()) {
36 // Ensure BoringSSL is initialized before calling |aead_getter|. In Chromium,
37 // the static initializer is disabled.
38 CRYPTO_library_init();
39 return aead_getter();
40}
41
42} // namespace
43
44AeadBaseEncrypter::AeadBaseEncrypter(const EVP_AEAD* (*aead_getter)(),
45 size_t key_size,
46 size_t auth_tag_size,
47 size_t nonce_size,
48 bool use_ietf_nonce_construction)
49 : aead_alg_(InitAndCall(aead_getter)),
50 key_size_(key_size),
51 auth_tag_size_(auth_tag_size),
52 nonce_size_(nonce_size),
53 use_ietf_nonce_construction_(use_ietf_nonce_construction) {
54 DCHECK_LE(key_size_, sizeof(key_));
55 DCHECK_LE(nonce_size_, sizeof(iv_));
56 DCHECK_GE(kMaxNonceSize, nonce_size_);
57}
58
59AeadBaseEncrypter::~AeadBaseEncrypter() {}
60
61bool AeadBaseEncrypter::SetKey(QuicStringPiece key) {
62 DCHECK_EQ(key.size(), key_size_);
63 if (key.size() != key_size_) {
64 return false;
65 }
66 memcpy(key_, key.data(), key.size());
67
68 EVP_AEAD_CTX_cleanup(ctx_.get());
69
70 if (!EVP_AEAD_CTX_init(ctx_.get(), aead_alg_, key_, key_size_, auth_tag_size_,
71 nullptr)) {
72 DLogOpenSslErrors();
73 return false;
74 }
75
76 return true;
77}
78
79bool AeadBaseEncrypter::SetNoncePrefix(QuicStringPiece nonce_prefix) {
80 if (use_ietf_nonce_construction_) {
81 QUIC_BUG << "Attempted to set nonce prefix on IETF QUIC crypter";
82 return false;
83 }
84 DCHECK_EQ(nonce_prefix.size(), nonce_size_ - sizeof(QuicPacketNumber));
85 if (nonce_prefix.size() != nonce_size_ - sizeof(QuicPacketNumber)) {
86 return false;
87 }
88 memcpy(iv_, nonce_prefix.data(), nonce_prefix.size());
89 return true;
90}
91
92bool AeadBaseEncrypter::SetIV(QuicStringPiece iv) {
93 if (!use_ietf_nonce_construction_) {
94 QUIC_BUG << "Attempted to set IV on Google QUIC crypter";
95 return false;
96 }
97 DCHECK_EQ(iv.size(), nonce_size_);
98 if (iv.size() != nonce_size_) {
99 return false;
100 }
101 memcpy(iv_, iv.data(), iv.size());
102 return true;
103}
104
105bool AeadBaseEncrypter::Encrypt(QuicStringPiece nonce,
106 QuicStringPiece associated_data,
107 QuicStringPiece plaintext,
108 unsigned char* output) {
109 DCHECK_EQ(nonce.size(), nonce_size_);
110
111 size_t ciphertext_len;
112 if (!EVP_AEAD_CTX_seal(
113 ctx_.get(), output, &ciphertext_len,
114 plaintext.size() + auth_tag_size_,
115 reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(),
116 reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size(),
117 reinterpret_cast<const uint8_t*>(associated_data.data()),
118 associated_data.size())) {
119 DLogOpenSslErrors();
120 return false;
121 }
122
123 return true;
124}
125
126bool AeadBaseEncrypter::EncryptPacket(uint64_t packet_number,
127 QuicStringPiece associated_data,
128 QuicStringPiece plaintext,
129 char* output,
130 size_t* output_length,
131 size_t max_output_length) {
132 size_t ciphertext_size = GetCiphertextSize(plaintext.length());
133 if (max_output_length < ciphertext_size) {
134 return false;
135 }
136 // TODO(ianswett): Introduce a check to ensure that we don't encrypt with the
137 // same packet number twice.
138 QUIC_ALIGNED(4) char nonce_buffer[kMaxNonceSize];
139 memcpy(nonce_buffer, iv_, nonce_size_);
140 size_t prefix_len = nonce_size_ - sizeof(packet_number);
141 if (use_ietf_nonce_construction_) {
142 for (size_t i = 0; i < sizeof(packet_number); ++i) {
143 nonce_buffer[prefix_len + i] ^=
144 (packet_number >> ((sizeof(packet_number) - i - 1) * 8)) & 0xff;
145 }
146 } else {
147 memcpy(nonce_buffer + prefix_len, &packet_number, sizeof(packet_number));
148 }
149
150 if (!Encrypt(QuicStringPiece(nonce_buffer, nonce_size_), associated_data,
151 plaintext, reinterpret_cast<unsigned char*>(output))) {
152 return false;
153 }
154 *output_length = ciphertext_size;
155 return true;
156}
157
158size_t AeadBaseEncrypter::GetKeySize() const {
159 return key_size_;
160}
161
162size_t AeadBaseEncrypter::GetNoncePrefixSize() const {
163 return nonce_size_ - sizeof(QuicPacketNumber);
164}
165
166size_t AeadBaseEncrypter::GetIVSize() const {
167 return nonce_size_;
168}
169
170size_t AeadBaseEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
171 return ciphertext_size - auth_tag_size_;
172}
173
174size_t AeadBaseEncrypter::GetCiphertextSize(size_t plaintext_size) const {
175 return plaintext_size + auth_tag_size_;
176}
177
178QuicStringPiece AeadBaseEncrypter::GetKey() const {
179 return QuicStringPiece(reinterpret_cast<const char*>(key_), key_size_);
180}
181
182QuicStringPiece AeadBaseEncrypter::GetNoncePrefix() const {
183 return QuicStringPiece(reinterpret_cast<const char*>(iv_),
184 GetNoncePrefixSize());
185}
186
187} // namespace quic