DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerator
aes_decryptor.cc
1 // Copyright 2016 Google Inc. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include "packager/media/base/aes_decryptor.h"
8 
9 #include <openssl/aes.h>
10 #include <openssl/err.h>
11 #include <openssl/rand.h>
12 
13 #include "packager/base/logging.h"
14 
15 namespace {
16 
17 // AES defines three key sizes: 128, 192 and 256 bits.
18 bool IsKeySizeValidForAes(size_t key_size) {
19  return key_size == 16 || key_size == 24 || key_size == 32;
20 }
21 
22 } // namespace
23 
24 namespace edash_packager {
25 namespace media {
26 
27 AesDecryptor::AesDecryptor() {}
28 AesDecryptor::~AesDecryptor() {}
29 
30 AesCtrDecryptor::AesCtrDecryptor() {}
31 
32 AesCtrDecryptor::~AesCtrDecryptor() {}
33 
34 bool AesCtrDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
35  const std::vector<uint8_t>& iv) {
36  encryptor_.reset(new AesCtrEncryptor);
37  return encryptor_->InitializeWithIv(key, iv);
38 }
39 
40 // For AES CTR, encryption and decryption are identical.
41 bool AesCtrDecryptor::Decrypt(const uint8_t* ciphertext,
42  size_t ciphertext_size,
43  uint8_t* plaintext) {
44  DCHECK(encryptor_);
45  return encryptor_->EncryptData(ciphertext, ciphertext_size, plaintext);
46 }
47 
48 bool AesCtrDecryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
49  std::vector<uint8_t>* plaintext) {
50  DCHECK(encryptor_);
51  return encryptor_->Encrypt(ciphertext, plaintext);
52 }
53 
54 bool AesCtrDecryptor::Decrypt(const std::string& ciphertext,
55  std::string* plaintext) {
56  DCHECK(encryptor_);
57  return encryptor_->Encrypt(ciphertext, plaintext);
58 }
59 
60 bool AesCtrDecryptor::SetIv(const std::vector<uint8_t>& iv) {
61  DCHECK(encryptor_);
62  return encryptor_->SetIv(iv);
63 }
64 
65 AesCbcPkcs5Decryptor::AesCbcPkcs5Decryptor() {}
66 AesCbcPkcs5Decryptor::~AesCbcPkcs5Decryptor() {}
67 
68 bool AesCbcPkcs5Decryptor::InitializeWithIv(const std::vector<uint8_t>& key,
69  const std::vector<uint8_t>& iv) {
70  if (!IsKeySizeValidForAes(key.size())) {
71  LOG(ERROR) << "Invalid AES key size: " << key.size();
72  return false;
73  }
74  if (iv.size() != AES_BLOCK_SIZE) {
75  LOG(ERROR) << "Invalid IV size: " << iv.size();
76  return false;
77  }
78 
79  aes_key_.reset(new AES_KEY());
80  CHECK_EQ(AES_set_decrypt_key(&key[0], key.size() * 8, aes_key_.get()), 0);
81 
82  iv_ = iv;
83  return true;
84 }
85 
86 bool AesCbcPkcs5Decryptor::Decrypt(const uint8_t* ciphertext,
87  size_t ciphertext_size,
88  uint8_t* plaintext) {
89  NOTIMPLEMENTED();
90  return false;
91 }
92 
93 bool AesCbcPkcs5Decryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
94  std::vector<uint8_t>* plaintext) {
95  NOTIMPLEMENTED();
96  return false;
97 }
98 
99 bool AesCbcPkcs5Decryptor::Decrypt(const std::string& ciphertext,
100  std::string* plaintext) {
101  if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) {
102  LOG(ERROR) << "Expecting cipher text size to be multiple of "
103  << AES_BLOCK_SIZE << ", got " << ciphertext.size();
104  return false;
105  }
106 
107  DCHECK(plaintext);
108  DCHECK(aes_key_);
109 
110  plaintext->resize(ciphertext.size());
111  AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(ciphertext.data()),
112  reinterpret_cast<uint8_t*>(string_as_array(plaintext)),
113  ciphertext.size(),
114  aes_key_.get(),
115  &iv_[0],
116  AES_DECRYPT);
117 
118  // Strip off PKCS5 padding bytes.
119  const uint8_t num_padding_bytes = (*plaintext)[plaintext->size() - 1];
120  if (num_padding_bytes > AES_BLOCK_SIZE) {
121  LOG(ERROR) << "Padding length is too large : "
122  << static_cast<int>(num_padding_bytes);
123  return false;
124  }
125  plaintext->resize(plaintext->size() - num_padding_bytes);
126  return true;
127 }
128 
129 bool AesCbcPkcs5Decryptor::SetIv(const std::vector<uint8_t>& iv) {
130  if (iv.size() != AES_BLOCK_SIZE) {
131  LOG(ERROR) << "Invalid IV size: " << iv.size();
132  return false;
133  }
134 
135  iv_ = iv;
136  return true;
137 }
138 
139 AesCbcCtsDecryptor::AesCbcCtsDecryptor() {}
140 AesCbcCtsDecryptor::~AesCbcCtsDecryptor() {}
141 
142 bool AesCbcCtsDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
143  const std::vector<uint8_t>& iv) {
144  if (!IsKeySizeValidForAes(key.size())) {
145  LOG(ERROR) << "Invalid AES key size: " << key.size();
146  return false;
147  }
148  if (iv.size() != AES_BLOCK_SIZE) {
149  LOG(ERROR) << "Invalid IV size: " << iv.size();
150  return false;
151  }
152 
153  aes_key_.reset(new AES_KEY());
154  CHECK_EQ(AES_set_decrypt_key(&key[0], key.size() * 8, aes_key_.get()), 0);
155 
156  iv_ = iv;
157  return true;
158 }
159 
160 bool AesCbcCtsDecryptor::Decrypt(const uint8_t* ciphertext,
161  size_t ciphertext_size,
162  uint8_t* plaintext) {
163  DCHECK(ciphertext);
164  DCHECK(plaintext);
165 
166  if (ciphertext_size < AES_BLOCK_SIZE) {
167  // Don't have a full block, leave unencrypted.
168  memcpy(plaintext, ciphertext, ciphertext_size);
169  return true;
170  }
171 
172  std::vector<uint8_t> iv(iv_);
173  size_t residual_block_size = ciphertext_size % AES_BLOCK_SIZE;
174 
175  if (residual_block_size == 0) {
176  // No residual block. No need to do ciphertext stealing.
177  AES_cbc_encrypt(ciphertext,
178  plaintext,
179  ciphertext_size,
180  aes_key_.get(),
181  &iv[0],
182  AES_DECRYPT);
183  return true;
184  }
185 
186  // AES-CBC decrypt everything up to the next-to-last full block.
187  size_t cbc_size = ciphertext_size - residual_block_size;
188  if (cbc_size > AES_BLOCK_SIZE) {
189  AES_cbc_encrypt(ciphertext,
190  plaintext,
191  cbc_size - AES_BLOCK_SIZE,
192  aes_key_.get(),
193  &iv[0],
194  AES_DECRYPT);
195  }
196 
197  // Determine what the last IV should be so that we can "skip ahead" in the
198  // CBC decryption.
199  std::vector<uint8_t> last_iv(
200  ciphertext + ciphertext_size - residual_block_size,
201  ciphertext + ciphertext_size);
202  last_iv.resize(AES_BLOCK_SIZE, 0);
203 
204  // Decrypt the next-to-last block using the IV determined above. This decrypts
205  // the residual block bits.
206  AES_cbc_encrypt(
207  ciphertext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE,
208  plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE,
209  AES_BLOCK_SIZE, aes_key_.get(), &last_iv[0], AES_DECRYPT);
210 
211  // Swap back the residual block bits and the next-to-last full block.
212  if (plaintext == ciphertext) {
213  uint8_t* ptr1 = plaintext + ciphertext_size - residual_block_size;
214  uint8_t* ptr2 = plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE;
215  for (size_t i = 0; i < residual_block_size; ++i) {
216  uint8_t temp = *ptr1;
217  *ptr1 = *ptr2;
218  *ptr2 = temp;
219  ++ptr1;
220  ++ptr2;
221  }
222  } else {
223  uint8_t* residual_plaintext_block =
224  plaintext + ciphertext_size - residual_block_size;
225  memcpy(residual_plaintext_block, residual_plaintext_block - AES_BLOCK_SIZE,
226  residual_block_size);
227  memcpy(residual_plaintext_block - AES_BLOCK_SIZE,
228  ciphertext + ciphertext_size - residual_block_size,
229  residual_block_size);
230  }
231 
232  // Decrypt the last full block.
233  AES_cbc_encrypt(
234  plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE,
235  plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE,
236  AES_BLOCK_SIZE, aes_key_.get(), &iv[0], AES_DECRYPT);
237  return true;
238 }
239 
240 bool AesCbcCtsDecryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
241  std::vector<uint8_t>* plaintext) {
242  DCHECK(plaintext);
243 
244  plaintext->resize(ciphertext.size(), 0);
245  if (ciphertext.empty())
246  return true;
247 
248  return Decrypt(ciphertext.data(), ciphertext.size(), &(*plaintext)[0]);
249 }
250 
251 bool AesCbcCtsDecryptor::Decrypt(const std::string& ciphertext,
252  std::string* plaintext) {
253  NOTIMPLEMENTED();
254  return false;
255 }
256 
257 bool AesCbcCtsDecryptor::SetIv(const std::vector<uint8_t>& iv) {
258  if (iv.size() != AES_BLOCK_SIZE) {
259  LOG(ERROR) << "Invalid IV size: " << iv.size();
260  return false;
261  }
262 
263  iv_ = iv;
264  return true;
265 }
266 
267 } // namespace media
268 } // namespace edash_packager
bool SetIv(const std::vector< uint8_t > &iv) override
bool SetIv(const std::vector< uint8_t > &iv) override
bool SetIv(const std::vector< uint8_t > &iv) override