blob: ea12e719aa3c59372d34670adc4186a3a41e7fcc [file] [log] [blame]
[email protected]9eb7b11b2012-03-28 20:19:311// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]2377cdee2011-06-24 20:46:062// 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/encryptor.h"
6
avidd373b8b2015-12-21 21:34:437#include <stddef.h>
8#include <stdint.h>
9
[email protected]2377cdee2011-06-24 20:46:0610#include "base/logging.h"
svaldez22de42fe2016-04-21 19:42:2211#include "base/strings/string_util.h"
[email protected]0e6f6192011-12-28 23:18:2112#include "base/sys_byteorder.h"
svaldez22de42fe2016-04-21 19:42:2213#include "crypto/openssl_util.h"
14#include "crypto/symmetric_key.h"
tfarina29a3a1742016-10-28 18:47:3315#include "third_party/boringssl/src/include/openssl/aes.h"
16#include "third_party/boringssl/src/include/openssl/evp.h"
[email protected]2377cdee2011-06-24 20:46:0617
18namespace crypto {
19
svaldez22de42fe2016-04-21 19:42:2220namespace {
21
Chris Mumfordea3b6c192017-06-09 18:33:1322const EVP_CIPHER* GetCipherForKey(const SymmetricKey* key) {
svaldez22de42fe2016-04-21 19:42:2223 switch (key->key().length()) {
24 case 16: return EVP_aes_128_cbc();
25 case 32: return EVP_aes_256_cbc();
rsleeviffe5a132016-06-28 01:51:5226 default:
27 return nullptr;
svaldez22de42fe2016-04-21 19:42:2228 }
29}
30
svaldez22de42fe2016-04-21 19:42:2231} // namespace
32
[email protected]2377cdee2011-06-24 20:46:0633/////////////////////////////////////////////////////////////////////////////
svaldez22de42fe2016-04-21 19:42:2234// Encryptor Implementation.
35
rsleeviffe5a132016-06-28 01:51:5236Encryptor::Encryptor() : key_(nullptr), mode_(CBC) {}
svaldez22de42fe2016-04-21 19:42:2237
Chris Watkinsa850a302017-11-30 03:53:4938Encryptor::~Encryptor() = default;
svaldez22de42fe2016-04-21 19:42:2239
David Benjamincda45eb2017-11-06 18:16:5240bool Encryptor::Init(const SymmetricKey* key, Mode mode, base::StringPiece iv) {
David Benjamin3efdcb72020-06-16 22:33:0941 return Init(key, mode, base::as_bytes(base::make_span(iv)));
42}
43
44bool Encryptor::Init(const SymmetricKey* key,
45 Mode mode,
46 base::span<const uint8_t> iv) {
svaldez22de42fe2016-04-21 19:42:2247 DCHECK(key);
48 DCHECK(mode == CBC || mode == CTR);
49
50 EnsureOpenSSLInit();
51 if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
52 return false;
David Benjamin47feaaff2020-06-16 22:54:4653 // CTR mode passes the starting counter separately, via SetCounter().
54 if (mode == CTR && !iv.empty())
55 return false;
svaldez22de42fe2016-04-21 19:42:2256
rsleeviffe5a132016-06-28 01:51:5257 if (GetCipherForKey(key) == nullptr)
svaldez22de42fe2016-04-21 19:42:2258 return false;
59
60 key_ = key;
61 mode_ = mode;
David Benjamin3efdcb72020-06-16 22:33:0962 iv_.assign(iv.begin(), iv.end());
svaldez22de42fe2016-04-21 19:42:2263 return true;
64}
65
David Benjamincda45eb2017-11-06 18:16:5266bool Encryptor::Encrypt(base::StringPiece plaintext, std::string* ciphertext) {
David Benjamin3efdcb72020-06-16 22:33:0967 return CryptString(/*do_encrypt=*/true, plaintext, ciphertext);
68}
69
70bool Encryptor::Encrypt(base::span<const uint8_t> plaintext,
71 std::vector<uint8_t>* ciphertext) {
David Benjamin3efdcb72020-06-16 22:33:0972 return CryptBytes(/*do_encrypt=*/true, plaintext, ciphertext);
svaldez22de42fe2016-04-21 19:42:2273}
74
David Benjamincda45eb2017-11-06 18:16:5275bool Encryptor::Decrypt(base::StringPiece ciphertext, std::string* plaintext) {
David Benjamin3efdcb72020-06-16 22:33:0976 return CryptString(/*do_encrypt=*/false, ciphertext, plaintext);
77}
78
79bool Encryptor::Decrypt(base::span<const uint8_t> ciphertext,
80 std::vector<uint8_t>* plaintext) {
David Benjamin3efdcb72020-06-16 22:33:0981 return CryptBytes(/*do_encrypt=*/false, ciphertext, plaintext);
svaldez22de42fe2016-04-21 19:42:2282}
[email protected]2377cdee2011-06-24 20:46:0683
David Benjamincda45eb2017-11-06 18:16:5284bool Encryptor::SetCounter(base::StringPiece counter) {
David Benjamin3efdcb72020-06-16 22:33:0985 return SetCounter(base::as_bytes(base::make_span(counter)));
86}
87
88bool Encryptor::SetCounter(base::span<const uint8_t> counter) {
[email protected]2377cdee2011-06-24 20:46:0689 if (mode_ != CTR)
90 return false;
David Benjamin3efdcb72020-06-16 22:33:0991 if (counter.size() != 16u)
[email protected]2377cdee2011-06-24 20:46:0692 return false;
93
David Benjamin47feaaff2020-06-16 22:54:4694 iv_.assign(counter.begin(), counter.end());
[email protected]2377cdee2011-06-24 20:46:0695 return true;
96}
97
David Benjamin3efdcb72020-06-16 22:33:0998bool Encryptor::CryptString(bool do_encrypt,
99 base::StringPiece input,
100 std::string* output) {
David Benjamina11a4322022-06-07 15:50:51101 std::string result(MaxOutput(do_encrypt, input.size()), '\0');
Anton Bikineeva3f961db2021-05-15 17:56:12102 absl::optional<size_t> len =
David Benjamin3efdcb72020-06-16 22:33:09103 (mode_ == CTR)
104 ? CryptCTR(do_encrypt, base::as_bytes(base::make_span(input)),
David Benjamina11a4322022-06-07 15:50:51105 base::as_writable_bytes(base::make_span(result)))
David Benjamin3efdcb72020-06-16 22:33:09106 : Crypt(do_encrypt, base::as_bytes(base::make_span(input)),
David Benjamina11a4322022-06-07 15:50:51107 base::as_writable_bytes(base::make_span(result)));
David Benjamin3efdcb72020-06-16 22:33:09108 if (!len)
109 return false;
110
111 result.resize(*len);
112 *output = std::move(result);
113 return true;
114}
115
116bool Encryptor::CryptBytes(bool do_encrypt,
117 base::span<const uint8_t> input,
118 std::vector<uint8_t>* output) {
119 std::vector<uint8_t> result(MaxOutput(do_encrypt, input.size()));
Anton Bikineeva3f961db2021-05-15 17:56:12120 absl::optional<size_t> len = (mode_ == CTR)
David Benjamin3efdcb72020-06-16 22:33:09121 ? CryptCTR(do_encrypt, input, result)
122 : Crypt(do_encrypt, input, result);
123 if (!len)
124 return false;
125
126 result.resize(*len);
127 *output = std::move(result);
128 return true;
129}
130
131size_t Encryptor::MaxOutput(bool do_encrypt, size_t length) {
132 size_t result = length + ((do_encrypt && mode_ == CBC) ? 16 : 0);
133 CHECK_GE(result, length); // Overflow
134 return result;
135}
136
Anton Bikineeva3f961db2021-05-15 17:56:12137absl::optional<size_t> Encryptor::Crypt(bool do_encrypt,
David Benjamin3efdcb72020-06-16 22:33:09138 base::span<const uint8_t> input,
139 base::span<uint8_t> output) {
140 DCHECK(key_); // Must call Init() before En/De-crypt.
svaldez22de42fe2016-04-21 19:42:22141
142 const EVP_CIPHER* cipher = GetCipherForKey(key_);
143 DCHECK(cipher); // Already handled in Init();
144
145 const std::string& key = key_->key();
David Benjamin3efdcb72020-06-16 22:33:09146 DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.size());
147 DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.size());
svaldez22de42fe2016-04-21 19:42:22148
David Benjamin47feaaff2020-06-16 22:54:46149 OpenSSLErrStackTracer err_tracer(FROM_HERE);
150 bssl::ScopedEVP_CIPHER_CTX ctx;
rsleeviffe5a132016-06-28 01:51:52151 if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr,
152 reinterpret_cast<const uint8_t*>(key.data()),
David Benjamin3efdcb72020-06-16 22:33:09153 iv_.data(), do_encrypt)) {
Anton Bikineeva3f961db2021-05-15 17:56:12154 return absl::nullopt;
David Benjamin3efdcb72020-06-16 22:33:09155 }
svaldez22de42fe2016-04-21 19:42:22156
David Benjamin3efdcb72020-06-16 22:33:09157 // Encrypting needs a block size of space to allow for any padding.
158 CHECK_GE(output.size(), input.size() + (do_encrypt ? iv_.size() : 0));
svaldez22de42fe2016-04-21 19:42:22159 int out_len;
David Benjamin3efdcb72020-06-16 22:33:09160 if (!EVP_CipherUpdate(ctx.get(), output.data(), &out_len, input.data(),
161 input.size()))
Anton Bikineeva3f961db2021-05-15 17:56:12162 return absl::nullopt;
svaldez22de42fe2016-04-21 19:42:22163
164 // Write out the final block plus padding (if any) to the end of the data
165 // just written.
166 int tail_len;
David Benjamin3efdcb72020-06-16 22:33:09167 if (!EVP_CipherFinal_ex(ctx.get(), output.data() + out_len, &tail_len))
Anton Bikineeva3f961db2021-05-15 17:56:12168 return absl::nullopt;
svaldez22de42fe2016-04-21 19:42:22169
170 out_len += tail_len;
David Benjamin3efdcb72020-06-16 22:33:09171 DCHECK_LE(out_len, static_cast<int>(output.size()));
172 return out_len;
svaldez22de42fe2016-04-21 19:42:22173}
174
Anton Bikineeva3f961db2021-05-15 17:56:12175absl::optional<size_t> Encryptor::CryptCTR(bool do_encrypt,
David Benjamin3efdcb72020-06-16 22:33:09176 base::span<const uint8_t> input,
177 base::span<uint8_t> output) {
David Benjamin47feaaff2020-06-16 22:54:46178 if (iv_.size() != AES_BLOCK_SIZE) {
svaldez22de42fe2016-04-21 19:42:22179 LOG(ERROR) << "Counter value not set in CTR mode.";
Anton Bikineeva3f961db2021-05-15 17:56:12180 return absl::nullopt;
svaldez22de42fe2016-04-21 19:42:22181 }
182
183 AES_KEY aes_key;
184 if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key_->key().data()),
185 key_->key().size() * 8, &aes_key) != 0) {
Anton Bikineeva3f961db2021-05-15 17:56:12186 return absl::nullopt;
svaldez22de42fe2016-04-21 19:42:22187 }
188
svaldez22de42fe2016-04-21 19:42:22189 uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 };
190 unsigned int block_offset = 0;
191
David Benjamin3efdcb72020-06-16 22:33:09192 // |output| must have room for |input|.
193 CHECK_GE(output.size(), input.size());
David Benjamin47feaaff2020-06-16 22:54:46194 // Note AES_ctr128_encrypt() will update |iv_|. However, this method discards
195 // |ecount_buf| and |block_offset|, so this is not quite a streaming API.
196 AES_ctr128_encrypt(input.data(), output.data(), input.size(), &aes_key,
197 iv_.data(), ecount_buf, &block_offset);
David Benjamin3efdcb72020-06-16 22:33:09198 return input.size();
svaldez22de42fe2016-04-21 19:42:22199}
200
[email protected]2377cdee2011-06-24 20:46:06201} // namespace crypto