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