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