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/strings/string_util.h"
12 #include "crypto/openssl_util.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 EnsureOpenSSLInit();
20 switch (algorithm) {
21 case AES_128_CTR_HMAC_SHA256:
22 aead_ = EVP_aead_aes_128_ctr_hmac_sha256();
23 break;
24 case AES_256_GCM:
25 aead_ = EVP_aead_aes_256_gcm();
26 break;
27 case AES_256_GCM_SIV:
28 aead_ = EVP_aead_aes_256_gcm_siv();
29 break;
30 case CHACHA20_POLY1305:
31 aead_ = EVP_aead_chacha20_poly1305();
32 break;
33 }
34 }
35
36 Aead::~Aead() = default;
37
Init(base::span<const uint8_t> key)38 void Aead::Init(base::span<const uint8_t> key) {
39 DCHECK(!key_);
40 DCHECK_EQ(KeyLength(), key.size());
41 key_ = key;
42 }
43
ToSpan(base::StringPiece sp)44 static base::span<const uint8_t> ToSpan(base::StringPiece sp) {
45 return base::as_bytes(base::make_span(sp));
46 }
47
Init(const std::string * key)48 void Aead::Init(const std::string* key) {
49 Init(ToSpan(*key));
50 }
51
Seal(base::span<const uint8_t> plaintext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data) const52 std::vector<uint8_t> Aead::Seal(
53 base::span<const uint8_t> plaintext,
54 base::span<const uint8_t> nonce,
55 base::span<const uint8_t> additional_data) const {
56 const size_t max_output_length =
57 EVP_AEAD_max_overhead(aead_) + plaintext.size();
58 CHECK(max_output_length >= plaintext.size());
59 std::vector<uint8_t> ret;
60 ret.resize(max_output_length);
61
62 size_t output_length;
63 CHECK(Seal(plaintext, nonce, additional_data, ret.data(), &output_length,
64 max_output_length));
65 ret.resize(output_length);
66 return ret;
67 }
68
Seal(base::StringPiece plaintext,base::StringPiece nonce,base::StringPiece additional_data,std::string * ciphertext) const69 bool Aead::Seal(base::StringPiece plaintext,
70 base::StringPiece nonce,
71 base::StringPiece additional_data,
72 std::string* ciphertext) const {
73 const size_t max_output_length =
74 EVP_AEAD_max_overhead(aead_) + plaintext.size();
75 CHECK(max_output_length + 1 >= plaintext.size());
76 uint8_t* out_ptr = reinterpret_cast<uint8_t*>(
77 base::WriteInto(ciphertext, max_output_length + 1));
78
79 size_t output_length;
80 if (!Seal(ToSpan(plaintext), ToSpan(nonce), ToSpan(additional_data), out_ptr,
81 &output_length, max_output_length)) {
82 ciphertext->clear();
83 return false;
84 }
85
86 ciphertext->resize(output_length);
87 return true;
88 }
89
Open(base::span<const uint8_t> ciphertext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data) const90 absl::optional<std::vector<uint8_t>> Aead::Open(
91 base::span<const uint8_t> ciphertext,
92 base::span<const uint8_t> nonce,
93 base::span<const uint8_t> additional_data) const {
94 const size_t max_output_length = ciphertext.size();
95 std::vector<uint8_t> ret;
96 ret.resize(max_output_length);
97
98 size_t output_length;
99 if (!Open(ciphertext, nonce, additional_data, ret.data(), &output_length,
100 max_output_length)) {
101 return absl::nullopt;
102 }
103
104 ret.resize(output_length);
105 return ret;
106 }
107
Open(base::StringPiece ciphertext,base::StringPiece nonce,base::StringPiece additional_data,std::string * plaintext) const108 bool Aead::Open(base::StringPiece ciphertext,
109 base::StringPiece nonce,
110 base::StringPiece additional_data,
111 std::string* plaintext) const {
112 const size_t max_output_length = ciphertext.size();
113 CHECK(max_output_length + 1 > max_output_length);
114 uint8_t* out_ptr = reinterpret_cast<uint8_t*>(
115 base::WriteInto(plaintext, max_output_length + 1));
116
117 size_t output_length;
118 if (!Open(ToSpan(ciphertext), ToSpan(nonce), ToSpan(additional_data), out_ptr,
119 &output_length, max_output_length)) {
120 plaintext->clear();
121 return false;
122 }
123
124 plaintext->resize(output_length);
125 return true;
126 }
127
KeyLength() const128 size_t Aead::KeyLength() const {
129 return EVP_AEAD_key_length(aead_);
130 }
131
NonceLength() const132 size_t Aead::NonceLength() const {
133 return EVP_AEAD_nonce_length(aead_);
134 }
135
Seal(base::span<const uint8_t> plaintext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data,uint8_t * out,size_t * output_length,size_t max_output_length) const136 bool Aead::Seal(base::span<const uint8_t> plaintext,
137 base::span<const uint8_t> nonce,
138 base::span<const uint8_t> additional_data,
139 uint8_t* out,
140 size_t* output_length,
141 size_t max_output_length) const {
142 DCHECK(key_);
143 DCHECK_EQ(NonceLength(), nonce.size());
144 bssl::ScopedEVP_AEAD_CTX ctx;
145
146 if (!EVP_AEAD_CTX_init(ctx.get(), aead_, key_->data(), key_->size(),
147 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) ||
148 !EVP_AEAD_CTX_seal(ctx.get(), out, output_length, max_output_length,
149 nonce.data(), nonce.size(), plaintext.data(),
150 plaintext.size(), additional_data.data(),
151 additional_data.size())) {
152 return false;
153 }
154
155 DCHECK_LE(*output_length, max_output_length);
156 return true;
157 }
158
Open(base::span<const uint8_t> plaintext,base::span<const uint8_t> nonce,base::span<const uint8_t> additional_data,uint8_t * out,size_t * output_length,size_t max_output_length) const159 bool Aead::Open(base::span<const uint8_t> plaintext,
160 base::span<const uint8_t> nonce,
161 base::span<const uint8_t> additional_data,
162 uint8_t* out,
163 size_t* output_length,
164 size_t max_output_length) const {
165 DCHECK(key_);
166 DCHECK_EQ(NonceLength(), nonce.size());
167 bssl::ScopedEVP_AEAD_CTX ctx;
168
169 if (!EVP_AEAD_CTX_init(ctx.get(), aead_, key_->data(), key_->size(),
170 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) ||
171 !EVP_AEAD_CTX_open(ctx.get(), out, output_length, max_output_length,
172 nonce.data(), nonce.size(), plaintext.data(),
173 plaintext.size(), additional_data.data(),
174 additional_data.size())) {
175 return false;
176 }
177
178 DCHECK_LE(*output_length, max_output_length);
179 return true;
180 }
181
182 } // namespace crypto
183