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