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 <openssl/aes.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <openssl/evp.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/openssl_util.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/symmetric_key.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace crypto { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const EVP_CIPHER* GetCipherForKey(SymmetricKey* key) { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (key->key().length()) { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 16: return EVP_aes_128_cbc(); 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 32: return EVP_aes_256_cbc(); 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: return NULL; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On destruction this class will cleanup the ctx, and also clear the OpenSSL 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ERR stack as a convenience. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ScopedCipherCTX { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit ScopedCipherCTX() { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EVP_CIPHER_CTX_init(&ctx_); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~ScopedCipherCTX() { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EVP_CIPHER_CTX_cleanup(&ctx_); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClearOpenSSLERRStack(FROM_HERE); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EVP_CIPHER_CTX* get() { return &ctx_; } 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EVP_CIPHER_CTX ctx_; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Encryptor::Encryptor() 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : key_(NULL), 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mode_(CBC) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Encryptor::~Encryptor() { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Init(SymmetricKey* key, 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mode mode, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::StringPiece& iv) { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(key); 587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(mode == CBC || mode == CTR); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureOpenSSLInit(); 617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (mode == CBC && iv.size() != AES_BLOCK_SIZE) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetCipherForKey(key) == NULL) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_ = key; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mode_ = mode; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iv.CopyToString(&iv_); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Encrypt(const base::StringPiece& plaintext, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* ciphertext) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!plaintext.empty() || (mode_ == CBC)); 767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return (mode_ == CTR) ? 777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) CryptCTR(true, plaintext, ciphertext) : 787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) Crypt(true, plaintext, ciphertext); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Decrypt(const base::StringPiece& ciphertext, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* plaintext) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!ciphertext.empty()); 847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return (mode_ == CTR) ? 857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) CryptCTR(false, ciphertext, plaintext) : 867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) Crypt(false, ciphertext, plaintext); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encryptor::Crypt(bool do_encrypt, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::StringPiece& input, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* output) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(key_); // Must call Init() before En/De-crypt. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Work on the result in a local variable, and then only transfer it to 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |output| on success to ensure no partial data is returned. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string result; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output->clear(); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const EVP_CIPHER* cipher = GetCipherForKey(key_); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(cipher); // Already handled in Init(); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& key = key_->key(); 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.length()); 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.length()); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedCipherCTX ctx; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!EVP_CipherInit_ex(ctx.get(), cipher, NULL, 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<const uint8*>(key.data()), 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<const uint8*>(iv_.data()), 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do_encrypt)) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When encrypting, add another block size of space to allow for any padding. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GT(output_size, 0u); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GT(output_size + 1, input.size()); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8* out_ptr = reinterpret_cast<uint8*>(WriteInto(&result, 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_size + 1)); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int out_len; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<const uint8*>(input.data()), 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input.length())) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Write out the final block plus padding (if any) to the end of the data 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // just written. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int tail_len; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len)) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_len += tail_len; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(out_len, static_cast<int>(output_size)); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.resize(out_len); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output->swap(result); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool Encryptor::CryptCTR(bool do_encrypt, 1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const base::StringPiece& input, 1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::string* output) { 1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!counter_.get()) { 1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) LOG(ERROR) << "Counter value not set in CTR mode."; 1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return false; 1447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 1457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AES_KEY aes_key; 1477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (AES_set_encrypt_key(reinterpret_cast<const uint8*>(key_->key().data()), 1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) key_->key().size() * 8, &aes_key) != 0) { 1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return false; 1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const size_t out_size = input.size(); 1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) CHECK_GT(out_size, 0u); 1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) CHECK_GT(out_size + 1, input.size()); 1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::string result; 1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) uint8* out_ptr = reinterpret_cast<uint8*>(WriteInto(&result, out_size + 1)); 1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) uint8_t ivec[AES_BLOCK_SIZE] = { 0 }; 1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 }; 1617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) unsigned int block_offset = 0; 1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) counter_->Write(ivec); 1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AES_ctr128_encrypt(reinterpret_cast<const uint8*>(input.data()), out_ptr, 1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) input.size(), &aes_key, ivec, ecount_buf, &block_offset); 1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // AES_ctr128_encrypt() updates |ivec|. Update the |counter_| here. 1697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) SetCounter(base::StringPiece(reinterpret_cast<const char*>(ivec), 1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AES_BLOCK_SIZE)); 1717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) output->swap(result); 1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return true; 1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace crypto 177