xref: /aosp_15_r20/external/tink/cc/subtle/xchacha20_poly1305_boringssl.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2018 Google Inc.
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/subtle/xchacha20_poly1305_boringssl.h"
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include "absl/memory/memory.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/str_cat.h"
29 #include "absl/strings/string_view.h"
30 #include "absl/types/span.h"
31 #include "tink/aead.h"
32 #include "tink/aead/internal/ssl_aead.h"
33 #include "tink/internal/util.h"
34 #include "tink/subtle/random.h"
35 #include "tink/subtle/subtle_util.h"
36 #include "tink/util/errors.h"
37 #include "tink/util/status.h"
38 #include "tink/util/statusor.h"
39 
40 namespace crypto {
41 namespace tink {
42 namespace subtle {
43 
44 constexpr int kNonceSizeInBytes = 24;
45 constexpr int kTagSizeInBytes = 16;
46 
New(util::SecretData key)47 util::StatusOr<std::unique_ptr<Aead>> XChacha20Poly1305BoringSsl::New(
48     util::SecretData key) {
49   auto status = internal::CheckFipsCompatibility<XChacha20Poly1305BoringSsl>();
50   if (!status.ok()) {
51     return status;
52   }
53   util::StatusOr<std::unique_ptr<internal::SslOneShotAead>> aead =
54       internal::CreateXchacha20Poly1305OneShotCrypter(key);
55   if (!aead.ok()) {
56     return aead.status();
57   }
58   std::unique_ptr<Aead> aead_impl =
59       absl::WrapUnique(new XChacha20Poly1305BoringSsl(*std::move(aead)));
60   return std::move(aead_impl);
61 }
62 
Encrypt(absl::string_view plaintext,absl::string_view associated_data) const63 util::StatusOr<std::string> XChacha20Poly1305BoringSsl::Encrypt(
64     absl::string_view plaintext, absl::string_view associated_data) const {
65   const int64_t kCiphertextSize =
66       kNonceSizeInBytes + aead_->CiphertextSize(plaintext.size());
67   std::string ct;
68   ResizeStringUninitialized(&ct, kCiphertextSize);
69   util::Status res =
70       Random::GetRandomBytes(absl::MakeSpan(ct).subspan(0, kNonceSizeInBytes));
71   if (!res.ok()) {
72     return res;
73   }
74   auto nonce = absl::string_view(ct).substr(0, kNonceSizeInBytes);
75   auto ciphertext_and_tag_buffer =
76       absl::MakeSpan(ct).subspan(kNonceSizeInBytes);
77   util::StatusOr<int64_t> written_bytes = aead_->Encrypt(
78       plaintext, associated_data, nonce, ciphertext_and_tag_buffer);
79   if (!written_bytes.ok()) {
80     return written_bytes.status();
81   }
82   return ct;
83 }
84 
Decrypt(absl::string_view ciphertext,absl::string_view associated_data) const85 util::StatusOr<std::string> XChacha20Poly1305BoringSsl::Decrypt(
86     absl::string_view ciphertext, absl::string_view associated_data) const {
87   if (ciphertext.size() < kNonceSizeInBytes + kTagSizeInBytes) {
88     return util::Status(absl::StatusCode::kInvalidArgument,
89                         absl::StrCat("Ciphertext too short; expected at least ",
90                                      kNonceSizeInBytes + kTagSizeInBytes,
91                                      " got ", ciphertext.size()));
92   }
93   const int64_t kPlaintextSize =
94       aead_->PlaintextSize(ciphertext.size() - kNonceSizeInBytes);
95   std::string plaintext;
96   ResizeStringUninitialized(&plaintext, kPlaintextSize);
97   auto nonce = ciphertext.substr(0, kNonceSizeInBytes);
98   auto encrypted = ciphertext.substr(kNonceSizeInBytes);
99   util::StatusOr<int64_t> written_bytes = aead_->Decrypt(
100       encrypted, associated_data, nonce, absl::MakeSpan(plaintext));
101   if (!written_bytes.ok()) {
102     return written_bytes.status();
103   }
104   return plaintext;
105 }
106 
107 }  // namespace subtle
108 }  // namespace tink
109 }  // namespace crypto
110