Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "crypto/encryptor.h"
      6 
      7 #include <cryptohi.h>
      8 #include <vector>
      9 
     10 #include "base/logging.h"
     11 #include "crypto/nss_util.h"
     12 #include "crypto/symmetric_key.h"
     13 
     14 namespace crypto {
     15 
     16 Encryptor::Encryptor()
     17     : key_(NULL),
     18       mode_(CBC) {
     19   EnsureNSSInit();
     20 }
     21 
     22 Encryptor::~Encryptor() {
     23 }
     24 
     25 bool Encryptor::Init(SymmetricKey* key, Mode mode, const std::string& iv) {
     26   DCHECK(key);
     27   DCHECK_EQ(CBC, mode);
     28 
     29   key_ = key;
     30   mode_ = mode;
     31 
     32   if (iv.size() != AES_BLOCK_SIZE)
     33     return false;
     34 
     35   slot_.reset(PK11_GetBestSlot(CKM_AES_CBC_PAD, NULL));
     36   if (!slot_.get())
     37     return false;
     38 
     39   SECItem iv_item;
     40   iv_item.type = siBuffer;
     41   iv_item.data = reinterpret_cast<unsigned char*>(
     42       const_cast<char *>(iv.data()));
     43   iv_item.len = iv.size();
     44 
     45   param_.reset(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item));
     46   if (!param_.get())
     47     return false;
     48 
     49   return true;
     50 }
     51 
     52 bool Encryptor::Encrypt(const std::string& plaintext, std::string* ciphertext) {
     53   ScopedPK11Context context(PK11_CreateContextBySymKey(CKM_AES_CBC_PAD,
     54                                                        CKA_ENCRYPT,
     55                                                        key_->key(),
     56                                                        param_.get()));
     57   if (!context.get())
     58     return false;
     59 
     60   size_t ciphertext_len = plaintext.size() + AES_BLOCK_SIZE;
     61   std::vector<unsigned char> buffer(ciphertext_len);
     62 
     63   int op_len;
     64   SECStatus rv = PK11_CipherOp(context.get(),
     65                                &buffer[0],
     66                                &op_len,
     67                                ciphertext_len,
     68                                reinterpret_cast<unsigned char*>(
     69                                    const_cast<char*>(plaintext.data())),
     70                                plaintext.size());
     71   if (SECSuccess != rv)
     72     return false;
     73 
     74   unsigned int digest_len;
     75   rv = PK11_DigestFinal(context.get(),
     76                         &buffer[op_len],
     77                         &digest_len,
     78                         ciphertext_len - op_len);
     79   if (SECSuccess != rv)
     80     return false;
     81 
     82   ciphertext->assign(reinterpret_cast<char *>(&buffer[0]),
     83                      op_len + digest_len);
     84   return true;
     85 }
     86 
     87 bool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) {
     88   if (ciphertext.empty())
     89     return false;
     90 
     91   ScopedPK11Context context(PK11_CreateContextBySymKey(CKM_AES_CBC_PAD,
     92                                                        CKA_DECRYPT,
     93                                                        key_->key(),
     94                                                        param_.get()));
     95   if (!context.get())
     96     return false;
     97 
     98   size_t plaintext_len = ciphertext.size();
     99   std::vector<unsigned char> buffer(plaintext_len);
    100 
    101   int op_len;
    102   SECStatus rv = PK11_CipherOp(context.get(),
    103                                &buffer[0],
    104                                &op_len,
    105                                plaintext_len,
    106                                reinterpret_cast<unsigned char*>(
    107                                    const_cast<char*>(ciphertext.data())),
    108                                ciphertext.size());
    109   if (SECSuccess != rv)
    110     return false;
    111 
    112   unsigned int digest_len;
    113   rv = PK11_DigestFinal(context.get(),
    114                         &buffer[op_len],
    115                         &digest_len,
    116                         plaintext_len - op_len);
    117   if (SECSuccess != rv)
    118     return false;
    119 
    120   plaintext->assign(reinterpret_cast<char *>(&buffer[0]),
    121                     op_len + digest_len);
    122   return true;
    123 }
    124 
    125 }  // namespace crypto
    126