• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 <stddef.h>
8 #include <stdint.h>
9 
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "base/sys_byteorder.h"
13 #include "crypto/openssl_util.h"
14 #include "crypto/symmetric_key.h"
15 #include "third_party/boringssl/src/include/openssl/aes.h"
16 #include "third_party/boringssl/src/include/openssl/evp.h"
17 
18 namespace crypto {
19 
20 namespace {
21 
GetCipherForKey(const SymmetricKey * key)22 const EVP_CIPHER* GetCipherForKey(const 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:
27       return nullptr;
28   }
29 }
30 
31 }  // namespace
32 
33 /////////////////////////////////////////////////////////////////////////////
34 // Encryptor Implementation.
35 
Encryptor()36 Encryptor::Encryptor() : key_(nullptr), mode_(CBC) {}
37 
38 Encryptor::~Encryptor() = default;
39 
Init(const SymmetricKey * key,Mode mode,base::StringPiece iv)40 bool Encryptor::Init(const SymmetricKey* key, Mode mode, base::StringPiece iv) {
41   return Init(key, mode, base::as_bytes(base::make_span(iv)));
42 }
43 
Init(const SymmetricKey * key,Mode mode,base::span<const uint8_t> iv)44 bool Encryptor::Init(const SymmetricKey* key,
45                      Mode mode,
46                      base::span<const uint8_t> iv) {
47   DCHECK(key);
48   DCHECK(mode == CBC || mode == CTR);
49 
50   EnsureOpenSSLInit();
51   if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
52     return false;
53   // CTR mode passes the starting counter separately, via SetCounter().
54   if (mode == CTR && !iv.empty())
55     return false;
56 
57   if (GetCipherForKey(key) == nullptr)
58     return false;
59 
60   key_ = key;
61   mode_ = mode;
62   iv_.assign(iv.begin(), iv.end());
63   return true;
64 }
65 
Encrypt(base::StringPiece plaintext,std::string * ciphertext)66 bool Encryptor::Encrypt(base::StringPiece plaintext, std::string* ciphertext) {
67   return CryptString(/*do_encrypt=*/true, plaintext, ciphertext);
68 }
69 
Encrypt(base::span<const uint8_t> plaintext,std::vector<uint8_t> * ciphertext)70 bool Encryptor::Encrypt(base::span<const uint8_t> plaintext,
71                         std::vector<uint8_t>* ciphertext) {
72   return CryptBytes(/*do_encrypt=*/true, plaintext, ciphertext);
73 }
74 
Decrypt(base::StringPiece ciphertext,std::string * plaintext)75 bool Encryptor::Decrypt(base::StringPiece ciphertext, std::string* plaintext) {
76   return CryptString(/*do_encrypt=*/false, ciphertext, plaintext);
77 }
78 
Decrypt(base::span<const uint8_t> ciphertext,std::vector<uint8_t> * plaintext)79 bool Encryptor::Decrypt(base::span<const uint8_t> ciphertext,
80                         std::vector<uint8_t>* plaintext) {
81   return CryptBytes(/*do_encrypt=*/false, ciphertext, plaintext);
82 }
83 
SetCounter(base::StringPiece counter)84 bool Encryptor::SetCounter(base::StringPiece counter) {
85   return SetCounter(base::as_bytes(base::make_span(counter)));
86 }
87 
SetCounter(base::span<const uint8_t> counter)88 bool Encryptor::SetCounter(base::span<const uint8_t> counter) {
89   if (mode_ != CTR)
90     return false;
91   if (counter.size() != 16u)
92     return false;
93 
94   iv_.assign(counter.begin(), counter.end());
95   return true;
96 }
97 
CryptString(bool do_encrypt,base::StringPiece input,std::string * output)98 bool Encryptor::CryptString(bool do_encrypt,
99                             base::StringPiece input,
100                             std::string* output) {
101   std::string result(MaxOutput(do_encrypt, input.size()), '\0');
102   absl::optional<size_t> len =
103       (mode_ == CTR)
104           ? CryptCTR(do_encrypt, base::as_bytes(base::make_span(input)),
105                      base::as_writable_bytes(base::make_span(result)))
106           : Crypt(do_encrypt, base::as_bytes(base::make_span(input)),
107                   base::as_writable_bytes(base::make_span(result)));
108   if (!len)
109     return false;
110 
111   result.resize(*len);
112   *output = std::move(result);
113   return true;
114 }
115 
CryptBytes(bool do_encrypt,base::span<const uint8_t> input,std::vector<uint8_t> * output)116 bool Encryptor::CryptBytes(bool do_encrypt,
117                            base::span<const uint8_t> input,
118                            std::vector<uint8_t>* output) {
119   std::vector<uint8_t> result(MaxOutput(do_encrypt, input.size()));
120   absl::optional<size_t> len = (mode_ == CTR)
121                                    ? CryptCTR(do_encrypt, input, result)
122                                    : Crypt(do_encrypt, input, result);
123   if (!len)
124     return false;
125 
126   result.resize(*len);
127   *output = std::move(result);
128   return true;
129 }
130 
MaxOutput(bool do_encrypt,size_t length)131 size_t Encryptor::MaxOutput(bool do_encrypt, size_t length) {
132   size_t result = length + ((do_encrypt && mode_ == CBC) ? 16 : 0);
133   CHECK_GE(result, length);  // Overflow
134   return result;
135 }
136 
Crypt(bool do_encrypt,base::span<const uint8_t> input,base::span<uint8_t> output)137 absl::optional<size_t> Encryptor::Crypt(bool do_encrypt,
138                                         base::span<const uint8_t> input,
139                                         base::span<uint8_t> output) {
140   DCHECK(key_);  // Must call Init() before En/De-crypt.
141 
142   const EVP_CIPHER* cipher = GetCipherForKey(key_);
143   DCHECK(cipher);  // Already handled in Init();
144 
145   const std::string& key = key_->key();
146   DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.size());
147   DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.size());
148 
149   OpenSSLErrStackTracer err_tracer(FROM_HERE);
150   bssl::ScopedEVP_CIPHER_CTX ctx;
151   if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr,
152                          reinterpret_cast<const uint8_t*>(key.data()),
153                          iv_.data(), do_encrypt)) {
154     return absl::nullopt;
155   }
156 
157   // Encrypting needs a block size of space to allow for any padding.
158   CHECK_GE(output.size(), input.size() + (do_encrypt ? iv_.size() : 0));
159   int out_len;
160   if (!EVP_CipherUpdate(ctx.get(), output.data(), &out_len, input.data(),
161                         input.size()))
162     return absl::nullopt;
163 
164   // Write out the final block plus padding (if any) to the end of the data
165   // just written.
166   int tail_len;
167   if (!EVP_CipherFinal_ex(ctx.get(), output.data() + out_len, &tail_len))
168     return absl::nullopt;
169 
170   out_len += tail_len;
171   DCHECK_LE(out_len, static_cast<int>(output.size()));
172   return out_len;
173 }
174 
CryptCTR(bool do_encrypt,base::span<const uint8_t> input,base::span<uint8_t> output)175 absl::optional<size_t> Encryptor::CryptCTR(bool do_encrypt,
176                                            base::span<const uint8_t> input,
177                                            base::span<uint8_t> output) {
178   if (iv_.size() != AES_BLOCK_SIZE) {
179     LOG(ERROR) << "Counter value not set in CTR mode.";
180     return absl::nullopt;
181   }
182 
183   AES_KEY aes_key;
184   if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key_->key().data()),
185                           key_->key().size() * 8, &aes_key) != 0) {
186     return absl::nullopt;
187   }
188 
189   uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 };
190   unsigned int block_offset = 0;
191 
192   // |output| must have room for |input|.
193   CHECK_GE(output.size(), input.size());
194   // Note AES_ctr128_encrypt() will update |iv_|. However, this method discards
195   // |ecount_buf| and |block_offset|, so this is not quite a streaming API.
196   AES_ctr128_encrypt(input.data(), output.data(), input.size(), &aes_key,
197                      iv_.data(), ecount_buf, &block_offset);
198   return input.size();
199 }
200 
201 }  // namespace crypto
202