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 "third_party/boringssl/src/include/openssl/aes.h"
14 #include "third_party/boringssl/src/include/openssl/evp.h"
15
16 namespace crypto {
17
Aead(AeadAlgorithm algorithm)18 Aead::Aead(AeadAlgorithm algorithm) {
19 switch (algorithm) {
20 case AES_128_CTR_HMAC_SHA256:
21 aead_ = EVP_aead_aes_128_ctr_hmac_sha256();
22 break;
23 case AES_256_GCM:
24 aead_ = EVP_aead_aes_256_gcm();
25 break;
26 case AES_256_GCM_SIV:
27 aead_ = EVP_aead_aes_256_gcm_siv();
28 break;
29 case CHACHA20_POLY1305:
30 aead_ = EVP_aead_chacha20_poly1305();
31 break;
32 }
33 }
34
35 Aead::~Aead() = default;
36
Init(base::span<const uint8_t> key)37 void Aead::Init(base::span<const uint8_t> key) {
38 DCHECK(!key_);
39 DCHECK_EQ(KeyLength(), key.size());
40 key_ = key;
41 }
42
Init(const std::string * key)43 void Aead::Init(const std::string* key) {
44 Init(base::as_byte_span(*key));
45 }
46
Seal(base::span<const uint8_t> plaintext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data) const47 std::vector<uint8_t> Aead::Seal(
48 base::span<const uint8_t> plaintext,
49 base::span<const uint8_t> nonce,
50 base::span<const uint8_t> additional_data) const {
51 size_t max_output_length =
52 base::CheckAdd(plaintext.size(), EVP_AEAD_max_overhead(aead_))
53 .ValueOrDie();
54 std::vector<uint8_t> ret(max_output_length);
55
56 std::optional<size_t> output_length =
57 Seal(plaintext, nonce, additional_data, ret);
58 CHECK(output_length);
59 ret.resize(*output_length);
60 return ret;
61 }
62
Seal(std::string_view plaintext,std::string_view nonce,std::string_view additional_data,std::string * ciphertext) const63 bool Aead::Seal(std::string_view plaintext,
64 std::string_view nonce,
65 std::string_view additional_data,
66 std::string* ciphertext) const {
67 size_t max_output_length =
68 base::CheckAdd(plaintext.size(), EVP_AEAD_max_overhead(aead_))
69 .ValueOrDie();
70 ciphertext->resize(max_output_length);
71
72 std::optional<size_t> output_length =
73 Seal(base::as_byte_span(plaintext), base::as_byte_span(nonce),
74 base::as_byte_span(additional_data),
75 base::as_writable_byte_span(*ciphertext));
76 if (!output_length) {
77 ciphertext->clear();
78 return false;
79 }
80
81 ciphertext->resize(*output_length);
82 return true;
83 }
84
Open(base::span<const uint8_t> ciphertext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data) const85 std::optional<std::vector<uint8_t>> Aead::Open(
86 base::span<const uint8_t> ciphertext,
87 base::span<const uint8_t> nonce,
88 base::span<const uint8_t> additional_data) const {
89 const size_t max_output_length = ciphertext.size();
90 std::vector<uint8_t> ret(max_output_length);
91
92 std::optional<size_t> output_length =
93 Open(ciphertext, nonce, additional_data, ret);
94 if (!output_length) {
95 return std::nullopt;
96 }
97
98 ret.resize(*output_length);
99 return ret;
100 }
101
Open(std::string_view ciphertext,std::string_view nonce,std::string_view additional_data,std::string * plaintext) const102 bool Aead::Open(std::string_view ciphertext,
103 std::string_view nonce,
104 std::string_view additional_data,
105 std::string* plaintext) const {
106 const size_t max_output_length = ciphertext.size();
107 plaintext->resize(max_output_length);
108
109 std::optional<size_t> output_length =
110 Open(base::as_byte_span(ciphertext), base::as_byte_span(nonce),
111 base::as_byte_span(additional_data),
112 base::as_writable_byte_span(*plaintext));
113 if (!output_length) {
114 plaintext->clear();
115 return false;
116 }
117
118 plaintext->resize(*output_length);
119 return true;
120 }
121
KeyLength() const122 size_t Aead::KeyLength() const {
123 return EVP_AEAD_key_length(aead_);
124 }
125
NonceLength() const126 size_t Aead::NonceLength() const {
127 return EVP_AEAD_nonce_length(aead_);
128 }
129
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) const130 std::optional<size_t> Aead::Seal(base::span<const uint8_t> plaintext,
131 base::span<const uint8_t> nonce,
132 base::span<const uint8_t> additional_data,
133 base::span<uint8_t> out) const {
134 DCHECK(key_);
135 DCHECK_EQ(NonceLength(), nonce.size());
136 bssl::ScopedEVP_AEAD_CTX ctx;
137
138 size_t out_len;
139 if (!EVP_AEAD_CTX_init(ctx.get(), aead_, key_->data(), key_->size(),
140 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) ||
141 !EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
142 nonce.data(), nonce.size(), plaintext.data(),
143 plaintext.size(), additional_data.data(),
144 additional_data.size())) {
145 return std::nullopt;
146 }
147
148 DCHECK_LE(out_len, out.size());
149 return out_len;
150 }
151
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) const152 std::optional<size_t> Aead::Open(base::span<const uint8_t> plaintext,
153 base::span<const uint8_t> nonce,
154 base::span<const uint8_t> additional_data,
155 base::span<uint8_t> out) const {
156 DCHECK(key_);
157 DCHECK_EQ(NonceLength(), nonce.size());
158 bssl::ScopedEVP_AEAD_CTX ctx;
159
160 size_t out_len;
161 if (!EVP_AEAD_CTX_init(ctx.get(), aead_, key_->data(), key_->size(),
162 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) ||
163 !EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
164 nonce.data(), nonce.size(), plaintext.data(),
165 plaintext.size(), additional_data.data(),
166 additional_data.size())) {
167 return std::nullopt;
168 }
169
170 DCHECK_LE(out_len, out.size());
171 return out_len;
172 }
173
174 } // namespace crypto
175