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 <openssl/aes.h> 8 #include <openssl/evp.h> 9 10 #include "base/logging.h" 11 #include "base/string_util.h" 12 #include "crypto/openssl_util.h" 13 #include "crypto/symmetric_key.h" 14 15 namespace crypto { 16 17 namespace { 18 19 const EVP_CIPHER* GetCipherForKey(SymmetricKey* key) { 20 switch (key->key().length()) { 21 case 16: return EVP_aes_128_cbc(); 22 case 24: return EVP_aes_192_cbc(); 23 case 32: return EVP_aes_256_cbc(); 24 default: return NULL; 25 } 26 } 27 28 // On destruction this class will cleanup the ctx, and also clear the OpenSSL 29 // ERR stack as a convenience. 30 class ScopedCipherCTX { 31 public: 32 explicit ScopedCipherCTX() { 33 EVP_CIPHER_CTX_init(&ctx_); 34 } 35 ~ScopedCipherCTX() { 36 EVP_CIPHER_CTX_cleanup(&ctx_); 37 ClearOpenSSLERRStack(FROM_HERE); 38 } 39 EVP_CIPHER_CTX* get() { return &ctx_; } 40 41 private: 42 EVP_CIPHER_CTX ctx_; 43 }; 44 45 } // namespace 46 47 Encryptor::Encryptor() 48 : key_(NULL), 49 mode_(CBC) { 50 } 51 52 Encryptor::~Encryptor() { 53 } 54 55 bool Encryptor::Init(SymmetricKey* key, Mode mode, const std::string& iv) { 56 DCHECK(key); 57 DCHECK_EQ(CBC, mode); 58 59 EnsureOpenSSLInit(); 60 if (iv.size() != AES_BLOCK_SIZE) 61 return false; 62 63 if (GetCipherForKey(key) == NULL) 64 return false; 65 66 key_ = key; 67 mode_ = mode; 68 iv_ = iv; 69 return true; 70 } 71 72 bool Encryptor::Encrypt(const std::string& plaintext, std::string* ciphertext) { 73 return Crypt(true, plaintext, ciphertext); 74 } 75 76 bool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) { 77 return Crypt(false, ciphertext, plaintext); 78 } 79 80 bool Encryptor::Crypt(bool do_encrypt, 81 const std::string& input, 82 std::string* output) { 83 DCHECK(key_); // Must call Init() before En/De-crypt. 84 // Work on the result in a local variable, and then only transfer it to 85 // |output| on success to ensure no partial data is returned. 86 std::string result; 87 output->swap(result); 88 89 const EVP_CIPHER* cipher = GetCipherForKey(key_); 90 DCHECK(cipher); // Already handled in Init(); 91 92 const std::string& key = key_->key(); 93 DCHECK_EQ(EVP_CIPHER_iv_length(cipher), static_cast<int>(iv_.length())); 94 DCHECK_EQ(EVP_CIPHER_key_length(cipher), static_cast<int>(key.length())); 95 96 ScopedCipherCTX ctx; 97 if (!EVP_CipherInit_ex(ctx.get(), cipher, NULL, 98 reinterpret_cast<const uint8*>(key.data()), 99 reinterpret_cast<const uint8*>(iv_.data()), 100 do_encrypt)) 101 return false; 102 103 // When encrypting, add another block size of space to allow for any padding. 104 const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0); 105 uint8* out_ptr = reinterpret_cast<uint8*>(WriteInto(&result, 106 output_size + 1)); 107 int out_len; 108 if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len, 109 reinterpret_cast<const uint8*>(input.data()), 110 input.length())) 111 return false; 112 113 // Write out the final block plus padding (if any) to the end of the data 114 // just written. 115 int tail_len; 116 if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len)) 117 return false; 118 119 out_len += tail_len; 120 DCHECK_LE(out_len, static_cast<int>(output_size)); 121 result.resize(out_len); 122 123 output->swap(result); 124 return true; 125 } 126 127 } // namespace crypto 128