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 bool AesDecryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
31  std::vector<uint8_t>* plaintext) {
32  DCHECK(plaintext);
33  plaintext->resize(ciphertext.size());
34  size_t plaintext_size;
35  if (!DecryptInternal(ciphertext.data(), ciphertext.size(), plaintext->data(),
36  &plaintext_size))
37  return false;
38  plaintext->resize(plaintext_size);
39  return true;
40 }
41 
42 bool AesDecryptor::Decrypt(const std::string& ciphertext,
43  std::string* plaintext) {
44  DCHECK(plaintext);
45  plaintext->resize(ciphertext.size());
46  size_t plaintext_size;
47  if (!DecryptInternal(reinterpret_cast<const uint8_t*>(ciphertext.data()),
48  ciphertext.size(),
49  reinterpret_cast<uint8_t*>(string_as_array(plaintext)),
50  &plaintext_size))
51  return false;
52  plaintext->resize(plaintext_size);
53  return true;
54 }
55 
56 AesCtrDecryptor::AesCtrDecryptor() {}
57 
58 AesCtrDecryptor::~AesCtrDecryptor() {}
59 
60 bool AesCtrDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
61  const std::vector<uint8_t>& iv) {
62  encryptor_.reset(new AesCtrEncryptor);
63  return encryptor_->InitializeWithIv(key, iv);
64 }
65 
66 bool AesCtrDecryptor::SetIv(const std::vector<uint8_t>& iv) {
67  DCHECK(encryptor_);
68  return encryptor_->SetIv(iv);
69 }
70 
71 bool AesCtrDecryptor::DecryptInternal(const uint8_t* ciphertext,
72  size_t ciphertext_size,
73  uint8_t* plaintext,
74  size_t* plaintext_size) {
75  DCHECK(encryptor_);
76  *plaintext_size = ciphertext_size;
77  // For AES CTR, encryption and decryption are identical.
78  return encryptor_->Encrypt(ciphertext, ciphertext_size, plaintext);
79 }
80 
81 AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme,
82  bool chain_across_calls)
83  : padding_scheme_(padding_scheme),
84  chain_across_calls_(chain_across_calls) {
85  if (padding_scheme_ != kNoPadding) {
86  CHECK(!chain_across_calls) << "cipher block chain across calls only makes "
87  "sense if the padding_scheme is kNoPadding.";
88  }
89 }
90 AesCbcDecryptor::~AesCbcDecryptor() {}
91 
92 bool AesCbcDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
93  const std::vector<uint8_t>& iv) {
94  if (!IsKeySizeValidForAes(key.size())) {
95  LOG(ERROR) << "Invalid AES key size: " << key.size();
96  return false;
97  }
98 
99  aes_key_.reset(new AES_KEY());
100  CHECK_EQ(AES_set_decrypt_key(key.data(), key.size() * 8, aes_key_.get()), 0);
101 
102  return SetIv(iv);
103 }
104 
105 bool AesCbcDecryptor::SetIv(const std::vector<uint8_t>& iv) {
106  if (iv.size() != AES_BLOCK_SIZE) {
107  LOG(ERROR) << "Invalid IV size: " << iv.size();
108  return false;
109  }
110 
111  iv_ = iv;
112  return true;
113 }
114 
115 bool AesCbcDecryptor::DecryptInternal(const uint8_t* ciphertext,
116  size_t ciphertext_size,
117  uint8_t* plaintext,
118  size_t* plaintext_size) {
119  DCHECK(plaintext_size);
120  DCHECK(aes_key_);
121  // Plaintext size is the same as ciphertext size except for pkcs5 padding.
122  // Will update later if using pkcs5 padding.
123  *plaintext_size = ciphertext_size;
124  if (ciphertext_size == 0) {
125  if (padding_scheme_ == kPkcs5Padding) {
126  LOG(ERROR) << "Expected ciphertext to be at least " << AES_BLOCK_SIZE
127  << " bytes with Pkcs5 padding";
128  return false;
129  }
130  return true;
131  }
132  DCHECK(plaintext);
133 
134  std::vector<uint8_t> local_iv(iv_);
135  const size_t residual_block_size = ciphertext_size % AES_BLOCK_SIZE;
136  if (residual_block_size == 0) {
137  AES_cbc_encrypt(ciphertext, plaintext, ciphertext_size, aes_key_.get(),
138  local_iv.data(), AES_DECRYPT);
139  if (chain_across_calls_)
140  iv_ = local_iv;
141  if (padding_scheme_ != kPkcs5Padding)
142  return true;
143 
144  // Strip off PKCS5 padding bytes.
145  const uint8_t num_padding_bytes = plaintext[ciphertext_size - 1];
146  if (num_padding_bytes > AES_BLOCK_SIZE) {
147  LOG(ERROR) << "Padding length is too large : "
148  << static_cast<int>(num_padding_bytes);
149  return false;
150  }
151  *plaintext_size -= num_padding_bytes;
152  return true;
153  } else if (padding_scheme_ != kCtsPadding) {
154  LOG(ERROR) << "Expecting cipher text size to be multiple of "
155  << AES_BLOCK_SIZE << ", got " << ciphertext_size;
156  return false;
157  }
158 
159  DCHECK(!chain_across_calls_);
160  DCHECK_EQ(padding_scheme_, kCtsPadding);
161  if (ciphertext_size < AES_BLOCK_SIZE) {
162  // Don't have a full block, leave unencrypted.
163  memcpy(plaintext, ciphertext, ciphertext_size);
164  return true;
165  }
166 
167  // AES-CBC decrypt everything up to the next-to-last full block.
168  const size_t cbc_size = ciphertext_size - residual_block_size;
169  if (cbc_size > AES_BLOCK_SIZE) {
170  AES_cbc_encrypt(ciphertext, plaintext, cbc_size - AES_BLOCK_SIZE,
171  aes_key_.get(), local_iv.data(), AES_DECRYPT);
172  }
173 
174  const uint8_t* next_to_last_ciphertext_block =
175  ciphertext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE;
176  uint8_t* next_to_last_plaintext_block =
177  plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE;
178 
179  // Determine what the last IV should be so that we can "skip ahead" in the
180  // CBC decryption.
181  std::vector<uint8_t> last_iv(
182  ciphertext + ciphertext_size - residual_block_size,
183  ciphertext + ciphertext_size);
184  last_iv.resize(AES_BLOCK_SIZE, 0);
185 
186  // Decrypt the next-to-last block using the IV determined above. This decrypts
187  // the residual block bits.
188  AES_cbc_encrypt(next_to_last_ciphertext_block, next_to_last_plaintext_block,
189  AES_BLOCK_SIZE, aes_key_.get(), last_iv.data(), AES_DECRYPT);
190 
191  // Swap back the residual block bits and the next-to-last block.
192  if (plaintext == ciphertext) {
193  std::swap_ranges(next_to_last_plaintext_block,
194  next_to_last_plaintext_block + residual_block_size,
195  next_to_last_plaintext_block + AES_BLOCK_SIZE);
196  } else {
197  memcpy(next_to_last_plaintext_block + AES_BLOCK_SIZE,
198  next_to_last_plaintext_block, residual_block_size);
199  memcpy(next_to_last_plaintext_block,
200  next_to_last_ciphertext_block + AES_BLOCK_SIZE, residual_block_size);
201  }
202 
203  // Decrypt the next-to-last full block.
204  AES_cbc_encrypt(next_to_last_plaintext_block, next_to_last_plaintext_block,
205  AES_BLOCK_SIZE, aes_key_.get(), local_iv.data(), AES_DECRYPT);
206  return true;
207 }
208 
209 } // namespace media
210 } // namespace edash_packager
bool SetIv(const std::vector< uint8_t > &iv) override
bool SetIv(const std::vector< uint8_t > &iv) override
bool DecryptInternal(const uint8_t *ciphertext, size_t ciphertext_size, uint8_t *plaintext, size_t *plaintext_size) override
bool InitializeWithIv(const std::vector< uint8_t > &key, const std::vector< uint8_t > &iv) override
virtual bool DecryptInternal(const uint8_t *ciphertext, size_t ciphertext_size, uint8_t *plaintext, size_t *plaintext_size)=0
bool DecryptInternal(const uint8_t *ciphertext, size_t ciphertext_size, uint8_t *plaintext, size_t *plaintext_size) override
AesCbcDecryptor(CbcPaddingScheme padding_scheme, bool chain_across_calls)
bool InitializeWithIv(const std::vector< uint8_t > &key, const std::vector< uint8_t > &iv) override