Shaka Packager SDK
decryptor_source.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/decryptor_source.h"
8 
9 #include "packager/base/logging.h"
10 #include "packager/media/base/aes_decryptor.h"
11 #include "packager/media/base/aes_pattern_cryptor.h"
12 
13 namespace {
14 // Return true if [encrypted_buffer, encrypted_buffer + buffer_size) overlaps
15 // with [decrypted_buffer, decrypted_buffer + buffer_size).
16 bool CheckMemoryOverlap(const uint8_t* encrypted_buffer,
17  size_t buffer_size,
18  uint8_t* decrypted_buffer) {
19  return (decrypted_buffer < encrypted_buffer)
20  ? (encrypted_buffer < decrypted_buffer + buffer_size)
21  : (decrypted_buffer < encrypted_buffer + buffer_size);
22 }
23 } // namespace
24 
25 namespace shaka {
26 namespace media {
27 
29  : key_source_(key_source) {
30  CHECK(key_source);
31 }
32 DecryptorSource::~DecryptorSource() {}
33 
35  const uint8_t* encrypted_buffer,
36  size_t buffer_size,
37  uint8_t* decrypted_buffer) {
38  DCHECK(decrypt_config);
39  DCHECK(encrypted_buffer);
40  DCHECK(decrypted_buffer);
41 
42  if (CheckMemoryOverlap(encrypted_buffer, buffer_size, decrypted_buffer)) {
43  LOG(ERROR) << "Encrypted buffer and decrypted buffer cannot overlap.";
44  return false;
45  }
46 
47  // Get the decryptor object.
48  AesCryptor* decryptor = nullptr;
49  auto found = decryptor_map_.find(decrypt_config->key_id());
50  if (found == decryptor_map_.end()) {
51  // Create new AesDecryptor based on decryption mode.
52  EncryptionKey key;
53  Status status(key_source_->GetKey(decrypt_config->key_id(), &key));
54  if (!status.ok()) {
55  LOG(ERROR) << "Error retrieving decryption key: " << status;
56  return false;
57  }
58 
59  std::unique_ptr<AesCryptor> aes_decryptor;
60  switch (decrypt_config->protection_scheme()) {
61  case FOURCC_cenc:
62  aes_decryptor.reset(new AesCtrDecryptor);
63  break;
64  case FOURCC_cbc1:
65  aes_decryptor.reset(new AesCbcDecryptor(kNoPadding));
66  break;
67  case FOURCC_cens:
68  aes_decryptor.reset(new AesPatternCryptor(
69  decrypt_config->crypt_byte_block(),
70  decrypt_config->skip_byte_block(),
72  AesCryptor::kDontUseConstantIv,
73  std::unique_ptr<AesCryptor>(new AesCtrDecryptor())));
74  break;
75  case FOURCC_cbcs:
76  aes_decryptor.reset(new AesPatternCryptor(
77  decrypt_config->crypt_byte_block(),
78  decrypt_config->skip_byte_block(),
80  AesCryptor::kUseConstantIv,
81  std::unique_ptr<AesCryptor>(new AesCbcDecryptor(kNoPadding))));
82  break;
83  default:
84  LOG(ERROR) << "Unsupported protection scheme: "
85  << decrypt_config->protection_scheme();
86  return false;
87  }
88 
89  if (!aes_decryptor->InitializeWithIv(key.key, decrypt_config->iv())) {
90  LOG(ERROR) << "Failed to initialize AesDecryptor for decryption.";
91  return false;
92  }
93  decryptor = aes_decryptor.get();
94  decryptor_map_[decrypt_config->key_id()] = std::move(aes_decryptor);
95  } else {
96  decryptor = found->second.get();
97  }
98  if (!decryptor->SetIv(decrypt_config->iv())) {
99  LOG(ERROR) << "Invalid initialization vector.";
100  return false;
101  }
102 
103  if (decrypt_config->subsamples().empty()) {
104  // Sample not encrypted using subsample encryption. Decrypt whole.
105  if (!decryptor->Crypt(encrypted_buffer, buffer_size, decrypted_buffer)) {
106  LOG(ERROR) << "Error during bulk sample decryption.";
107  return false;
108  }
109  return true;
110  }
111 
112  // Subsample decryption.
113  const std::vector<SubsampleEntry>& subsamples = decrypt_config->subsamples();
114  const uint8_t* current_ptr = encrypted_buffer;
115  const uint8_t* const buffer_end = encrypted_buffer + buffer_size;
116  for (const auto& subsample : subsamples) {
117  if ((current_ptr + subsample.clear_bytes + subsample.cipher_bytes) >
118  buffer_end) {
119  LOG(ERROR) << "Subsamples overflow sample buffer.";
120  return false;
121  }
122  memcpy(decrypted_buffer, current_ptr, subsample.clear_bytes);
123  current_ptr += subsample.clear_bytes;
124  decrypted_buffer += subsample.clear_bytes;
125  if (!decryptor->Crypt(current_ptr, subsample.cipher_bytes,
126  decrypted_buffer)) {
127  LOG(ERROR) << "Error decrypting subsample buffer.";
128  return false;
129  }
130  current_ptr += subsample.cipher_bytes;
131  decrypted_buffer += subsample.cipher_bytes;
132  }
133  return true;
134 }
135 
136 } // namespace media
137 } // namespace shaka
Class which implements AES-CBC (Cipher block chaining) decryption.
Definition: aes_decryptor.h:25
bool SetIv(const std::vector< uint8_t > &iv)
Definition: aes_cryptor.cc:70
Implements pattern-based encryption/decryption.
DecryptorSource(KeySource *key_source)
bool DecryptSampleBuffer(const DecryptConfig *decrypt_config, const uint8_t *encrypted_buffer, size_t buffer_size, uint8_t *decrypted_buffer)
KeySource is responsible for encryption key acquisition.
Definition: key_source.h:51
virtual Status GetKey(const std::string &stream_label, EncryptionKey *key)=0
All the methods that are virtual are virtual for mocking.