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