xref: /aosp_15_r20/external/tink/cc/aead/internal/ssl_aead.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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