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