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 32: return EVP_aes_256_cbc();
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default: return NULL;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On destruction this class will cleanup the ctx, and also clear the OpenSSL
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ERR stack as a convenience.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ScopedCipherCTX {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit ScopedCipherCTX() {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EVP_CIPHER_CTX_init(&ctx_);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~ScopedCipherCTX() {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EVP_CIPHER_CTX_cleanup(&ctx_);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearOpenSSLERRStack(FROM_HERE);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVP_CIPHER_CTX* get() { return &ctx_; }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVP_CIPHER_CTX ctx_;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Encryptor::Encryptor()
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : key_(NULL),
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mode_(CBC) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Encryptor::~Encryptor() {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Init(SymmetricKey* key,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     Mode mode,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const base::StringPiece& iv) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key);
587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(mode == CBC || mode == CTR);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureOpenSSLInit();
617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetCipherForKey(key) == NULL)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_ = key;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mode_ = mode;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iv.CopyToString(&iv_);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Encrypt(const base::StringPiece& plaintext,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::string* ciphertext) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!plaintext.empty() || (mode_ == CBC));
767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return (mode_ == CTR) ?
777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      CryptCTR(true, plaintext, ciphertext) :
787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      Crypt(true, plaintext, ciphertext);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Decrypt(const base::StringPiece& ciphertext,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::string* plaintext) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!ciphertext.empty());
847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return (mode_ == CTR) ?
857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      CryptCTR(false, ciphertext, plaintext) :
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      Crypt(false, ciphertext, plaintext);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Crypt(bool do_encrypt,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const base::StringPiece& input,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      std::string* output) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key_);  // Must call Init() before En/De-crypt.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Work on the result in a local variable, and then only transfer it to
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |output| on success to ensure no partial data is returned.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string result;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->clear();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const EVP_CIPHER* cipher = GetCipherForKey(key_);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(cipher);  // Already handled in Init();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& key = key_->key();
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.length());
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.length());
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedCipherCTX ctx;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EVP_CipherInit_ex(ctx.get(), cipher, NULL,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         reinterpret_cast<const uint8*>(key.data()),
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         reinterpret_cast<const uint8*>(iv_.data()),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         do_encrypt))
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When encrypting, add another block size of space to allow for any padding.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GT(output_size, 0u);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GT(output_size + 1, input.size());
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8* out_ptr = reinterpret_cast<uint8*>(WriteInto(&result,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      output_size + 1));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int out_len;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        reinterpret_cast<const uint8*>(input.data()),
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        input.length()))
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write out the final block plus padding (if any) to the end of the data
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just written.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tail_len;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len))
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out_len += tail_len;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(out_len, static_cast<int>(output_size));
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result.resize(out_len);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->swap(result);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool Encryptor::CryptCTR(bool do_encrypt,
1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                         const base::StringPiece& input,
1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                         std::string* output) {
1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!counter_.get()) {
1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    LOG(ERROR) << "Counter value not set in CTR mode.";
1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return false;
1447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  AES_KEY aes_key;
1477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (AES_set_encrypt_key(reinterpret_cast<const uint8*>(key_->key().data()),
1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                          key_->key().size() * 8, &aes_key) != 0) {
1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return false;
1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const size_t out_size = input.size();
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  CHECK_GT(out_size, 0u);
1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  CHECK_GT(out_size + 1, input.size());
1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  std::string result;
1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  uint8* out_ptr = reinterpret_cast<uint8*>(WriteInto(&result, out_size + 1));
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  uint8_t ivec[AES_BLOCK_SIZE] = { 0 };
1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 };
1617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  unsigned int block_offset = 0;
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  counter_->Write(ivec);
1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  AES_ctr128_encrypt(reinterpret_cast<const uint8*>(input.data()), out_ptr,
1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     input.size(), &aes_key, ivec, ecount_buf, &block_offset);
1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // AES_ctr128_encrypt() updates |ivec|. Update the |counter_| here.
1697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  SetCounter(base::StringPiece(reinterpret_cast<const char*>(ivec),
1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                               AES_BLOCK_SIZE));
1717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  output->swap(result);
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return true;
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace crypto
177