// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "crypto/encryptor.h" #include <cryptohi.h> #include <vector> #include "base/logging.h" #include "crypto/nss_util.h" #include "crypto/symmetric_key.h" namespace crypto { Encryptor::Encryptor() : key_(NULL), mode_(CBC) { EnsureNSSInit(); } Encryptor::~Encryptor() { } bool Encryptor::Init(SymmetricKey* key, Mode mode, const std::string& iv) { DCHECK(key); DCHECK_EQ(CBC, mode); key_ = key; mode_ = mode; if (iv.size() != AES_BLOCK_SIZE) return false; slot_.reset(PK11_GetBestSlot(CKM_AES_CBC_PAD, NULL)); if (!slot_.get()) return false; SECItem iv_item; iv_item.type = siBuffer; iv_item.data = reinterpret_cast<unsigned char*>( const_cast<char *>(iv.data())); iv_item.len = iv.size(); param_.reset(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); if (!param_.get()) return false; return true; } bool Encryptor::Encrypt(const std::string& plaintext, std::string* ciphertext) { ScopedPK11Context context(PK11_CreateContextBySymKey(CKM_AES_CBC_PAD, CKA_ENCRYPT, key_->key(), param_.get())); if (!context.get()) return false; size_t ciphertext_len = plaintext.size() + AES_BLOCK_SIZE; std::vector<unsigned char> buffer(ciphertext_len); int op_len; SECStatus rv = PK11_CipherOp(context.get(), &buffer[0], &op_len, ciphertext_len, reinterpret_cast<unsigned char*>( const_cast<char*>(plaintext.data())), plaintext.size()); if (SECSuccess != rv) return false; unsigned int digest_len; rv = PK11_DigestFinal(context.get(), &buffer[op_len], &digest_len, ciphertext_len - op_len); if (SECSuccess != rv) return false; ciphertext->assign(reinterpret_cast<char *>(&buffer[0]), op_len + digest_len); return true; } bool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) { if (ciphertext.empty()) return false; ScopedPK11Context context(PK11_CreateContextBySymKey(CKM_AES_CBC_PAD, CKA_DECRYPT, key_->key(), param_.get())); if (!context.get()) return false; size_t plaintext_len = ciphertext.size(); std::vector<unsigned char> buffer(plaintext_len); int op_len; SECStatus rv = PK11_CipherOp(context.get(), &buffer[0], &op_len, plaintext_len, reinterpret_cast<unsigned char*>( const_cast<char*>(ciphertext.data())), ciphertext.size()); if (SECSuccess != rv) return false; unsigned int digest_len; rv = PK11_DigestFinal(context.get(), &buffer[op_len], &digest_len, plaintext_len - op_len); if (SECSuccess != rv) return false; plaintext->assign(reinterpret_cast<char *>(&buffer[0]), op_len + digest_len); return true; } } // namespace crypto