1*e7b1675dSTing-Kang Chang // Copyright 2021 Google LLC.
2*e7b1675dSTing-Kang Chang //
3*e7b1675dSTing-Kang Chang // Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang // you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang // You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang //
7*e7b1675dSTing-Kang Chang // http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang //
9*e7b1675dSTing-Kang Chang // Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang // distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang // See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang // limitations under the License.
14*e7b1675dSTing-Kang Chang //
15*e7b1675dSTing-Kang Chang ///////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang #include "tink/aead/internal/ssl_aead.h"
17*e7b1675dSTing-Kang Chang
18*e7b1675dSTing-Kang Chang #include <algorithm>
19*e7b1675dSTing-Kang Chang #include <cstdint>
20*e7b1675dSTing-Kang Chang #include <limits>
21*e7b1675dSTing-Kang Chang #include <memory>
22*e7b1675dSTing-Kang Chang #include <string>
23*e7b1675dSTing-Kang Chang #include <utility>
24*e7b1675dSTing-Kang Chang
25*e7b1675dSTing-Kang Chang #include "absl/cleanup/cleanup.h"
26*e7b1675dSTing-Kang Chang #include "absl/memory/memory.h"
27*e7b1675dSTing-Kang Chang #include "absl/status/status.h"
28*e7b1675dSTing-Kang Chang #include "absl/strings/str_cat.h"
29*e7b1675dSTing-Kang Chang #include "absl/strings/string_view.h"
30*e7b1675dSTing-Kang Chang #include "absl/types/span.h"
31*e7b1675dSTing-Kang Chang #include "openssl/crypto.h"
32*e7b1675dSTing-Kang Chang #include "openssl/evp.h"
33*e7b1675dSTing-Kang Chang #include "tink/aead/internal/aead_util.h"
34*e7b1675dSTing-Kang Chang #include "tink/internal/err_util.h"
35*e7b1675dSTing-Kang Chang #include "tink/internal/ssl_unique_ptr.h"
36*e7b1675dSTing-Kang Chang #include "tink/internal/util.h"
37*e7b1675dSTing-Kang Chang #include "tink/util/secret_data.h"
38*e7b1675dSTing-Kang Chang #include "tink/util/status.h"
39*e7b1675dSTing-Kang Chang #include "tink/util/statusor.h"
40*e7b1675dSTing-Kang Chang
41*e7b1675dSTing-Kang Chang namespace crypto {
42*e7b1675dSTing-Kang Chang namespace tink {
43*e7b1675dSTing-Kang Chang namespace internal {
44*e7b1675dSTing-Kang Chang
45*e7b1675dSTing-Kang Chang ABSL_CONST_INIT const int kXchacha20Poly1305TagSizeInBytes = 16;
46*e7b1675dSTing-Kang Chang ABSL_CONST_INIT const int kAesGcmTagSizeInBytes = 16;
47*e7b1675dSTing-Kang Chang ABSL_CONST_INIT const int kAesGcmSivTagSizeInBytes = 16;
48*e7b1675dSTing-Kang Chang
49*e7b1675dSTing-Kang Chang namespace {
50*e7b1675dSTing-Kang Chang
51*e7b1675dSTing-Kang Chang // Encrypts/Decrypts `data` and writes the result into `out`. The direction
52*e7b1675dSTing-Kang Chang // (encrypt/decrypt) is given by `context`. `out` is assumed to be large enough
53*e7b1675dSTing-Kang Chang // to hold the encrypted/decrypted content.
UpdateCipher(EVP_CIPHER_CTX * context,absl::string_view data,absl::Span<char> out)54*e7b1675dSTing-Kang Chang util::StatusOr<int64_t> UpdateCipher(EVP_CIPHER_CTX *context,
55*e7b1675dSTing-Kang Chang absl::string_view data,
56*e7b1675dSTing-Kang Chang absl::Span<char> out) {
57*e7b1675dSTing-Kang Chang // We encrypt/decrypt in chunks of at most MAX int.
58*e7b1675dSTing-Kang Chang const int64_t kMaxChunkSize = std::numeric_limits<int>::max();
59*e7b1675dSTing-Kang Chang // Keep track of the bytes written to out.
60*e7b1675dSTing-Kang Chang int64_t total_written_bytes = 0;
61*e7b1675dSTing-Kang Chang // In practical cases data.size() is assumed to fit into a int64_t.
62*e7b1675dSTing-Kang Chang int64_t left_to_update = data.size();
63*e7b1675dSTing-Kang Chang while (left_to_update > 0) {
64*e7b1675dSTing-Kang Chang const int chunk_size = std::min(kMaxChunkSize, left_to_update);
65*e7b1675dSTing-Kang Chang auto *buffer_ptr =
66*e7b1675dSTing-Kang Chang reinterpret_cast<uint8_t *>(out.data() + total_written_bytes);
67*e7b1675dSTing-Kang Chang absl::string_view data_chunk = data.substr(total_written_bytes, chunk_size);
68*e7b1675dSTing-Kang Chang int written_bytes = 0;
69*e7b1675dSTing-Kang Chang if (EVP_CipherUpdate(context, buffer_ptr, &written_bytes,
70*e7b1675dSTing-Kang Chang reinterpret_cast<const uint8_t *>(data_chunk.data()),
71*e7b1675dSTing-Kang Chang data_chunk.size()) <= 0) {
72*e7b1675dSTing-Kang Chang const bool is_encrypting = EVP_CIPHER_CTX_encrypting(context) == 1;
73*e7b1675dSTing-Kang Chang return util::Status(
74*e7b1675dSTing-Kang Chang absl::StatusCode::kInternal,
75*e7b1675dSTing-Kang Chang absl::StrCat(is_encrypting ? "Encryption" : "Decryption", " failed"));
76*e7b1675dSTing-Kang Chang }
77*e7b1675dSTing-Kang Chang left_to_update -= written_bytes;
78*e7b1675dSTing-Kang Chang total_written_bytes += written_bytes;
79*e7b1675dSTing-Kang Chang }
80*e7b1675dSTing-Kang Chang return total_written_bytes;
81*e7b1675dSTing-Kang Chang }
82*e7b1675dSTing-Kang Chang
83*e7b1675dSTing-Kang Chang class OpenSslOneShotAeadImpl : public SslOneShotAead {
84*e7b1675dSTing-Kang Chang public:
OpenSslOneShotAeadImpl(const util::SecretData & key,const EVP_CIPHER * cipher,size_t tag_size)85*e7b1675dSTing-Kang Chang explicit OpenSslOneShotAeadImpl(const util::SecretData &key,
86*e7b1675dSTing-Kang Chang const EVP_CIPHER *cipher, size_t tag_size)
87*e7b1675dSTing-Kang Chang : key_(key), cipher_(cipher), tag_size_(tag_size) {}
88*e7b1675dSTing-Kang Chang
Encrypt(absl::string_view plaintext,absl::string_view associated_data,absl::string_view iv,absl::Span<char> out) const89*e7b1675dSTing-Kang Chang util::StatusOr<int64_t> Encrypt(absl::string_view plaintext,
90*e7b1675dSTing-Kang Chang absl::string_view associated_data,
91*e7b1675dSTing-Kang Chang absl::string_view iv,
92*e7b1675dSTing-Kang Chang absl::Span<char> out) const override {
93*e7b1675dSTing-Kang Chang absl::string_view plaintext_data = internal::EnsureStringNonNull(plaintext);
94*e7b1675dSTing-Kang Chang absl::string_view ad = internal::EnsureStringNonNull(associated_data);
95*e7b1675dSTing-Kang Chang
96*e7b1675dSTing-Kang Chang const int64_t min_out_buff_size = CiphertextSize(plaintext.size());
97*e7b1675dSTing-Kang Chang if (out.size() < min_out_buff_size) {
98*e7b1675dSTing-Kang Chang return util::Status(
99*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
100*e7b1675dSTing-Kang Chang absl::StrCat("Encryption buffer too small; expected at least ",
101*e7b1675dSTing-Kang Chang min_out_buff_size, " bytes, got ", out.size()));
102*e7b1675dSTing-Kang Chang }
103*e7b1675dSTing-Kang Chang
104*e7b1675dSTing-Kang Chang if (BuffersOverlap(plaintext, absl::string_view(out.data(), out.size()))) {
105*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
106*e7b1675dSTing-Kang Chang "Plaintext and output buffer must not overlap");
107*e7b1675dSTing-Kang Chang }
108*e7b1675dSTing-Kang Chang
109*e7b1675dSTing-Kang Chang if (associated_data.size() > std::numeric_limits<int>::max()) {
110*e7b1675dSTing-Kang Chang return util::Status(
111*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
112*e7b1675dSTing-Kang Chang absl::StrCat("Associated data too large; expected at most ",
113*e7b1675dSTing-Kang Chang std::numeric_limits<int>::max(), " got ",
114*e7b1675dSTing-Kang Chang associated_data.size()));
115*e7b1675dSTing-Kang Chang }
116*e7b1675dSTing-Kang Chang
117*e7b1675dSTing-Kang Chang util::StatusOr<internal::SslUniquePtr<EVP_CIPHER_CTX>> context =
118*e7b1675dSTing-Kang Chang GetContext(iv, /*encryption=*/true);
119*e7b1675dSTing-Kang Chang if (!context.ok()) {
120*e7b1675dSTing-Kang Chang return context.status();
121*e7b1675dSTing-Kang Chang }
122*e7b1675dSTing-Kang Chang
123*e7b1675dSTing-Kang Chang // Set the associated data.
124*e7b1675dSTing-Kang Chang int len = 0;
125*e7b1675dSTing-Kang Chang if (EVP_EncryptUpdate(context->get(), /*out=*/nullptr, &len,
126*e7b1675dSTing-Kang Chang reinterpret_cast<const uint8_t *>(ad.data()),
127*e7b1675dSTing-Kang Chang ad.size()) <= 0) {
128*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal,
129*e7b1675dSTing-Kang Chang "Failed to set associated data");
130*e7b1675dSTing-Kang Chang }
131*e7b1675dSTing-Kang Chang
132*e7b1675dSTing-Kang Chang util::StatusOr<int64_t> raw_ciphertext_bytes =
133*e7b1675dSTing-Kang Chang UpdateCipher(context->get(), plaintext_data, out);
134*e7b1675dSTing-Kang Chang if (!raw_ciphertext_bytes.ok()) {
135*e7b1675dSTing-Kang Chang return raw_ciphertext_bytes.status();
136*e7b1675dSTing-Kang Chang }
137*e7b1675dSTing-Kang Chang
138*e7b1675dSTing-Kang Chang if (EVP_EncryptFinal_ex(context->get(), /*out=*/nullptr, &len) <= 0) {
139*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal, "Finalization failed");
140*e7b1675dSTing-Kang Chang }
141*e7b1675dSTing-Kang Chang
142*e7b1675dSTing-Kang Chang // Write the tag after the ciphertext.
143*e7b1675dSTing-Kang Chang absl::Span<char> tag = out.subspan(*raw_ciphertext_bytes, tag_size_);
144*e7b1675dSTing-Kang Chang if (EVP_CIPHER_CTX_ctrl(context->get(), EVP_CTRL_AEAD_GET_TAG, tag_size_,
145*e7b1675dSTing-Kang Chang reinterpret_cast<uint8_t *>(tag.data())) <= 0) {
146*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal, "Failed to get the tag");
147*e7b1675dSTing-Kang Chang }
148*e7b1675dSTing-Kang Chang return *raw_ciphertext_bytes + tag_size_;
149*e7b1675dSTing-Kang Chang }
150*e7b1675dSTing-Kang Chang
Decrypt(absl::string_view ciphertext,absl::string_view associated_data,absl::string_view iv,absl::Span<char> out) const151*e7b1675dSTing-Kang Chang util::StatusOr<int64_t> Decrypt(absl::string_view ciphertext,
152*e7b1675dSTing-Kang Chang absl::string_view associated_data,
153*e7b1675dSTing-Kang Chang absl::string_view iv,
154*e7b1675dSTing-Kang Chang absl::Span<char> out) const override {
155*e7b1675dSTing-Kang Chang absl::string_view ad = internal::EnsureStringNonNull(associated_data);
156*e7b1675dSTing-Kang Chang
157*e7b1675dSTing-Kang Chang if (ciphertext.size() < tag_size_) {
158*e7b1675dSTing-Kang Chang return util::Status(
159*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
160*e7b1675dSTing-Kang Chang absl::StrCat("Ciphertext buffer too small; expected at least ",
161*e7b1675dSTing-Kang Chang tag_size_, " got ", ciphertext.size()));
162*e7b1675dSTing-Kang Chang }
163*e7b1675dSTing-Kang Chang
164*e7b1675dSTing-Kang Chang const int64_t min_out_buff_size = PlaintextSize(ciphertext.size());
165*e7b1675dSTing-Kang Chang if (out.size() < min_out_buff_size) {
166*e7b1675dSTing-Kang Chang return util::Status(
167*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
168*e7b1675dSTing-Kang Chang absl::StrCat("Output buffer too small; expected at least ",
169*e7b1675dSTing-Kang Chang min_out_buff_size, " got ", out.size()));
170*e7b1675dSTing-Kang Chang }
171*e7b1675dSTing-Kang Chang
172*e7b1675dSTing-Kang Chang if (BuffersOverlap(ciphertext, absl::string_view(out.data(), out.size()))) {
173*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
174*e7b1675dSTing-Kang Chang "Ciphertext and output buffer must not overlap");
175*e7b1675dSTing-Kang Chang }
176*e7b1675dSTing-Kang Chang
177*e7b1675dSTing-Kang Chang if (associated_data.size() > std::numeric_limits<int>::max()) {
178*e7b1675dSTing-Kang Chang return util::Status(
179*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
180*e7b1675dSTing-Kang Chang absl::StrCat("Associated data too large; expected at most ",
181*e7b1675dSTing-Kang Chang std::numeric_limits<int>::max(), " got ",
182*e7b1675dSTing-Kang Chang associated_data.size()));
183*e7b1675dSTing-Kang Chang }
184*e7b1675dSTing-Kang Chang
185*e7b1675dSTing-Kang Chang util::StatusOr<internal::SslUniquePtr<EVP_CIPHER_CTX>> context =
186*e7b1675dSTing-Kang Chang GetContext(iv, /*encryption=*/false);
187*e7b1675dSTing-Kang Chang if (!context.ok()) {
188*e7b1675dSTing-Kang Chang return context.status();
189*e7b1675dSTing-Kang Chang }
190*e7b1675dSTing-Kang Chang
191*e7b1675dSTing-Kang Chang int len = 0;
192*e7b1675dSTing-Kang Chang // Add the associated data.
193*e7b1675dSTing-Kang Chang if (EVP_DecryptUpdate(context->get(), /*out=*/nullptr, &len,
194*e7b1675dSTing-Kang Chang reinterpret_cast<const uint8_t *>(ad.data()),
195*e7b1675dSTing-Kang Chang ad.size()) <= 0) {
196*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal,
197*e7b1675dSTing-Kang Chang "Failed to set associated_data");
198*e7b1675dSTing-Kang Chang }
199*e7b1675dSTing-Kang Chang
200*e7b1675dSTing-Kang Chang const int64_t raw_ciphertext_size = ciphertext.size() - tag_size_;
201*e7b1675dSTing-Kang Chang // "Unpack" the ciphertext.
202*e7b1675dSTing-Kang Chang absl::string_view raw_ciphertext =
203*e7b1675dSTing-Kang Chang ciphertext.substr(0, raw_ciphertext_size);
204*e7b1675dSTing-Kang Chang // This copy is needed since EVP_CIPHER_CTX_ctrl requires a non-const
205*e7b1675dSTing-Kang Chang // pointer even if the EVP_CTRL_AEAD_SET_TAG operation doesn't modify the
206*e7b1675dSTing-Kang Chang // content of the buffer.
207*e7b1675dSTing-Kang Chang auto tag = std::string(ciphertext.substr(raw_ciphertext_size, tag_size_));
208*e7b1675dSTing-Kang Chang
209*e7b1675dSTing-Kang Chang // Set the tag.
210*e7b1675dSTing-Kang Chang if (EVP_CIPHER_CTX_ctrl(context->get(), EVP_CTRL_AEAD_SET_TAG, tag_size_,
211*e7b1675dSTing-Kang Chang reinterpret_cast<uint8_t *>(&tag[0])) <= 0) {
212*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal,
213*e7b1675dSTing-Kang Chang "Could not set authentication tag");
214*e7b1675dSTing-Kang Chang }
215*e7b1675dSTing-Kang Chang
216*e7b1675dSTing-Kang Chang // If out.empty() accessing the 0th element would result in an out of
217*e7b1675dSTing-Kang Chang // bound violation. This makes sure we pass a pointer to at least one byte
218*e7b1675dSTing-Kang Chang // when calling into OpenSSL.
219*e7b1675dSTing-Kang Chang char buffer_if_size_is_zero = '\0';
220*e7b1675dSTing-Kang Chang auto out_buffer = absl::Span<char>(&buffer_if_size_is_zero, /*length=*/1);
221*e7b1675dSTing-Kang Chang if (!out.empty()) {
222*e7b1675dSTing-Kang Chang out_buffer = out.subspan(0, min_out_buff_size - tag_size_);
223*e7b1675dSTing-Kang Chang }
224*e7b1675dSTing-Kang Chang
225*e7b1675dSTing-Kang Chang // Zero the plaintext buffer in case decryption fails before returning an
226*e7b1675dSTing-Kang Chang // error.
227*e7b1675dSTing-Kang Chang auto output_eraser =
228*e7b1675dSTing-Kang Chang absl::MakeCleanup([out] { OPENSSL_cleanse(out.data(), out.size()); });
229*e7b1675dSTing-Kang Chang
230*e7b1675dSTing-Kang Chang util::StatusOr<int64_t> written_bytes =
231*e7b1675dSTing-Kang Chang UpdateCipher(context->get(), raw_ciphertext, out_buffer);
232*e7b1675dSTing-Kang Chang if (!written_bytes.ok()) {
233*e7b1675dSTing-Kang Chang return written_bytes.status();
234*e7b1675dSTing-Kang Chang }
235*e7b1675dSTing-Kang Chang
236*e7b1675dSTing-Kang Chang if (!EVP_DecryptFinal_ex(context->get(), /*out=*/nullptr, &len)) {
237*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal, "Authentication failed");
238*e7b1675dSTing-Kang Chang }
239*e7b1675dSTing-Kang Chang
240*e7b1675dSTing-Kang Chang // Decryption executed correctly, cancel cleanup on the output buffer.
241*e7b1675dSTing-Kang Chang std::move(output_eraser).Cancel();
242*e7b1675dSTing-Kang Chang return *written_bytes;
243*e7b1675dSTing-Kang Chang }
244*e7b1675dSTing-Kang Chang
CiphertextSize(int64_t plaintext_length) const245*e7b1675dSTing-Kang Chang int64_t CiphertextSize(int64_t plaintext_length) const override {
246*e7b1675dSTing-Kang Chang return plaintext_length + tag_size_;
247*e7b1675dSTing-Kang Chang }
248*e7b1675dSTing-Kang Chang
PlaintextSize(int64_t ciphertext_length) const249*e7b1675dSTing-Kang Chang int64_t PlaintextSize(int64_t ciphertext_length) const override {
250*e7b1675dSTing-Kang Chang if (ciphertext_length < tag_size_) {
251*e7b1675dSTing-Kang Chang return 0;
252*e7b1675dSTing-Kang Chang }
253*e7b1675dSTing-Kang Chang return ciphertext_length - tag_size_;
254*e7b1675dSTing-Kang Chang }
255*e7b1675dSTing-Kang Chang
256*e7b1675dSTing-Kang Chang private:
257*e7b1675dSTing-Kang Chang // Returns a new EVP_CIPHER_CTX for encryption (`ecryption` == true) or
258*e7b1675dSTing-Kang Chang // decryption (`encryption` == false).
GetContext(absl::string_view iv,bool encryption) const259*e7b1675dSTing-Kang Chang util::StatusOr<internal::SslUniquePtr<EVP_CIPHER_CTX>> GetContext(
260*e7b1675dSTing-Kang Chang absl::string_view iv, bool encryption) const {
261*e7b1675dSTing-Kang Chang internal::SslUniquePtr<EVP_CIPHER_CTX> context(EVP_CIPHER_CTX_new());
262*e7b1675dSTing-Kang Chang if (context == nullptr) {
263*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal,
264*e7b1675dSTing-Kang Chang "EVP_CIPHER_CTX_new failed");
265*e7b1675dSTing-Kang Chang }
266*e7b1675dSTing-Kang Chang const int encryption_flag = encryption ? 1 : 0;
267*e7b1675dSTing-Kang Chang if (EVP_CipherInit_ex(context.get(), cipher_, /*impl=*/nullptr,
268*e7b1675dSTing-Kang Chang /*key=*/nullptr, /*iv=*/nullptr,
269*e7b1675dSTing-Kang Chang encryption_flag) <= 0) {
270*e7b1675dSTing-Kang Chang return util::Status(
271*e7b1675dSTing-Kang Chang absl::StatusCode::kInternal,
272*e7b1675dSTing-Kang Chang absl::StrCat("Failed initializializing context for ",
273*e7b1675dSTing-Kang Chang encryption ? "encryption" : "decryption"));
274*e7b1675dSTing-Kang Chang }
275*e7b1675dSTing-Kang Chang // Set the size for IV first, then set the IV bytes.
276*e7b1675dSTing-Kang Chang if (EVP_CIPHER_CTX_ctrl(context.get(), EVP_CTRL_AEAD_SET_IVLEN, iv.size(),
277*e7b1675dSTing-Kang Chang /*ptr=*/nullptr) <= 0) {
278*e7b1675dSTing-Kang Chang return util::Status(
279*e7b1675dSTing-Kang Chang absl::StatusCode::kInternal,
280*e7b1675dSTing-Kang Chang absl::StrCat("Failed stting size of the IV to ", iv.size()));
281*e7b1675dSTing-Kang Chang }
282*e7b1675dSTing-Kang Chang if (EVP_CipherInit_ex(context.get(), /*cipher=*/nullptr, /*impl=*/nullptr,
283*e7b1675dSTing-Kang Chang reinterpret_cast<const uint8_t *>(key_.data()),
284*e7b1675dSTing-Kang Chang reinterpret_cast<const uint8_t *>(iv.data()),
285*e7b1675dSTing-Kang Chang encryption_flag) <= 0) {
286*e7b1675dSTing-Kang Chang return util::Status(
287*e7b1675dSTing-Kang Chang absl::StatusCode::kInternal,
288*e7b1675dSTing-Kang Chang absl::StrCat("Failed to set key of size ", key_.size(),
289*e7b1675dSTing-Kang Chang "and IV of size ", iv.size()));
290*e7b1675dSTing-Kang Chang }
291*e7b1675dSTing-Kang Chang
292*e7b1675dSTing-Kang Chang return std::move(context);
293*e7b1675dSTing-Kang Chang }
294*e7b1675dSTing-Kang Chang
295*e7b1675dSTing-Kang Chang const util::SecretData key_;
296*e7b1675dSTing-Kang Chang const EVP_CIPHER *cipher_;
297*e7b1675dSTing-Kang Chang const size_t tag_size_;
298*e7b1675dSTing-Kang Chang };
299*e7b1675dSTing-Kang Chang
300*e7b1675dSTing-Kang Chang #ifdef OPENSSL_IS_BORINGSSL
301*e7b1675dSTing-Kang Chang
302*e7b1675dSTing-Kang Chang // Implementation of the one-shot AEAD cypter. This is purposely internal to
303*e7b1675dSTing-Kang Chang // an anonymous namespace to disallow direct use of this class other than
304*e7b1675dSTing-Kang Chang // through the Create* functions below.
305*e7b1675dSTing-Kang Chang class BoringSslOneShotAeadImpl : public SslOneShotAead {
306*e7b1675dSTing-Kang Chang public:
BoringSslOneShotAeadImpl(internal::SslUniquePtr<EVP_AEAD_CTX> context,size_t tag_size)307*e7b1675dSTing-Kang Chang explicit BoringSslOneShotAeadImpl(
308*e7b1675dSTing-Kang Chang internal::SslUniquePtr<EVP_AEAD_CTX> context, size_t tag_size)
309*e7b1675dSTing-Kang Chang : context_(std::move(context)), tag_size_(tag_size) {}
310*e7b1675dSTing-Kang Chang
Encrypt(absl::string_view plaintext,absl::string_view associated_data,absl::string_view iv,absl::Span<char> out) const311*e7b1675dSTing-Kang Chang util::StatusOr<int64_t> Encrypt(absl::string_view plaintext,
312*e7b1675dSTing-Kang Chang absl::string_view associated_data,
313*e7b1675dSTing-Kang Chang absl::string_view iv,
314*e7b1675dSTing-Kang Chang absl::Span<char> out) const override {
315*e7b1675dSTing-Kang Chang // BoringSSL expects a non-null pointer for associated_data,
316*e7b1675dSTing-Kang Chang // regardless of whether the size is 0.
317*e7b1675dSTing-Kang Chang plaintext = internal::EnsureStringNonNull(plaintext);
318*e7b1675dSTing-Kang Chang associated_data = internal::EnsureStringNonNull(associated_data);
319*e7b1675dSTing-Kang Chang iv = internal::EnsureStringNonNull(iv);
320*e7b1675dSTing-Kang Chang
321*e7b1675dSTing-Kang Chang if (BuffersOverlap(plaintext, absl::string_view(out.data(), out.size()))) {
322*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
323*e7b1675dSTing-Kang Chang "Plaintext and output buffer must not overlap");
324*e7b1675dSTing-Kang Chang }
325*e7b1675dSTing-Kang Chang
326*e7b1675dSTing-Kang Chang const int64_t min_out_buff_size = CiphertextSize(plaintext.size());
327*e7b1675dSTing-Kang Chang if (out.size() < min_out_buff_size) {
328*e7b1675dSTing-Kang Chang return util::Status(
329*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
330*e7b1675dSTing-Kang Chang absl::StrCat("Output buffer too small; expected at least ",
331*e7b1675dSTing-Kang Chang min_out_buff_size, " got ", out.size()));
332*e7b1675dSTing-Kang Chang }
333*e7b1675dSTing-Kang Chang size_t out_len = 0;
334*e7b1675dSTing-Kang Chang if (!EVP_AEAD_CTX_seal(
335*e7b1675dSTing-Kang Chang context_.get(), reinterpret_cast<uint8_t *>(&out[0]), &out_len,
336*e7b1675dSTing-Kang Chang out.size(), reinterpret_cast<const uint8_t *>(iv.data()), iv.size(),
337*e7b1675dSTing-Kang Chang reinterpret_cast<const uint8_t *>(plaintext.data()),
338*e7b1675dSTing-Kang Chang plaintext.size(),
339*e7b1675dSTing-Kang Chang /*ad=*/reinterpret_cast<const uint8_t *>(associated_data.data()),
340*e7b1675dSTing-Kang Chang /*ad_len=*/associated_data.size())) {
341*e7b1675dSTing-Kang Chang return util::Status(
342*e7b1675dSTing-Kang Chang absl::StatusCode::kInternal,
343*e7b1675dSTing-Kang Chang absl::StrCat("Encryption failed: ", internal::GetSslErrors()));
344*e7b1675dSTing-Kang Chang }
345*e7b1675dSTing-Kang Chang
346*e7b1675dSTing-Kang Chang return out_len;
347*e7b1675dSTing-Kang Chang }
348*e7b1675dSTing-Kang Chang
Decrypt(absl::string_view ciphertext,absl::string_view associated_data,absl::string_view iv,absl::Span<char> out) const349*e7b1675dSTing-Kang Chang util::StatusOr<int64_t> Decrypt(absl::string_view ciphertext,
350*e7b1675dSTing-Kang Chang absl::string_view associated_data,
351*e7b1675dSTing-Kang Chang absl::string_view iv,
352*e7b1675dSTing-Kang Chang absl::Span<char> out) const override {
353*e7b1675dSTing-Kang Chang ciphertext = internal::EnsureStringNonNull(ciphertext);
354*e7b1675dSTing-Kang Chang associated_data = internal::EnsureStringNonNull(associated_data);
355*e7b1675dSTing-Kang Chang iv = internal::EnsureStringNonNull(iv);
356*e7b1675dSTing-Kang Chang
357*e7b1675dSTing-Kang Chang if (BuffersOverlap(ciphertext, absl::string_view(out.data(), out.size()))) {
358*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
359*e7b1675dSTing-Kang Chang "Ciphertext and output buffer must not overlap");
360*e7b1675dSTing-Kang Chang }
361*e7b1675dSTing-Kang Chang
362*e7b1675dSTing-Kang Chang if (ciphertext.size() < tag_size_) {
363*e7b1675dSTing-Kang Chang return util::Status(
364*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
365*e7b1675dSTing-Kang Chang absl::StrCat("Ciphertext buffer too small; expected at least ",
366*e7b1675dSTing-Kang Chang tag_size_, " got ", ciphertext.size()));
367*e7b1675dSTing-Kang Chang }
368*e7b1675dSTing-Kang Chang
369*e7b1675dSTing-Kang Chang const int64_t min_out_buff_size = PlaintextSize(ciphertext.size());
370*e7b1675dSTing-Kang Chang if (out.size() < min_out_buff_size) {
371*e7b1675dSTing-Kang Chang return util::Status(
372*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
373*e7b1675dSTing-Kang Chang absl::StrCat("Output buffer too small; expected at least ",
374*e7b1675dSTing-Kang Chang min_out_buff_size, " got ", out.size()));
375*e7b1675dSTing-Kang Chang }
376*e7b1675dSTing-Kang Chang
377*e7b1675dSTing-Kang Chang // If out.empty() accessing the 0th element would result in an out of
378*e7b1675dSTing-Kang Chang // bound violation. This makes sure we pass a pointer to at least one byte
379*e7b1675dSTing-Kang Chang // when calling into OpenSSL.
380*e7b1675dSTing-Kang Chang uint8_t buffer_if_size_is_zero;
381*e7b1675dSTing-Kang Chang uint8_t *buffer_ptr = &buffer_if_size_is_zero;
382*e7b1675dSTing-Kang Chang if (!out.empty()) {
383*e7b1675dSTing-Kang Chang buffer_ptr = reinterpret_cast<uint8_t *>(&out[0]);
384*e7b1675dSTing-Kang Chang }
385*e7b1675dSTing-Kang Chang
386*e7b1675dSTing-Kang Chang size_t out_len = 0;
387*e7b1675dSTing-Kang Chang if (!EVP_AEAD_CTX_open(
388*e7b1675dSTing-Kang Chang context_.get(), buffer_ptr, &out_len, out.size(),
389*e7b1675dSTing-Kang Chang reinterpret_cast<const uint8_t *>(iv.data()), iv.size(),
390*e7b1675dSTing-Kang Chang reinterpret_cast<const uint8_t *>(ciphertext.data()),
391*e7b1675dSTing-Kang Chang ciphertext.size(),
392*e7b1675dSTing-Kang Chang /*ad=*/reinterpret_cast<const uint8_t *>(associated_data.data()),
393*e7b1675dSTing-Kang Chang /*ad_len=*/associated_data.size())) {
394*e7b1675dSTing-Kang Chang return util::Status(
395*e7b1675dSTing-Kang Chang absl::StatusCode::kInternal,
396*e7b1675dSTing-Kang Chang absl::StrCat("Authentication failed: ", internal::GetSslErrors()));
397*e7b1675dSTing-Kang Chang }
398*e7b1675dSTing-Kang Chang
399*e7b1675dSTing-Kang Chang return out_len;
400*e7b1675dSTing-Kang Chang }
401*e7b1675dSTing-Kang Chang
CiphertextSize(int64_t plaintext_length) const402*e7b1675dSTing-Kang Chang int64_t CiphertextSize(int64_t plaintext_length) const override {
403*e7b1675dSTing-Kang Chang return plaintext_length + tag_size_;
404*e7b1675dSTing-Kang Chang }
405*e7b1675dSTing-Kang Chang
PlaintextSize(int64_t ciphertext_length) const406*e7b1675dSTing-Kang Chang int64_t PlaintextSize(int64_t ciphertext_length) const override {
407*e7b1675dSTing-Kang Chang if (ciphertext_length < tag_size_) {
408*e7b1675dSTing-Kang Chang return 0;
409*e7b1675dSTing-Kang Chang }
410*e7b1675dSTing-Kang Chang return ciphertext_length - tag_size_;
411*e7b1675dSTing-Kang Chang }
412*e7b1675dSTing-Kang Chang
413*e7b1675dSTing-Kang Chang private:
414*e7b1675dSTing-Kang Chang const internal::SslUniquePtr<EVP_AEAD_CTX> context_;
415*e7b1675dSTing-Kang Chang const size_t tag_size_;
416*e7b1675dSTing-Kang Chang };
417*e7b1675dSTing-Kang Chang
418*e7b1675dSTing-Kang Chang #endif
419*e7b1675dSTing-Kang Chang
420*e7b1675dSTing-Kang Chang } // namespace
421*e7b1675dSTing-Kang Chang
CreateAesGcmOneShotCrypter(const util::SecretData & key)422*e7b1675dSTing-Kang Chang util::StatusOr<std::unique_ptr<SslOneShotAead>> CreateAesGcmOneShotCrypter(
423*e7b1675dSTing-Kang Chang const util::SecretData &key) {
424*e7b1675dSTing-Kang Chang #ifdef OPENSSL_IS_BORINGSSL
425*e7b1675dSTing-Kang Chang util::StatusOr<const EVP_AEAD *> aead_cipher =
426*e7b1675dSTing-Kang Chang GetAesGcmAeadForKeySize(key.size());
427*e7b1675dSTing-Kang Chang if (!aead_cipher.ok()) {
428*e7b1675dSTing-Kang Chang return aead_cipher.status();
429*e7b1675dSTing-Kang Chang }
430*e7b1675dSTing-Kang Chang
431*e7b1675dSTing-Kang Chang internal::SslUniquePtr<EVP_AEAD_CTX> context(EVP_AEAD_CTX_new(
432*e7b1675dSTing-Kang Chang *aead_cipher, key.data(), key.size(), kAesGcmTagSizeInBytes));
433*e7b1675dSTing-Kang Chang if (context == nullptr) {
434*e7b1675dSTing-Kang Chang return util::Status(
435*e7b1675dSTing-Kang Chang absl::StatusCode::kInternal,
436*e7b1675dSTing-Kang Chang absl::StrCat("EVP_AEAD_CTX_new failed: ", internal::GetSslErrors()));
437*e7b1675dSTing-Kang Chang }
438*e7b1675dSTing-Kang Chang return {absl::make_unique<BoringSslOneShotAeadImpl>(std::move(context),
439*e7b1675dSTing-Kang Chang kAesGcmTagSizeInBytes)};
440*e7b1675dSTing-Kang Chang #else
441*e7b1675dSTing-Kang Chang util::StatusOr<const EVP_CIPHER *> aead_cipher =
442*e7b1675dSTing-Kang Chang GetAesGcmCipherForKeySize(key.size());
443*e7b1675dSTing-Kang Chang if (!aead_cipher.ok()) {
444*e7b1675dSTing-Kang Chang return aead_cipher.status();
445*e7b1675dSTing-Kang Chang }
446*e7b1675dSTing-Kang Chang
447*e7b1675dSTing-Kang Chang return absl::make_unique<OpenSslOneShotAeadImpl>(key, *aead_cipher,
448*e7b1675dSTing-Kang Chang kAesGcmTagSizeInBytes);
449*e7b1675dSTing-Kang Chang #endif
450*e7b1675dSTing-Kang Chang }
451*e7b1675dSTing-Kang Chang
CreateAesGcmSivOneShotCrypter(const util::SecretData & key)452*e7b1675dSTing-Kang Chang util::StatusOr<std::unique_ptr<SslOneShotAead>> CreateAesGcmSivOneShotCrypter(
453*e7b1675dSTing-Kang Chang const util::SecretData &key) {
454*e7b1675dSTing-Kang Chang #ifdef OPENSSL_IS_BORINGSSL
455*e7b1675dSTing-Kang Chang util::StatusOr<const EVP_AEAD *> aead_cipher =
456*e7b1675dSTing-Kang Chang GetAesGcmSivAeadCipherForKeySize(key.size());
457*e7b1675dSTing-Kang Chang if (!aead_cipher.ok()) {
458*e7b1675dSTing-Kang Chang return aead_cipher.status();
459*e7b1675dSTing-Kang Chang }
460*e7b1675dSTing-Kang Chang internal::SslUniquePtr<EVP_AEAD_CTX> context(EVP_AEAD_CTX_new(
461*e7b1675dSTing-Kang Chang *aead_cipher, key.data(), key.size(), kAesGcmTagSizeInBytes));
462*e7b1675dSTing-Kang Chang if (context == nullptr) {
463*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal,
464*e7b1675dSTing-Kang Chang absl::StrCat("EVP_AEAD_CTX_new initialization Failed: ",
465*e7b1675dSTing-Kang Chang internal::GetSslErrors()));
466*e7b1675dSTing-Kang Chang }
467*e7b1675dSTing-Kang Chang return {absl::make_unique<BoringSslOneShotAeadImpl>(
468*e7b1675dSTing-Kang Chang std::move(context), kAesGcmSivTagSizeInBytes)};
469*e7b1675dSTing-Kang Chang #else
470*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kUnimplemented,
471*e7b1675dSTing-Kang Chang "AES-GCM-SIV is unimplemented for OpenSSL");
472*e7b1675dSTing-Kang Chang #endif
473*e7b1675dSTing-Kang Chang }
474*e7b1675dSTing-Kang Chang
475*e7b1675dSTing-Kang Chang util::StatusOr<std::unique_ptr<SslOneShotAead>>
CreateXchacha20Poly1305OneShotCrypter(const util::SecretData & key)476*e7b1675dSTing-Kang Chang CreateXchacha20Poly1305OneShotCrypter(const util::SecretData &key) {
477*e7b1675dSTing-Kang Chang #ifdef OPENSSL_IS_BORINGSSL
478*e7b1675dSTing-Kang Chang if (key.size() != 32) {
479*e7b1675dSTing-Kang Chang return util::Status(
480*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
481*e7b1675dSTing-Kang Chang absl::StrCat("Invalid key size; valid values are {32} bytes, got ",
482*e7b1675dSTing-Kang Chang key.size()));
483*e7b1675dSTing-Kang Chang }
484*e7b1675dSTing-Kang Chang
485*e7b1675dSTing-Kang Chang internal::SslUniquePtr<EVP_AEAD_CTX> context(
486*e7b1675dSTing-Kang Chang EVP_AEAD_CTX_new(EVP_aead_xchacha20_poly1305(), key.data(), key.size(),
487*e7b1675dSTing-Kang Chang kAesGcmTagSizeInBytes));
488*e7b1675dSTing-Kang Chang if (context == nullptr) {
489*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInternal,
490*e7b1675dSTing-Kang Chang absl::StrCat("EVP_AEAD_CTX_new initialization Failed: ",
491*e7b1675dSTing-Kang Chang internal::GetSslErrors()));
492*e7b1675dSTing-Kang Chang }
493*e7b1675dSTing-Kang Chang return {absl::make_unique<BoringSslOneShotAeadImpl>(
494*e7b1675dSTing-Kang Chang std::move(context), kXchacha20Poly1305TagSizeInBytes)};
495*e7b1675dSTing-Kang Chang #else
496*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kUnimplemented,
497*e7b1675dSTing-Kang Chang "Xchacha20-Poly1305 is unimplemented for OpenSSL");
498*e7b1675dSTing-Kang Chang #endif
499*e7b1675dSTing-Kang Chang }
500*e7b1675dSTing-Kang Chang
501*e7b1675dSTing-Kang Chang } // namespace internal
502*e7b1675dSTing-Kang Chang } // namespace tink
503*e7b1675dSTing-Kang Chang } // namespace crypto
504