xref: /aosp_15_r20/external/cronet/crypto/aead.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "crypto/aead.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <string>
10 
11 #include "base/containers/span.h"
12 #include "base/numerics/checked_math.h"
13 #include "crypto/openssl_util.h"
14 #include "third_party/boringssl/src/include/openssl/aes.h"
15 #include "third_party/boringssl/src/include/openssl/evp.h"
16 
17 namespace crypto {
18 
Aead(AeadAlgorithm algorithm)19 Aead::Aead(AeadAlgorithm algorithm) {
20   EnsureOpenSSLInit();
21   switch (algorithm) {
22     case AES_128_CTR_HMAC_SHA256:
23       aead_ = EVP_aead_aes_128_ctr_hmac_sha256();
24       break;
25     case AES_256_GCM:
26       aead_ = EVP_aead_aes_256_gcm();
27       break;
28     case AES_256_GCM_SIV:
29       aead_ = EVP_aead_aes_256_gcm_siv();
30       break;
31     case CHACHA20_POLY1305:
32       aead_ = EVP_aead_chacha20_poly1305();
33       break;
34   }
35 }
36 
37 Aead::~Aead() = default;
38 
Init(base::span<const uint8_t> key)39 void Aead::Init(base::span<const uint8_t> key) {
40   DCHECK(!key_);
41   DCHECK_EQ(KeyLength(), key.size());
42   key_ = key;
43 }
44 
Init(const std::string * key)45 void Aead::Init(const std::string* key) {
46   Init(base::as_byte_span(*key));
47 }
48 
Seal(base::span<const uint8_t> plaintext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data) const49 std::vector<uint8_t> Aead::Seal(
50     base::span<const uint8_t> plaintext,
51     base::span<const uint8_t> nonce,
52     base::span<const uint8_t> additional_data) const {
53   size_t max_output_length =
54       base::CheckAdd(plaintext.size(), EVP_AEAD_max_overhead(aead_))
55           .ValueOrDie();
56   std::vector<uint8_t> ret(max_output_length);
57 
58   std::optional<size_t> output_length =
59       Seal(plaintext, nonce, additional_data, ret);
60   CHECK(output_length);
61   ret.resize(*output_length);
62   return ret;
63 }
64 
Seal(std::string_view plaintext,std::string_view nonce,std::string_view additional_data,std::string * ciphertext) const65 bool Aead::Seal(std::string_view plaintext,
66                 std::string_view nonce,
67                 std::string_view additional_data,
68                 std::string* ciphertext) const {
69   size_t max_output_length =
70       base::CheckAdd(plaintext.size(), EVP_AEAD_max_overhead(aead_))
71           .ValueOrDie();
72   ciphertext->resize(max_output_length);
73 
74   std::optional<size_t> output_length =
75       Seal(base::as_byte_span(plaintext), base::as_byte_span(nonce),
76            base::as_byte_span(additional_data),
77            base::as_writable_byte_span(*ciphertext));
78   if (!output_length) {
79     ciphertext->clear();
80     return false;
81   }
82 
83   ciphertext->resize(*output_length);
84   return true;
85 }
86 
Open(base::span<const uint8_t> ciphertext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data) const87 std::optional<std::vector<uint8_t>> Aead::Open(
88     base::span<const uint8_t> ciphertext,
89     base::span<const uint8_t> nonce,
90     base::span<const uint8_t> additional_data) const {
91   const size_t max_output_length = ciphertext.size();
92   std::vector<uint8_t> ret(max_output_length);
93 
94   std::optional<size_t> output_length =
95       Open(ciphertext, nonce, additional_data, ret);
96   if (!output_length) {
97     return std::nullopt;
98   }
99 
100   ret.resize(*output_length);
101   return ret;
102 }
103 
Open(std::string_view ciphertext,std::string_view nonce,std::string_view additional_data,std::string * plaintext) const104 bool Aead::Open(std::string_view ciphertext,
105                 std::string_view nonce,
106                 std::string_view additional_data,
107                 std::string* plaintext) const {
108   const size_t max_output_length = ciphertext.size();
109   plaintext->resize(max_output_length);
110 
111   std::optional<size_t> output_length =
112       Open(base::as_byte_span(ciphertext), base::as_byte_span(nonce),
113            base::as_byte_span(additional_data),
114            base::as_writable_byte_span(*plaintext));
115   if (!output_length) {
116     plaintext->clear();
117     return false;
118   }
119 
120   plaintext->resize(*output_length);
121   return true;
122 }
123 
KeyLength() const124 size_t Aead::KeyLength() const {
125   return EVP_AEAD_key_length(aead_);
126 }
127 
NonceLength() const128 size_t Aead::NonceLength() const {
129   return EVP_AEAD_nonce_length(aead_);
130 }
131 
Seal(base::span<const uint8_t> plaintext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data,base::span<uint8_t> out) const132 std::optional<size_t> Aead::Seal(base::span<const uint8_t> plaintext,
133                                  base::span<const uint8_t> nonce,
134                                  base::span<const uint8_t> additional_data,
135                                  base::span<uint8_t> out) const {
136   DCHECK(key_);
137   DCHECK_EQ(NonceLength(), nonce.size());
138   bssl::ScopedEVP_AEAD_CTX ctx;
139 
140   size_t out_len;
141   if (!EVP_AEAD_CTX_init(ctx.get(), aead_, key_->data(), key_->size(),
142                          EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) ||
143       !EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
144                          nonce.data(), nonce.size(), plaintext.data(),
145                          plaintext.size(), additional_data.data(),
146                          additional_data.size())) {
147     return std::nullopt;
148   }
149 
150   DCHECK_LE(out_len, out.size());
151   return out_len;
152 }
153 
Open(base::span<const uint8_t> plaintext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data,base::span<uint8_t> out) const154 std::optional<size_t> Aead::Open(base::span<const uint8_t> plaintext,
155                                  base::span<const uint8_t> nonce,
156                                  base::span<const uint8_t> additional_data,
157                                  base::span<uint8_t> out) const {
158   DCHECK(key_);
159   DCHECK_EQ(NonceLength(), nonce.size());
160   bssl::ScopedEVP_AEAD_CTX ctx;
161 
162   size_t out_len;
163   if (!EVP_AEAD_CTX_init(ctx.get(), aead_, key_->data(), key_->size(),
164                          EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) ||
165       !EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
166                          nonce.data(), nonce.size(), plaintext.data(),
167                          plaintext.size(), additional_data.data(),
168                          additional_data.size())) {
169     return std::nullopt;
170   }
171 
172   DCHECK_LE(out_len, out.size());
173   return out_len;
174 }
175 
176 }  // namespace crypto
177