OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "crypto/encryptor.h" | 5 #include "crypto/encryptor.h" |
6 | 6 |
| 7 #include <openssl/aes.h> |
| 8 #include <openssl/evp.h> |
7 #include <stddef.h> | 9 #include <stddef.h> |
8 #include <stdint.h> | 10 #include <stdint.h> |
9 | 11 |
10 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/strings/string_util.h" |
11 #include "base/sys_byteorder.h" | 14 #include "base/sys_byteorder.h" |
| 15 #include "crypto/openssl_util.h" |
| 16 #include "crypto/symmetric_key.h" |
12 | 17 |
13 namespace crypto { | 18 namespace crypto { |
14 | 19 |
| 20 namespace { |
| 21 |
| 22 const EVP_CIPHER* GetCipherForKey(SymmetricKey* key) { |
| 23 switch (key->key().length()) { |
| 24 case 16: return EVP_aes_128_cbc(); |
| 25 case 32: return EVP_aes_256_cbc(); |
| 26 default: return NULL; |
| 27 } |
| 28 } |
| 29 |
| 30 // On destruction this class will cleanup the ctx, and also clear the OpenSSL |
| 31 // ERR stack as a convenience. |
| 32 class ScopedCipherCTX { |
| 33 public: |
| 34 explicit ScopedCipherCTX() { |
| 35 EVP_CIPHER_CTX_init(&ctx_); |
| 36 } |
| 37 ~ScopedCipherCTX() { |
| 38 EVP_CIPHER_CTX_cleanup(&ctx_); |
| 39 ClearOpenSSLERRStack(FROM_HERE); |
| 40 } |
| 41 EVP_CIPHER_CTX* get() { return &ctx_; } |
| 42 |
| 43 private: |
| 44 EVP_CIPHER_CTX ctx_; |
| 45 }; |
| 46 |
| 47 } // namespace |
| 48 |
15 ///////////////////////////////////////////////////////////////////////////// | 49 ///////////////////////////////////////////////////////////////////////////// |
16 // Encyptor::Counter Implementation. | 50 // Encyptor::Counter Implementation. |
17 Encryptor::Counter::Counter(const base::StringPiece& counter) { | 51 Encryptor::Counter::Counter(const base::StringPiece& counter) { |
18 CHECK(sizeof(counter_) == counter.length()); | 52 CHECK(sizeof(counter_) == counter.length()); |
19 | 53 |
20 memcpy(&counter_, counter.data(), sizeof(counter_)); | 54 memcpy(&counter_, counter.data(), sizeof(counter_)); |
21 } | 55 } |
22 | 56 |
23 Encryptor::Counter::~Counter() { | 57 Encryptor::Counter::~Counter() { |
24 } | 58 } |
(...skipping 16 matching lines...) Expand all Loading... |
41 void Encryptor::Counter::Write(void* buf) { | 75 void Encryptor::Counter::Write(void* buf) { |
42 uint8_t* buf_ptr = reinterpret_cast<uint8_t*>(buf); | 76 uint8_t* buf_ptr = reinterpret_cast<uint8_t*>(buf); |
43 memcpy(buf_ptr, &counter_, sizeof(counter_)); | 77 memcpy(buf_ptr, &counter_, sizeof(counter_)); |
44 } | 78 } |
45 | 79 |
46 size_t Encryptor::Counter::GetLengthInBytes() const { | 80 size_t Encryptor::Counter::GetLengthInBytes() const { |
47 return sizeof(counter_); | 81 return sizeof(counter_); |
48 } | 82 } |
49 | 83 |
50 ///////////////////////////////////////////////////////////////////////////// | 84 ///////////////////////////////////////////////////////////////////////////// |
51 // Partial Encryptor Implementation. | 85 // Encryptor Implementation. |
| 86 |
| 87 Encryptor::Encryptor() |
| 88 : key_(NULL), |
| 89 mode_(CBC) { |
| 90 } |
| 91 |
| 92 Encryptor::~Encryptor() { |
| 93 } |
| 94 |
| 95 bool Encryptor::Init(SymmetricKey* key, |
| 96 Mode mode, |
| 97 const base::StringPiece& iv) { |
| 98 DCHECK(key); |
| 99 DCHECK(mode == CBC || mode == CTR); |
| 100 |
| 101 EnsureOpenSSLInit(); |
| 102 if (mode == CBC && iv.size() != AES_BLOCK_SIZE) |
| 103 return false; |
| 104 |
| 105 if (GetCipherForKey(key) == NULL) |
| 106 return false; |
| 107 |
| 108 key_ = key; |
| 109 mode_ = mode; |
| 110 iv.CopyToString(&iv_); |
| 111 return true; |
| 112 } |
| 113 |
| 114 bool Encryptor::Encrypt(const base::StringPiece& plaintext, |
| 115 std::string* ciphertext) { |
| 116 CHECK(!plaintext.empty() || (mode_ == CBC)); |
| 117 return (mode_ == CTR) ? |
| 118 CryptCTR(true, plaintext, ciphertext) : |
| 119 Crypt(true, plaintext, ciphertext); |
| 120 } |
| 121 |
| 122 bool Encryptor::Decrypt(const base::StringPiece& ciphertext, |
| 123 std::string* plaintext) { |
| 124 CHECK(!ciphertext.empty()); |
| 125 return (mode_ == CTR) ? |
| 126 CryptCTR(false, ciphertext, plaintext) : |
| 127 Crypt(false, ciphertext, plaintext); |
| 128 } |
52 | 129 |
53 bool Encryptor::SetCounter(const base::StringPiece& counter) { | 130 bool Encryptor::SetCounter(const base::StringPiece& counter) { |
54 if (mode_ != CTR) | 131 if (mode_ != CTR) |
55 return false; | 132 return false; |
56 if (counter.length() != 16u) | 133 if (counter.length() != 16u) |
57 return false; | 134 return false; |
58 | 135 |
59 counter_.reset(new Counter(counter)); | 136 counter_.reset(new Counter(counter)); |
60 return true; | 137 return true; |
61 } | 138 } |
(...skipping 28 matching lines...) Expand all Loading... |
90 void* ciphertext) const { | 167 void* ciphertext) const { |
91 DCHECK_EQ(CTR, mode_); | 168 DCHECK_EQ(CTR, mode_); |
92 const uint8_t* plaintext_ptr = reinterpret_cast<const uint8_t*>(plaintext); | 169 const uint8_t* plaintext_ptr = reinterpret_cast<const uint8_t*>(plaintext); |
93 const uint8_t* mask_ptr = reinterpret_cast<const uint8_t*>(mask); | 170 const uint8_t* mask_ptr = reinterpret_cast<const uint8_t*>(mask); |
94 uint8_t* ciphertext_ptr = reinterpret_cast<uint8_t*>(ciphertext); | 171 uint8_t* ciphertext_ptr = reinterpret_cast<uint8_t*>(ciphertext); |
95 | 172 |
96 for (size_t i = 0; i < plaintext_len; ++i) | 173 for (size_t i = 0; i < plaintext_len; ++i) |
97 ciphertext_ptr[i] = plaintext_ptr[i] ^ mask_ptr[i]; | 174 ciphertext_ptr[i] = plaintext_ptr[i] ^ mask_ptr[i]; |
98 } | 175 } |
99 | 176 |
| 177 bool Encryptor::Crypt(bool do_encrypt, |
| 178 const base::StringPiece& input, |
| 179 std::string* output) { |
| 180 DCHECK(key_); // Must call Init() before En/De-crypt. |
| 181 // Work on the result in a local variable, and then only transfer it to |
| 182 // |output| on success to ensure no partial data is returned. |
| 183 std::string result; |
| 184 output->clear(); |
| 185 |
| 186 const EVP_CIPHER* cipher = GetCipherForKey(key_); |
| 187 DCHECK(cipher); // Already handled in Init(); |
| 188 |
| 189 const std::string& key = key_->key(); |
| 190 DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.length()); |
| 191 DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.length()); |
| 192 |
| 193 ScopedCipherCTX ctx; |
| 194 if (!EVP_CipherInit_ex( |
| 195 ctx.get(), cipher, NULL, reinterpret_cast<const uint8_t*>(key.data()), |
| 196 reinterpret_cast<const uint8_t*>(iv_.data()), do_encrypt)) |
| 197 return false; |
| 198 |
| 199 // When encrypting, add another block size of space to allow for any padding. |
| 200 const size_t output_size = input.size() + (do_encrypt ? iv_.size() : 0); |
| 201 CHECK_GT(output_size, 0u); |
| 202 CHECK_GT(output_size + 1, input.size()); |
| 203 uint8_t* out_ptr = |
| 204 reinterpret_cast<uint8_t*>(base::WriteInto(&result, output_size + 1)); |
| 205 int out_len; |
| 206 if (!EVP_CipherUpdate(ctx.get(), out_ptr, &out_len, |
| 207 reinterpret_cast<const uint8_t*>(input.data()), |
| 208 input.length())) |
| 209 return false; |
| 210 |
| 211 // Write out the final block plus padding (if any) to the end of the data |
| 212 // just written. |
| 213 int tail_len; |
| 214 if (!EVP_CipherFinal_ex(ctx.get(), out_ptr + out_len, &tail_len)) |
| 215 return false; |
| 216 |
| 217 out_len += tail_len; |
| 218 DCHECK_LE(out_len, static_cast<int>(output_size)); |
| 219 result.resize(out_len); |
| 220 |
| 221 output->swap(result); |
| 222 return true; |
| 223 } |
| 224 |
| 225 bool Encryptor::CryptCTR(bool do_encrypt, |
| 226 const base::StringPiece& input, |
| 227 std::string* output) { |
| 228 if (!counter_.get()) { |
| 229 LOG(ERROR) << "Counter value not set in CTR mode."; |
| 230 return false; |
| 231 } |
| 232 |
| 233 AES_KEY aes_key; |
| 234 if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key_->key().data()), |
| 235 key_->key().size() * 8, &aes_key) != 0) { |
| 236 return false; |
| 237 } |
| 238 |
| 239 const size_t out_size = input.size(); |
| 240 CHECK_GT(out_size, 0u); |
| 241 CHECK_GT(out_size + 1, input.size()); |
| 242 |
| 243 std::string result; |
| 244 uint8_t* out_ptr = |
| 245 reinterpret_cast<uint8_t*>(base::WriteInto(&result, out_size + 1)); |
| 246 |
| 247 uint8_t ivec[AES_BLOCK_SIZE] = { 0 }; |
| 248 uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 }; |
| 249 unsigned int block_offset = 0; |
| 250 |
| 251 counter_->Write(ivec); |
| 252 |
| 253 AES_ctr128_encrypt(reinterpret_cast<const uint8_t*>(input.data()), out_ptr, |
| 254 input.size(), &aes_key, ivec, ecount_buf, &block_offset); |
| 255 |
| 256 // AES_ctr128_encrypt() updates |ivec|. Update the |counter_| here. |
| 257 SetCounter(base::StringPiece(reinterpret_cast<const char*>(ivec), |
| 258 AES_BLOCK_SIZE)); |
| 259 |
| 260 output->swap(result); |
| 261 return true; |
| 262 } |
| 263 |
100 } // namespace crypto | 264 } // namespace crypto |
OLD | NEW |