15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/encryptor.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <openssl/aes.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <openssl/evp.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/openssl_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/symmetric_key.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace crypto {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const EVP_CIPHER* GetCipherForKey(SymmetricKey* key) {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (key->key().length()) {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 16: return EVP_aes_128_cbc();
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 24: return EVP_aes_192_cbc();
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 32: return EVP_aes_256_cbc();
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default: return NULL;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On destruction this class will cleanup the ctx, and also clear the OpenSSL
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ERR stack as a convenience.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ScopedCipherCTX {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit ScopedCipherCTX() {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EVP_CIPHER_CTX_init(&ctx_);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~ScopedCipherCTX() {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EVP_CIPHER_CTX_cleanup(&ctx_);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearOpenSSLERRStack(FROM_HERE);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVP_CIPHER_CTX* get() { return &ctx_; }
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVP_CIPHER_CTX ctx_;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Encryptor::Encryptor()
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : key_(NULL),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mode_(CBC) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Encryptor::~Encryptor() {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Init(SymmetricKey* key,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     Mode mode,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const base::StringPiece& iv) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key);
597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(mode == CBC || mode == CTR);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureOpenSSLInit();
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetCipherForKey(key) == NULL)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_ = key;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mode_ = mode;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iv.CopyToString(&iv_);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Encrypt(const base::StringPiece& plaintext,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::string* ciphertext) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!plaintext.empty() || (mode_ == CBC));
777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return (mode_ == CTR) ?
787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      CryptCTR(true, plaintext, ciphertext) :
797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      Crypt(true, plaintext, ciphertext);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Decrypt(const base::StringPiece& ciphertext,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::string* plaintext) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!ciphertext.empty());
857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return (mode_ == CTR) ?
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      CryptCTR(false, ciphertext, plaintext) :
877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      Crypt(false, ciphertext, plaintext);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Crypt(bool do_encrypt,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const base::StringPiece& input,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      std::string* output) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key_);  // Must call Init() before En/De-crypt.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Work on the result in a local variable, and then only transfer it to
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |output| on success to ensure no partial data is returned.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string result;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->clear();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const EVP_CIPHER* cipher = GetCipherForKey(key_);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(cipher);  // Already handled in Init();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& key = key_->key();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(EVP_CIPHER_iv_length(cipher), static_cast<int>(iv_.length()));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(EVP_CIPHER_key_length(cipher), static_cast<int>(key.length()));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedCipherCTX ctx;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EVP_CipherInit_ex(ctx.get(), cipher, NULL,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         reinterpret_cast<const uint8*>(key.data()),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         reinterpret_cast<const uint8*>(iv_.data()),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         do_encrypt))
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When encrypting, add another block size of space to allow for any padding.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GT(output_size, 0u);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GT(output_size + 1, input.size());
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8* out_ptr = reinterpret_cast<uint8*>(WriteInto(&result,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      output_size + 1));
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int out_len;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len,
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        reinterpret_cast<const uint8*>(input.data()),
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        input.length()))
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write out the final block plus padding (if any) to the end of the data
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just written.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tail_len;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len))
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out_len += tail_len;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(out_len, static_cast<int>(output_size));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result.resize(out_len);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->swap(result);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool Encryptor::CryptCTR(bool do_encrypt,
1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                         const base::StringPiece& input,
1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                         std::string* output) {
1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!counter_.get()) {
1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    LOG(ERROR) << "Counter value not set in CTR mode.";
1447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return false;
1457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  AES_KEY aes_key;
1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (AES_set_encrypt_key(reinterpret_cast<const uint8*>(key_->key().data()),
1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                          key_->key().size() * 8, &aes_key) != 0) {
1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return false;
1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const size_t out_size = input.size();
1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  CHECK_GT(out_size, 0u);
1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  CHECK_GT(out_size + 1, input.size());
1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::string result;
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  uint8* out_ptr = reinterpret_cast<uint8*>(WriteInto(&result, out_size + 1));
1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  uint8_t ivec[AES_BLOCK_SIZE] = { 0 };
1617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 };
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  unsigned int block_offset = 0;
1637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  counter_->Write(ivec);
1657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  AES_ctr128_encrypt(reinterpret_cast<const uint8*>(input.data()), out_ptr,
1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     input.size(), &aes_key, ivec, ecount_buf, &block_offset);
1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // AES_ctr128_encrypt() updates |ivec|. Update the |counter_| here.
1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  SetCounter(base::StringPiece(reinterpret_cast<const char*>(ivec),
1717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                               AES_BLOCK_SIZE));
1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  output->swap(result);
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return true;
1757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace crypto
178