DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs
aes_encryptor.cc
1 // Copyright 2014 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_encryptor.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 // Increment an 8-byte counter by 1. Return true if overflowed.
18 bool Increment64(uint8_t* counter) {
19  DCHECK(counter);
20  for (int i = 7; i >= 0; --i)
21  if (++counter[i] != 0)
22  return false;
23  return true;
24 }
25 
26 // According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either
27 // 64-bit (8-byte) or 128-bit (16-byte).
28 bool IsIvSizeValid(size_t iv_size) { return iv_size == 8 || iv_size == 16; }
29 
30 // AES defines three key sizes: 128, 192 and 256 bits.
31 bool IsKeySizeValidForAes(size_t key_size) {
32  return key_size == 16 || key_size == 24 || key_size == 32;
33 }
34 
35 // CENC protection scheme uses 128-bit keys in counter mode.
36 const uint32_t kCencKeySize = 16;
37 
38 } // namespace
39 
40 namespace edash_packager {
41 namespace media {
42 
43 AesCtrEncryptor::AesCtrEncryptor()
44  : block_offset_(0),
45  encrypted_counter_(AES_BLOCK_SIZE, 0),
46  counter_overflow_(false) {
47  COMPILE_ASSERT(AES_BLOCK_SIZE == kCencKeySize,
48  cenc_key_size_should_be_the_same_as_aes_block_size);
49 }
50 
51 AesCtrEncryptor::~AesCtrEncryptor() {}
52 
53 bool AesCtrEncryptor::InitializeWithRandomIv(const std::vector<uint8_t>& key,
54  uint8_t iv_size) {
55  std::vector<uint8_t> iv(iv_size, 0);
56  if (RAND_bytes(&iv[0], iv_size) != 1) {
57  LOG(ERROR) << "RAND_bytes failed with error: "
58  << ERR_error_string(ERR_get_error(), NULL);
59  return false;
60  }
61  return InitializeWithIv(key, iv);
62 }
63 
64 bool AesCtrEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
65  const std::vector<uint8_t>& iv) {
66  if (key.size() != kCencKeySize) {
67  LOG(ERROR) << "Invalid key size of " << key.size() << " for CENC.";
68  return false;
69  }
70  if (!IsIvSizeValid(iv.size())) {
71  LOG(ERROR) << "Invalid IV size: " << iv.size();
72  return false;
73  }
74 
75  aes_key_.reset(new AES_KEY());
76  CHECK_EQ(AES_set_encrypt_key(&key[0], AES_BLOCK_SIZE * 8, aes_key_.get()), 0);
77  return SetIv(iv);
78 }
79 
80 bool AesCtrEncryptor::Encrypt(const uint8_t* plaintext,
81  size_t plaintext_size,
82  uint8_t* ciphertext) {
83  DCHECK(plaintext);
84  DCHECK(ciphertext);
85  DCHECK(aes_key_);
86 
87  for (size_t i = 0; i < plaintext_size; ++i) {
88  if (block_offset_ == 0) {
89  AES_encrypt(&counter_[0], &encrypted_counter_[0], aes_key_.get());
90  // As mentioned in ISO/IEC FDIS 23001-7: CENC spec, of the 16 byte counter
91  // block, bytes 8 to 15 (i.e. the least significant bytes) are used as a
92  // simple 64 bit unsigned integer that is incremented by one for each
93  // subsequent block of sample data processed and is kept in network byte
94  // order.
95  if (Increment64(&counter_[8]))
96  counter_overflow_ = true;
97  }
98  ciphertext[i] = plaintext[i] ^ encrypted_counter_[block_offset_];
99  block_offset_ = (block_offset_ + 1) % AES_BLOCK_SIZE;
100  }
101  return true;
102 }
103 
104 void AesCtrEncryptor::UpdateIv() {
105  block_offset_ = 0;
106 
107  // As recommended in ISO/IEC FDIS 23001-7: CENC spec, for 64-bit (8-byte)
108  // IV_Sizes, initialization vectors for subsequent samples can be created by
109  // incrementing the initialization vector of the previous sample.
110  // For 128-bit (16-byte) IV_Sizes, initialization vectors for subsequent
111  // samples should be created by adding the block count of the previous sample
112  // to the initialization vector of the previous sample.
113  if (iv_.size() == 8) {
114  Increment64(&iv_[0]);
115  counter_ = iv_;
116  counter_.resize(AES_BLOCK_SIZE, 0);
117  } else {
118  DCHECK_EQ(16u, iv_.size());
119  // Even though the block counter portion of the counter (bytes 8 to 15) is
120  // treated as a 64-bit number, it is recommended that the initialization
121  // vector is treated as a 128-bit number when calculating the next
122  // initialization vector from the previous one. The block counter portion
123  // is already incremented by number of blocks, the other 64 bits of the
124  // counter (bytes 0 to 7) is incremented here if the block counter portion
125  // has overflowed.
126  if (counter_overflow_)
127  Increment64(&counter_[0]);
128  iv_ = counter_;
129  }
130  counter_overflow_ = false;
131 }
132 
133 bool AesCtrEncryptor::SetIv(const std::vector<uint8_t>& iv) {
134  if (!IsIvSizeValid(iv.size())) {
135  LOG(ERROR) << "Invalid IV size: " << iv.size();
136  return false;
137  }
138 
139  block_offset_ = 0;
140  counter_ = iv_ = iv;
141  counter_.resize(AES_BLOCK_SIZE, 0);
142  return true;
143 }
144 
145 AesCbcPkcs5Encryptor::AesCbcPkcs5Encryptor() {}
146 AesCbcPkcs5Encryptor::~AesCbcPkcs5Encryptor() {}
147 
148 bool AesCbcPkcs5Encryptor::InitializeWithIv(const std::vector<uint8_t>& key,
149  const std::vector<uint8_t>& iv) {
150  if (!IsKeySizeValidForAes(key.size())) {
151  LOG(ERROR) << "Invalid AES key size: " << key.size();
152  return false;
153  }
154  if (iv.size() != AES_BLOCK_SIZE) {
155  LOG(ERROR) << "Invalid IV size: " << iv.size();
156  return false;
157  }
158 
159  encrypt_key_.reset(new AES_KEY());
160  CHECK_EQ(AES_set_encrypt_key(&key[0], key.size() * 8, encrypt_key_.get()), 0);
161 
162  iv_ = iv;
163  return true;
164 }
165 
166 void AesCbcPkcs5Encryptor::Encrypt(const std::string& plaintext,
167  std::string* ciphertext) {
168  DCHECK(ciphertext);
169  DCHECK(encrypt_key_);
170 
171  // Pad the input with PKCS5 padding.
172  const size_t num_padding_bytes =
173  AES_BLOCK_SIZE - (plaintext.size() % AES_BLOCK_SIZE);
174  std::string padded_text = plaintext;
175  padded_text.append(num_padding_bytes, static_cast<char>(num_padding_bytes));
176 
177  ciphertext->resize(padded_text.size());
178  std::vector<uint8_t> iv(iv_);
179  AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(padded_text.data()),
180  reinterpret_cast<uint8_t*>(string_as_array(ciphertext)),
181  padded_text.size(),
182  encrypt_key_.get(),
183  &iv[0],
184  AES_ENCRYPT);
185 }
186 
187 bool AesCbcPkcs5Encryptor::SetIv(const std::vector<uint8_t>& iv) {
188  if (iv.size() != AES_BLOCK_SIZE) {
189  LOG(ERROR) << "Invalid IV size: " << iv.size();
190  return false;
191  }
192 
193  iv_ = iv;
194  return true;
195 }
196 
197 AesCbcPkcs5Decryptor::AesCbcPkcs5Decryptor() {}
198 AesCbcPkcs5Decryptor::~AesCbcPkcs5Decryptor() {}
199 
200 bool AesCbcPkcs5Decryptor::InitializeWithIv(const std::vector<uint8_t>& key,
201  const std::vector<uint8_t>& iv) {
202  if (!IsKeySizeValidForAes(key.size())) {
203  LOG(ERROR) << "Invalid AES key size: " << key.size();
204  return false;
205  }
206  if (iv.size() != AES_BLOCK_SIZE) {
207  LOG(ERROR) << "Invalid IV size: " << iv.size();
208  return false;
209  }
210 
211  decrypt_key_.reset(new AES_KEY());
212  CHECK_EQ(AES_set_decrypt_key(&key[0], key.size() * 8, decrypt_key_.get()), 0);
213 
214  iv_ = iv;
215  return true;
216 }
217 
218 bool AesCbcPkcs5Decryptor::Decrypt(const std::string& ciphertext,
219  std::string* plaintext) {
220  if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) {
221  LOG(ERROR) << "Expecting cipher text size to be multiple of "
222  << AES_BLOCK_SIZE << ", got " << ciphertext.size();
223  return false;
224  }
225 
226  DCHECK(plaintext);
227  DCHECK(decrypt_key_);
228 
229  plaintext->resize(ciphertext.size());
230  AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(ciphertext.data()),
231  reinterpret_cast<uint8_t*>(string_as_array(plaintext)),
232  ciphertext.size(),
233  decrypt_key_.get(),
234  &iv_[0],
235  AES_DECRYPT);
236 
237  // Strip off PKCS5 padding bytes.
238  const uint8_t num_padding_bytes = (*plaintext)[plaintext->size() - 1];
239  if (num_padding_bytes > AES_BLOCK_SIZE) {
240  LOG(ERROR) << "Padding length is too large : "
241  << static_cast<int>(num_padding_bytes);
242  return false;
243  }
244  plaintext->resize(plaintext->size() - num_padding_bytes);
245  return true;
246 }
247 
248 bool AesCbcPkcs5Decryptor::SetIv(const std::vector<uint8_t>& iv) {
249  if (iv.size() != AES_BLOCK_SIZE) {
250  LOG(ERROR) << "Invalid IV size: " << iv.size();
251  return false;
252  }
253 
254  iv_ = iv;
255  return true;
256 }
257 
258 AesCbcCtsEncryptor::AesCbcCtsEncryptor() {}
259 AesCbcCtsEncryptor::~AesCbcCtsEncryptor() {}
260 
261 bool AesCbcCtsEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
262  const std::vector<uint8_t>& iv) {
263  if (!IsKeySizeValidForAes(key.size())) {
264  LOG(ERROR) << "Invalid AES key size: " << key.size();
265  return false;
266  }
267  if (iv.size() != AES_BLOCK_SIZE) {
268  LOG(ERROR) << "Invalid IV size: " << iv.size();
269  return false;
270  }
271 
272  encrypt_key_.reset(new AES_KEY());
273  CHECK_EQ(AES_set_encrypt_key(&key[0], key.size() * 8, encrypt_key_.get()), 0);
274 
275  iv_ = iv;
276  return true;
277 }
278 
279 void AesCbcCtsEncryptor::Encrypt(const uint8_t* plaintext,
280  size_t size,
281  uint8_t* ciphertext) {
282  DCHECK(plaintext);
283  DCHECK(ciphertext);
284 
285  if (size < AES_BLOCK_SIZE) {
286  // Don't have a full block, leave unencrypted.
287  memcpy(ciphertext, plaintext, size);
288  return;
289  }
290 
291  std::vector<uint8_t> iv(iv_);
292  size_t residual_block_size = size % AES_BLOCK_SIZE;
293  size_t cbc_size = size - residual_block_size;
294 
295  // Encrypt everything but the residual block using CBC.
296  AES_cbc_encrypt(plaintext,
297  ciphertext,
298  cbc_size,
299  encrypt_key_.get(),
300  &iv[0],
301  AES_ENCRYPT);
302  if (residual_block_size == 0) {
303  // No residual block. No need to do ciphertext stealing.
304  return;
305  }
306 
307  // Zero-pad the residual block and encrypt using CBC.
308  std::vector<uint8_t> residual_block(plaintext + size - residual_block_size,
309  plaintext + size);
310  residual_block.resize(AES_BLOCK_SIZE, 0);
311  AES_cbc_encrypt(&residual_block[0],
312  &residual_block[0],
313  AES_BLOCK_SIZE,
314  encrypt_key_.get(),
315  &iv[0],
316  AES_ENCRYPT);
317 
318  // Replace the last full block with the zero-padded, encrypted residual block,
319  // and replace the residual block with the equivalent portion of the last full
320  // encrypted block. It may appear that some encrypted bits of the last full
321  // block are lost, but they are not, as they were used as the IV when
322  // encrypting the zero-padded residual block.
323  uint8_t* residual_ciphertext_block = ciphertext + size - residual_block_size;
324  memcpy(residual_ciphertext_block,
325  residual_ciphertext_block - AES_BLOCK_SIZE,
326  residual_block_size);
327  memcpy(residual_ciphertext_block - AES_BLOCK_SIZE,
328  residual_block.data(),
329  AES_BLOCK_SIZE);
330 }
331 
332 void AesCbcCtsEncryptor::Encrypt(const std::vector<uint8_t>& plaintext,
333  std::vector<uint8_t>* ciphertext) {
334  DCHECK(ciphertext);
335 
336  ciphertext->resize(plaintext.size(), 0);
337  if (plaintext.empty())
338  return;
339 
340  Encrypt(plaintext.data(), plaintext.size(), &(*ciphertext)[0]);
341 }
342 
343 bool AesCbcCtsEncryptor::SetIv(const std::vector<uint8_t>& iv) {
344  if (iv.size() != AES_BLOCK_SIZE) {
345  LOG(ERROR) << "Invalid IV size: " << iv.size();
346  return false;
347  }
348 
349  iv_ = iv;
350  return true;
351 }
352 
353 AesCbcCtsDecryptor::AesCbcCtsDecryptor() {}
354 AesCbcCtsDecryptor::~AesCbcCtsDecryptor() {}
355 
356 bool AesCbcCtsDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
357  const std::vector<uint8_t>& iv) {
358  if (!IsKeySizeValidForAes(key.size())) {
359  LOG(ERROR) << "Invalid AES key size: " << key.size();
360  return false;
361  }
362  if (iv.size() != AES_BLOCK_SIZE) {
363  LOG(ERROR) << "Invalid IV size: " << iv.size();
364  return false;
365  }
366 
367  decrypt_key_.reset(new AES_KEY());
368  CHECK_EQ(AES_set_decrypt_key(&key[0], key.size() * 8, decrypt_key_.get()), 0);
369 
370  iv_ = iv;
371  return true;
372 }
373 
374 void AesCbcCtsDecryptor::Decrypt(const uint8_t* ciphertext,
375  size_t size,
376  uint8_t* plaintext) {
377  DCHECK(ciphertext);
378  DCHECK(plaintext);
379 
380  if (size < AES_BLOCK_SIZE) {
381  // Don't have a full block, leave unencrypted.
382  memcpy(plaintext, ciphertext, size);
383  return;
384  }
385 
386  std::vector<uint8_t> iv(iv_);
387  size_t residual_block_size = size % AES_BLOCK_SIZE;
388 
389  if (residual_block_size == 0) {
390  // No residual block. No need to do ciphertext stealing.
391  AES_cbc_encrypt(ciphertext,
392  plaintext,
393  size,
394  decrypt_key_.get(),
395  &iv[0],
396  AES_DECRYPT);
397  return;
398  }
399 
400  // AES-CBC decrypt everything up to the next-to-last full block.
401  size_t cbc_size = size - residual_block_size;
402  if (cbc_size > AES_BLOCK_SIZE) {
403  AES_cbc_encrypt(ciphertext,
404  plaintext,
405  cbc_size - AES_BLOCK_SIZE,
406  decrypt_key_.get(),
407  &iv[0],
408  AES_DECRYPT);
409  }
410 
411  // Determine what the last IV should be so that we can "skip ahead" in the
412  // CBC decryption.
413  std::vector<uint8_t> last_iv(ciphertext + size - residual_block_size,
414  ciphertext + size);
415  last_iv.resize(AES_BLOCK_SIZE, 0);
416 
417  // Decrypt the next-to-last block using the IV determined above. This decrypts
418  // the residual block bits.
419  AES_cbc_encrypt(ciphertext + size - residual_block_size - AES_BLOCK_SIZE,
420  plaintext + size - residual_block_size - AES_BLOCK_SIZE,
421  AES_BLOCK_SIZE,
422  decrypt_key_.get(),
423  &last_iv[0],
424  AES_DECRYPT);
425 
426  // Swap back the residual block bits and the next-to-last full block.
427  if (plaintext == ciphertext) {
428  uint8_t* ptr1 = plaintext + size - residual_block_size;
429  uint8_t* ptr2 = plaintext + size - residual_block_size - AES_BLOCK_SIZE;
430  for (size_t i = 0; i < residual_block_size; ++i) {
431  uint8_t temp = *ptr1;
432  *ptr1 = *ptr2;
433  *ptr2 = temp;
434  ++ptr1;
435  ++ptr2;
436  }
437  } else {
438  uint8_t* residual_plaintext_block = plaintext + size - residual_block_size;
439  memcpy(residual_plaintext_block,
440  residual_plaintext_block - AES_BLOCK_SIZE,
441  residual_block_size);
442  memcpy(residual_plaintext_block - AES_BLOCK_SIZE,
443  ciphertext + size - residual_block_size,
444  residual_block_size);
445  }
446 
447  // Decrypt the last full block.
448  AES_cbc_encrypt(plaintext + size - residual_block_size - AES_BLOCK_SIZE,
449  plaintext + size - residual_block_size - AES_BLOCK_SIZE,
450  AES_BLOCK_SIZE,
451  decrypt_key_.get(),
452  &iv[0],
453  AES_DECRYPT);
454 }
455 
456 void AesCbcCtsDecryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
457  std::vector<uint8_t>* plaintext) {
458  DCHECK(plaintext);
459 
460  plaintext->resize(ciphertext.size(), 0);
461  if (ciphertext.empty())
462  return;
463 
464  Decrypt(ciphertext.data(), ciphertext.size(), &(*plaintext)[0]);
465 }
466 
467 bool AesCbcCtsDecryptor::SetIv(const std::vector<uint8_t>& iv) {
468  if (iv.size() != AES_BLOCK_SIZE) {
469  LOG(ERROR) << "Invalid IV size: " << iv.size();
470  return false;
471  }
472 
473  iv_ = iv;
474  return true;
475 }
476 
477 } // namespace media
478 } // namespace edash_packager