From 399c965b6064c440ddcf4015f5f8e9d131c7a0a6 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 14 Jul 2016 17:41:05 +0200 Subject: BASELINE: Update Chromium to 52.0.2743.76 and Ninja to 1.7.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I382f51b959689505a60f8b707255ecb344f7d8b4 Reviewed-by: Michael BrĂ¼ning --- chromium/crypto/encryptor.cc | 166 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) (limited to 'chromium/crypto/encryptor.cc') diff --git a/chromium/crypto/encryptor.cc b/chromium/crypto/encryptor.cc index 7872774e301..a9f9a9d5dce 100644 --- a/chromium/crypto/encryptor.cc +++ b/chromium/crypto/encryptor.cc @@ -4,14 +4,48 @@ #include "crypto/encryptor.h" +#include +#include #include #include #include "base/logging.h" +#include "base/strings/string_util.h" #include "base/sys_byteorder.h" +#include "crypto/openssl_util.h" +#include "crypto/symmetric_key.h" namespace crypto { +namespace { + +const EVP_CIPHER* GetCipherForKey(SymmetricKey* key) { + switch (key->key().length()) { + case 16: return EVP_aes_128_cbc(); + case 32: return EVP_aes_256_cbc(); + default: return NULL; + } +} + +// On destruction this class will cleanup the ctx, and also clear the OpenSSL +// ERR stack as a convenience. +class ScopedCipherCTX { + public: + explicit 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(const base::StringPiece& counter) { @@ -48,7 +82,50 @@ size_t Encryptor::Counter::GetLengthInBytes() const { } ///////////////////////////////////////////////////////////////////////////// -// Partial Encryptor Implementation. +// Encryptor Implementation. + +Encryptor::Encryptor() + : key_(NULL), + mode_(CBC) { +} + +Encryptor::~Encryptor() { +} + +bool Encryptor::Init(SymmetricKey* key, + Mode mode, + const base::StringPiece& iv) { + DCHECK(key); + DCHECK(mode == CBC || mode == CTR); + + EnsureOpenSSLInit(); + if (mode == CBC && iv.size() != AES_BLOCK_SIZE) + return false; + + if (GetCipherForKey(key) == NULL) + return false; + + key_ = key; + mode_ = mode; + iv.CopyToString(&iv_); + return true; +} + +bool Encryptor::Encrypt(const base::StringPiece& plaintext, + std::string* ciphertext) { + CHECK(!plaintext.empty() || (mode_ == CBC)); + return (mode_ == CTR) ? + CryptCTR(true, plaintext, ciphertext) : + Crypt(true, plaintext, ciphertext); +} + +bool Encryptor::Decrypt(const base::StringPiece& ciphertext, + std::string* plaintext) { + CHECK(!ciphertext.empty()); + return (mode_ == CTR) ? + CryptCTR(false, ciphertext, plaintext) : + Crypt(false, ciphertext, plaintext); +} bool Encryptor::SetCounter(const base::StringPiece& counter) { if (mode_ != CTR) @@ -97,4 +174,91 @@ void Encryptor::MaskMessage(const void* plaintext, ciphertext_ptr[i] = plaintext_ptr[i] ^ mask_ptr[i]; } +bool Encryptor::Crypt(bool do_encrypt, + const 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. + std::string result; + output->clear(); + + 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()); + + ScopedCipherCTX ctx; + if (!EVP_CipherInit_ex( + ctx.get(), cipher, NULL, reinterpret_cast(key.data()), + reinterpret_cast(iv_.data()), do_encrypt)) + return false; + + // 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(base::WriteInto(&result, output_size + 1)); + int out_len; + if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len, + reinterpret_cast(input.data()), + input.length())) + return false; + + // 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; + + out_len += tail_len; + DCHECK_LE(out_len, static_cast(output_size)); + result.resize(out_len); + + output->swap(result); + return true; +} + +bool Encryptor::CryptCTR(bool do_encrypt, + const base::StringPiece& input, + std::string* output) { + if (!counter_.get()) { + LOG(ERROR) << "Counter value not set in CTR mode."; + return false; + } + + AES_KEY aes_key; + if (AES_set_encrypt_key(reinterpret_cast(key_->key().data()), + key_->key().size() * 8, &aes_key) != 0) { + return false; + } + + 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(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(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(ivec), + AES_BLOCK_SIZE)); + + output->swap(result); + return true; +} + } // namespace crypto -- cgit v1.2.1