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