1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// found in the LICENSE file. 4513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/encryptor.h" 6513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 74a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <openssl/aes.h> 84a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <openssl/evp.h> 94a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 10513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/logging.h" 114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/string_util.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/openssl_util.h" 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/symmetric_key.h" 14513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace crypto { 16513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochnamespace { 184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst EVP_CIPHER* GetCipherForKey(SymmetricKey* key) { 204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch switch (key->key().length()) { 214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch case 16: return EVP_aes_128_cbc(); 224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch case 24: return EVP_aes_192_cbc(); 234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch case 32: return EVP_aes_256_cbc(); 244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch default: return NULL; 254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// On destruction this class will cleanup the ctx, and also clear the OpenSSL 294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// ERR stack as a convenience. 304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochclass ScopedCipherCTX { 314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch public: 324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch explicit ScopedCipherCTX() { 334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EVP_CIPHER_CTX_init(&ctx_); 344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ~ScopedCipherCTX() { 364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EVP_CIPHER_CTX_cleanup(&ctx_); 37201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch ClearOpenSSLERRStack(FROM_HERE); 384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EVP_CIPHER_CTX* get() { return &ctx_; } 404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch private: 424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EVP_CIPHER_CTX ctx_; 434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}; 444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} // namespace 464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochEncryptor::Encryptor() 48dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen : key_(NULL), 49dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen mode_(CBC) { 50513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 51513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 52513209b27ff55e2841eac0e4120199c23acce758Ben MurdochEncryptor::~Encryptor() { 53513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 54513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 55513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool Encryptor::Init(SymmetricKey* key, Mode mode, const std::string& iv) { 564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(key); 574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK_EQ(CBC, mode); 584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EnsureOpenSSLInit(); 604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (iv.size() != AES_BLOCK_SIZE) 614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return false; 624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (GetCipherForKey(key) == NULL) 644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return false; 654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch key_ = key; 674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch mode_ = mode; 684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch iv_ = iv; 694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return true; 70513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 71513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 72513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool Encryptor::Encrypt(const std::string& plaintext, std::string* ciphertext) { 734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return Crypt(true, plaintext, ciphertext); 74513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 75513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 76513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) { 774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return Crypt(false, ciphertext, plaintext); 784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool Encryptor::Crypt(bool do_encrypt, 814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const std::string& input, 824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::string* output) { 834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(key_); // Must call Init() before En/De-crypt. 844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Work on the result in a local variable, and then only transfer it to 854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // |output| on success to ensure no partial data is returned. 864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::string result; 874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch output->swap(result); 884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const EVP_CIPHER* cipher = GetCipherForKey(key_); 904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK(cipher); // Already handled in Init(); 914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const std::string& key = key_->key(); 934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK_EQ(EVP_CIPHER_iv_length(cipher), static_cast<int>(iv_.length())); 944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK_EQ(EVP_CIPHER_key_length(cipher), static_cast<int>(key.length())); 954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ScopedCipherCTX ctx; 974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!EVP_CipherInit_ex(ctx.get(), cipher, NULL, 984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch reinterpret_cast<const uint8*>(key.data()), 994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch reinterpret_cast<const uint8*>(iv_.data()), 1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch do_encrypt)) 1014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return false; 1024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // When encrypting, add another block size of space to allow for any padding. 1044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0); 1054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch uint8* out_ptr = reinterpret_cast<uint8*>(WriteInto(&result, 1064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch output_size + 1)); 1074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch int out_len; 1084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len, 1094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch reinterpret_cast<const uint8*>(input.data()), 1104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch input.length())) 1114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return false; 1124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Write out the final block plus padding (if any) to the end of the data 1144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // just written. 1154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch int tail_len; 1164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len)) 1174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return false; 1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch out_len += tail_len; 1204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch DCHECK_LE(out_len, static_cast<int>(output_size)); 1214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch result.resize(out_len); 1224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch output->swap(result); 1244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return true; 125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 126513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace crypto 128