• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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