xref: /aosp_15_r20/external/tink/cc/aead/internal/zero_copy_aes_gcm_boringssl.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 
17 #include "tink/aead/internal/zero_copy_aes_gcm_boringssl.h"
18 
19 #include <cstdint>
20 #include <memory>
21 #include <utility>
22 
23 #include "absl/memory/memory.h"
24 #include "absl/status/status.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/string_view.h"
27 #include "tink/aead/internal/aead_util.h"
28 #include "tink/aead/internal/ssl_aead.h"
29 #include "tink/aead/internal/zero_copy_aead.h"
30 #include "tink/internal/util.h"
31 #include "tink/subtle/random.h"
32 #include "tink/subtle/subtle_util.h"
33 #include "tink/util/status.h"
34 #include "tink/util/statusor.h"
35 
36 namespace crypto {
37 namespace tink {
38 namespace internal {
39 
40 constexpr int kIvSizeInBytes = 12;
41 constexpr int kTagSizeInBytes = 16;
42 
New(const util::SecretData & key)43 util::StatusOr<std::unique_ptr<ZeroCopyAead>> ZeroCopyAesGcmBoringSsl::New(
44     const util::SecretData &key) {
45   util::StatusOr<std::unique_ptr<internal::SslOneShotAead>> aead =
46       internal::CreateAesGcmOneShotCrypter(key);
47   if (!aead.ok()) {
48     return aead.status();
49   }
50   return {absl::WrapUnique(new ZeroCopyAesGcmBoringSsl(*std::move(aead)))};
51 }
52 
MaxEncryptionSize(int64_t plaintext_size) const53 int64_t ZeroCopyAesGcmBoringSsl::MaxEncryptionSize(
54     int64_t plaintext_size) const {
55   return kIvSizeInBytes + aead_->CiphertextSize(plaintext_size);
56 }
57 
Encrypt(absl::string_view plaintext,absl::string_view associated_data,absl::Span<char> buffer) const58 util::StatusOr<int64_t> ZeroCopyAesGcmBoringSsl::Encrypt(
59     absl::string_view plaintext, absl::string_view associated_data,
60     absl::Span<char> buffer) const {
61   const int64_t max_encryption_size = MaxEncryptionSize(plaintext.size());
62   if (buffer.size() < max_encryption_size) {
63     return util::Status(
64         absl::StatusCode::kInvalidArgument,
65         absl::StrCat("Encryption buffer too small; expected at least ",
66                      max_encryption_size, " bytes, got ", buffer.size()));
67   }
68   absl::string_view buffer_string(buffer.data(), buffer.size());
69   if (BuffersOverlap(plaintext, buffer_string)) {
70     return util::Status(
71         absl::StatusCode::kFailedPrecondition,
72         "Plaintext and ciphertext buffers overlap; this is disallowed");
73   }
74 
75   util::Status res =
76       subtle::Random::GetRandomBytes(buffer.subspan(0, kIvSizeInBytes));
77   if (!res.ok()) {
78     return res;
79   }
80   absl::string_view iv = buffer_string.substr(0, kIvSizeInBytes);
81   absl::Span<char> raw_cipher_and_tag_buffer = buffer.subspan(kIvSizeInBytes);
82 
83   util::StatusOr<int64_t> written_bytes =
84       aead_->Encrypt(plaintext, associated_data, iv, raw_cipher_and_tag_buffer);
85   if (!written_bytes.ok()) {
86     return written_bytes.status();
87   }
88   return kIvSizeInBytes + *written_bytes;
89 }
90 
MaxDecryptionSize(int64_t ciphertext_size) const91 int64_t ZeroCopyAesGcmBoringSsl::MaxDecryptionSize(
92     int64_t ciphertext_size) const {
93   const int64_t size = ciphertext_size - kIvSizeInBytes - kTagSizeInBytes;
94   if (size <= 0) {
95     return 0;
96   }
97   return size;
98 }
99 
Decrypt(absl::string_view ciphertext,absl::string_view associated_data,absl::Span<char> buffer) const100 util::StatusOr<int64_t> ZeroCopyAesGcmBoringSsl::Decrypt(
101     absl::string_view ciphertext, absl::string_view associated_data,
102     absl::Span<char> buffer) const {
103   const size_t min_ciphertext_size = kIvSizeInBytes + kTagSizeInBytes;
104   if (ciphertext.size() < min_ciphertext_size) {
105     return util::Status(
106         absl::StatusCode::kInvalidArgument,
107         absl::StrCat("Ciphertext too short; expected at least ",
108                      min_ciphertext_size, " bytes, got ", ciphertext.size()));
109   }
110 
111   const int64_t max_decryption_size = MaxDecryptionSize(ciphertext.size());
112   if (buffer.size() < max_decryption_size) {
113     return util::Status(
114         absl::StatusCode::kInvalidArgument,
115         absl::StrCat("Decryption buffer too small; expected at least ",
116                      max_decryption_size, " bytes, got ", buffer.size()));
117   }
118 
119   absl::string_view buffer_string(buffer.data(), buffer.size());
120   if (BuffersOverlap(ciphertext, buffer_string)) {
121     return util::Status(
122         absl::StatusCode::kFailedPrecondition,
123         "Plaintext and ciphertext buffers overlap; this is disallowed");
124   }
125 
126   auto iv = ciphertext.substr(0, kIvSizeInBytes);
127   auto ciphertext_and_tag =
128       ciphertext.substr(kIvSizeInBytes, ciphertext.size() - kIvSizeInBytes);
129   return aead_->Decrypt(ciphertext_and_tag, associated_data, iv, buffer);
130 }
131 
132 }  // namespace internal
133 }  // namespace tink
134 }  // namespace crypto
135