summaryrefslogtreecommitdiff
path: root/chromium/crypto/encryptor.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/crypto/encryptor.cc
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/crypto/encryptor.cc')
-rw-r--r--chromium/crypto/encryptor.cc224
1 files changed, 107 insertions, 117 deletions
diff --git a/chromium/crypto/encryptor.cc b/chromium/crypto/encryptor.cc
index a58522c9311..d7da5a80199 100644
--- a/chromium/crypto/encryptor.cc
+++ b/chromium/crypto/encryptor.cc
@@ -28,60 +28,9 @@ const EVP_CIPHER* GetCipherForKey(const SymmetricKey* key) {
}
}
-// On destruction this class will cleanup the ctx, and also clear the OpenSSL
-// ERR stack as a convenience.
-class ScopedCipherCTX {
- public:
- ScopedCipherCTX() {
- EVP_CIPHER_CTX_init(&ctx_);
- }
- ~ScopedCipherCTX() {
- EVP_CIPHER_CTX_cleanup(&ctx_);
- ClearOpenSSLERRStack(FROM_HERE);
- }
- EVP_CIPHER_CTX* get() { return &ctx_; }
-
- private:
- EVP_CIPHER_CTX ctx_;
-};
-
} // namespace
/////////////////////////////////////////////////////////////////////////////
-// Encyptor::Counter Implementation.
-Encryptor::Counter::Counter(base::StringPiece counter) {
- CHECK(sizeof(counter_) == counter.length());
-
- memcpy(&counter_, counter.data(), sizeof(counter_));
-}
-
-Encryptor::Counter::~Counter() = default;
-
-bool Encryptor::Counter::Increment() {
- uint64_t low_num = base::NetToHost64(counter_.components64[1]);
- uint64_t new_low_num = low_num + 1;
- counter_.components64[1] = base::HostToNet64(new_low_num);
-
- // If overflow occured then increment the most significant component.
- if (new_low_num < low_num) {
- counter_.components64[0] =
- base::HostToNet64(base::NetToHost64(counter_.components64[0]) + 1);
- }
-
- // TODO(hclam): Return false if counter value overflows.
- return true;
-}
-
-void Encryptor::Counter::Write(void* buf) {
- uint8_t* buf_ptr = reinterpret_cast<uint8_t*>(buf);
- memcpy(buf_ptr, &counter_, sizeof(counter_));
-}
-
-size_t Encryptor::Counter::GetLengthInBytes() const {
- return sizeof(counter_);
-}
-
-/////////////////////////////////////////////////////////////////////////////
// Encryptor Implementation.
Encryptor::Encryptor() : key_(nullptr), mode_(CBC) {}
@@ -89,132 +38,173 @@ Encryptor::Encryptor() : key_(nullptr), mode_(CBC) {}
Encryptor::~Encryptor() = default;
bool Encryptor::Init(const SymmetricKey* key, Mode mode, base::StringPiece iv) {
+ return Init(key, mode, base::as_bytes(base::make_span(iv)));
+}
+
+bool Encryptor::Init(const SymmetricKey* key,
+ Mode mode,
+ base::span<const uint8_t> iv) {
DCHECK(key);
DCHECK(mode == CBC || mode == CTR);
EnsureOpenSSLInit();
if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
return false;
+ // CTR mode passes the starting counter separately, via SetCounter().
+ if (mode == CTR && !iv.empty())
+ return false;
if (GetCipherForKey(key) == nullptr)
return false;
key_ = key;
mode_ = mode;
- iv_ = std::string(iv);
+ iv_.assign(iv.begin(), iv.end());
return true;
}
bool Encryptor::Encrypt(base::StringPiece plaintext, std::string* ciphertext) {
- CHECK(!plaintext.empty() || (mode_ == CBC));
- return (mode_ == CTR) ?
- CryptCTR(true, plaintext, ciphertext) :
- Crypt(true, plaintext, ciphertext);
+ CHECK(!plaintext.empty() || mode_ == CBC);
+ return CryptString(/*do_encrypt=*/true, plaintext, ciphertext);
+}
+
+bool Encryptor::Encrypt(base::span<const uint8_t> plaintext,
+ std::vector<uint8_t>* ciphertext) {
+ CHECK(!plaintext.empty() || mode_ == CBC);
+ return CryptBytes(/*do_encrypt=*/true, plaintext, ciphertext);
}
bool Encryptor::Decrypt(base::StringPiece ciphertext, std::string* plaintext) {
CHECK(!ciphertext.empty());
- return (mode_ == CTR) ?
- CryptCTR(false, ciphertext, plaintext) :
- Crypt(false, ciphertext, plaintext);
+ return CryptString(/*do_encrypt=*/false, ciphertext, plaintext);
+}
+
+bool Encryptor::Decrypt(base::span<const uint8_t> ciphertext,
+ std::vector<uint8_t>* plaintext) {
+ CHECK(!ciphertext.empty());
+ return CryptBytes(/*do_encrypt=*/false, ciphertext, plaintext);
}
bool Encryptor::SetCounter(base::StringPiece counter) {
+ return SetCounter(base::as_bytes(base::make_span(counter)));
+}
+
+bool Encryptor::SetCounter(base::span<const uint8_t> counter) {
if (mode_ != CTR)
return false;
- if (counter.length() != 16u)
+ if (counter.size() != 16u)
return false;
- counter_.reset(new Counter(counter));
+ iv_.assign(counter.begin(), counter.end());
return true;
}
-bool Encryptor::Crypt(bool do_encrypt,
- base::StringPiece input,
- std::string* output) {
- DCHECK(key_); // Must call Init() before En/De-crypt.
- // Work on the result in a local variable, and then only transfer it to
- // |output| on success to ensure no partial data is returned.
+bool Encryptor::CryptString(bool do_encrypt,
+ base::StringPiece input,
+ std::string* output) {
+ size_t out_size = MaxOutput(do_encrypt, input.size());
+ CHECK_GT(out_size + 1, out_size); // Overflow
std::string result;
- output->clear();
+ uint8_t* out_ptr =
+ reinterpret_cast<uint8_t*>(base::WriteInto(&result, out_size + 1));
+
+ base::Optional<size_t> len =
+ (mode_ == CTR)
+ ? CryptCTR(do_encrypt, base::as_bytes(base::make_span(input)),
+ base::make_span(out_ptr, out_size))
+ : Crypt(do_encrypt, base::as_bytes(base::make_span(input)),
+ base::make_span(out_ptr, out_size));
+ if (!len)
+ return false;
+
+ result.resize(*len);
+ *output = std::move(result);
+ return true;
+}
+
+bool Encryptor::CryptBytes(bool do_encrypt,
+ base::span<const uint8_t> input,
+ std::vector<uint8_t>* output) {
+ std::vector<uint8_t> result(MaxOutput(do_encrypt, input.size()));
+ base::Optional<size_t> len = (mode_ == CTR)
+ ? CryptCTR(do_encrypt, input, result)
+ : Crypt(do_encrypt, input, result);
+ if (!len)
+ return false;
+
+ result.resize(*len);
+ *output = std::move(result);
+ return true;
+}
+
+size_t Encryptor::MaxOutput(bool do_encrypt, size_t length) {
+ size_t result = length + ((do_encrypt && mode_ == CBC) ? 16 : 0);
+ CHECK_GE(result, length); // Overflow
+ return result;
+}
+
+base::Optional<size_t> Encryptor::Crypt(bool do_encrypt,
+ base::span<const uint8_t> input,
+ base::span<uint8_t> output) {
+ DCHECK(key_); // Must call Init() before En/De-crypt.
const EVP_CIPHER* cipher = GetCipherForKey(key_);
DCHECK(cipher); // Already handled in Init();
const std::string& key = key_->key();
- DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.length());
- DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.length());
+ DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.size());
+ DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.size());
- ScopedCipherCTX ctx;
+ OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ bssl::ScopedEVP_CIPHER_CTX ctx;
if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr,
reinterpret_cast<const uint8_t*>(key.data()),
- reinterpret_cast<const uint8_t*>(iv_.data()),
- do_encrypt))
- return false;
+ iv_.data(), do_encrypt)) {
+ return base::nullopt;
+ }
- // When encrypting, add another block size of space to allow for any padding.
- const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0);
- CHECK_GT(output_size, 0u);
- CHECK_GT(output_size + 1, input.size());
- uint8_t* out_ptr =
- reinterpret_cast<uint8_t*>(base::WriteInto(&result, output_size + 1));
+ // Encrypting needs a block size of space to allow for any padding.
+ CHECK_GE(output.size(), input.size() + (do_encrypt ? iv_.size() : 0));
int out_len;
- if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len,
- reinterpret_cast<const uint8_t*>(input.data()),
- input.length()))
- return false;
+ if (!EVP_CipherUpdate(ctx.get(), output.data(), &out_len, input.data(),
+ input.size()))
+ return base::nullopt;
// Write out the final block plus padding (if any) to the end of the data
// just written.
int tail_len;
- if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len))
- return false;
+ if (!EVP_CipherFinal_ex(ctx.get(), output.data() + out_len, &tail_len))
+ return base::nullopt;
out_len += tail_len;
- DCHECK_LE(out_len, static_cast<int>(output_size));
- result.resize(out_len);
-
- output->swap(result);
- return true;
+ DCHECK_LE(out_len, static_cast<int>(output.size()));
+ return out_len;
}
-bool Encryptor::CryptCTR(bool do_encrypt,
- base::StringPiece input,
- std::string* output) {
- if (!counter_.get()) {
+base::Optional<size_t> Encryptor::CryptCTR(bool do_encrypt,
+ base::span<const uint8_t> input,
+ base::span<uint8_t> output) {
+ if (iv_.size() != AES_BLOCK_SIZE) {
LOG(ERROR) << "Counter value not set in CTR mode.";
- return false;
+ return base::nullopt;
}
AES_KEY aes_key;
if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key_->key().data()),
key_->key().size() * 8, &aes_key) != 0) {
- return false;
+ return base::nullopt;
}
- const size_t out_size = input.size();
- CHECK_GT(out_size, 0u);
- CHECK_GT(out_size + 1, input.size());
-
- std::string result;
- uint8_t* out_ptr =
- reinterpret_cast<uint8_t*>(base::WriteInto(&result, out_size + 1));
-
- uint8_t ivec[AES_BLOCK_SIZE] = { 0 };
uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 };
unsigned int block_offset = 0;
- counter_->Write(ivec);
-
- AES_ctr128_encrypt(reinterpret_cast<const uint8_t*>(input.data()), out_ptr,
- input.size(), &aes_key, ivec, ecount_buf, &block_offset);
-
- // AES_ctr128_encrypt() updates |ivec|. Update the |counter_| here.
- SetCounter(base::StringPiece(reinterpret_cast<const char*>(ivec),
- AES_BLOCK_SIZE));
-
- output->swap(result);
- return true;
+ // |output| must have room for |input|.
+ CHECK_GE(output.size(), input.size());
+ // Note AES_ctr128_encrypt() will update |iv_|. However, this method discards
+ // |ecount_buf| and |block_offset|, so this is not quite a streaming API.
+ AES_ctr128_encrypt(input.data(), output.data(), input.size(), &aes_key,
+ iv_.data(), ecount_buf, &block_offset);
+ return input.size();
}
} // namespace crypto