Shaka Packager SDK
Loading...
Searching...
No Matches
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
15namespace {
16// Return true if [encrypted_buffer, encrypted_buffer + buffer_size) overlaps
17// with [decrypted_buffer, decrypted_buffer + buffer_size).
18bool 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
27namespace shaka {
28namespace media {
29
31 : key_source_(key_source) {
32 CHECK(key_source);
33}
34DecryptorSource::~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.
bool SetIv(const std::vector< uint8_t > &iv)
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.