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 <cryptohi.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/nss_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/symmetric_key.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace crypto {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline CK_MECHANISM_TYPE GetMechanism(Encryptor::Mode mode) {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (mode) {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Encryptor::CBC:
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return CKM_AES_CBC_PAD;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case Encryptor::CTR:
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // AES-CTR encryption uses ECB encryptor as a building block since
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // NSS doesn't support CTR encryption mode.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return CKM_AES_ECB;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Unsupported mode of operation";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<CK_MECHANISM_TYPE>(-1);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Encryptor::Encryptor()
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : key_(NULL),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mode_(CBC) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureNSSInit();
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Encryptor::~Encryptor() {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Init(SymmetricKey* key,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     Mode mode,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const base::StringPiece& iv) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CBC == mode || CTR == mode) << "Unsupported mode of operation";
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_ = key;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mode_ = mode;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (mode) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CBC:
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SECItem iv_item;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iv_item.type = siBuffer;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iv_item.data = reinterpret_cast<unsigned char*>(
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          const_cast<char *>(iv.data()));
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iv_item.len = iv.size();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param_.reset(PK11_ParamFromIV(GetMechanism(mode), &iv_item));
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CTR:
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param_.reset(PK11_ParamFromIV(GetMechanism(mode), NULL));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return param_ != NULL;
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));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedPK11Context context(PK11_CreateContextBySymKey(GetMechanism(mode_),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       CKA_ENCRYPT,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       key_->key(),
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       param_.get()));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!context.get())
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (mode_ == CTR) ?
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CryptCTR(context.get(), plaintext, ciphertext) :
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Crypt(context.get(), plaintext, ciphertext);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Decrypt(const base::StringPiece& ciphertext,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::string* plaintext) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!ciphertext.empty());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedPK11Context context(PK11_CreateContextBySymKey(
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetMechanism(mode_), (mode_ == CTR ? CKA_ENCRYPT : CKA_DECRYPT),
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_->key(), param_.get()));
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!context.get())
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (mode_ == CTR)
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return CryptCTR(context.get(), ciphertext, plaintext);
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (ciphertext.size() % AES_BLOCK_SIZE != 0) {
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Decryption will fail if the input is not a multiple of the block size.
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // PK11_CipherOp has a bug where it will do an invalid memory access before
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // the start of the input, so avoid calling it. (NSS bug 922780).
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    plaintext->clear();
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return false;
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return Crypt(context.get(), ciphertext, plaintext);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Crypt(PK11Context* context,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const base::StringPiece& input,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      std::string* output) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t output_len = input.size() + AES_BLOCK_SIZE;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GT(output_len, input.size());
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->resize(output_len);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8* output_data =
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int input_len = input.size();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8* input_data =
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<uint8*>(const_cast<char*>(input.data()));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int op_len;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = PK11_CipherOp(context,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               output_data,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &op_len,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               output_len,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               input_data,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               input_len);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SECSuccess != rv) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output->clear();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int digest_len;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rv = PK11_DigestFinal(context,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        output_data + op_len,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        &digest_len,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        output_len - op_len);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SECSuccess != rv) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output->clear();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->resize(op_len + digest_len);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::CryptCTR(PK11Context* context,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const base::StringPiece& input,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         std::string* output) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!counter_.get()) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Counter value not set in CTR mode.";
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t output_len = ((input.size() + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) *
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AES_BLOCK_SIZE;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GE(output_len, input.size());
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->resize(output_len);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8* output_data =
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<uint8*>(const_cast<char*>(output->data()));
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t mask_len;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ret = GenerateCounterMask(input.size(), output_data, &mask_len);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ret)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(mask_len, output_len);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int op_len;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = PK11_CipherOp(context,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               output_data,
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &op_len,
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               output_len,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               output_data,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               mask_len);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SECSuccess != rv)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(static_cast<int>(mask_len), op_len);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int digest_len;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rv = PK11_DigestFinal(context,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        NULL,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        &digest_len,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        0);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SECSuccess != rv)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!digest_len);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use |output_data| to mask |input|.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaskMessage(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<uint8*>(const_cast<char*>(input.data())),
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input.length(), output_data, output_data);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->resize(input.length());
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace crypto
203