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