7 #include "packager/media/crypto/encryption_handler.h"
14 #include "packager/media/base/aes_encryptor.h"
15 #include "packager/media/base/audio_stream_info.h"
16 #include "packager/media/base/common_pssh_generator.h"
17 #include "packager/media/base/key_source.h"
18 #include "packager/media/base/macros.h"
19 #include "packager/media/base/media_sample.h"
20 #include "packager/media/base/playready_pssh_generator.h"
21 #include "packager/media/base/protection_system_ids.h"
22 #include "packager/media/base/video_stream_info.h"
23 #include "packager/media/base/widevine_pssh_generator.h"
24 #include "packager/media/crypto/aes_encryptor_factory.h"
25 #include "packager/media/crypto/subsample_generator.h"
26 #include "packager/status_macros.h"
33 const size_t kStreamIndex = 0;
37 const uint8_t kKeyRotationDefaultKeyId[] = {
38 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40 const uint8_t kKeyRotationDefaultKey[] = {
41 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43 const uint8_t kKeyRotationDefaultIv[] = {
44 0, 0, 0, 0, 0, 0, 0, 0,
47 std::string GetStreamLabelForEncryption(
48 const StreamInfo& stream_info,
49 const std::function<std::string(
50 const EncryptionParams::EncryptedStreamAttributes& stream_attributes)>&
52 EncryptionParams::EncryptedStreamAttributes stream_attributes;
53 if (stream_info.stream_type() == kStreamAudio) {
54 stream_attributes.stream_type =
55 EncryptionParams::EncryptedStreamAttributes::kAudio;
56 }
else if (stream_info.stream_type() == kStreamVideo) {
57 const VideoStreamInfo& video_stream_info =
58 static_cast<const VideoStreamInfo&
>(stream_info);
59 stream_attributes.stream_type =
60 EncryptionParams::EncryptedStreamAttributes::kVideo;
61 stream_attributes.oneof.video.width = video_stream_info.width();
62 stream_attributes.oneof.video.height = video_stream_info.height();
64 return stream_label_func(stream_attributes);
67 bool IsPatternEncryptionScheme(FourCC protection_scheme) {
68 return protection_scheme == kAppleSampleAesProtectionScheme ||
69 protection_scheme == FOURCC_cbcs || protection_scheme == FOURCC_cens;
72 void FillPsshGenerators(
73 const EncryptionParams& encryption_params,
74 std::vector<std::unique_ptr<PsshGenerator>>* pssh_generators,
75 std::vector<std::vector<uint8_t>>* no_pssh_systems) {
76 if (has_flag(encryption_params.protection_systems,
78 pssh_generators->emplace_back(
new CommonPsshGenerator());
81 if (has_flag(encryption_params.protection_systems,
82 ProtectionSystem::kPlayReady)) {
83 pssh_generators->emplace_back(
new PlayReadyPsshGenerator(
84 encryption_params.playready_extra_header_data,
85 static_cast<FourCC
>(encryption_params.protection_scheme)));
88 if (has_flag(encryption_params.protection_systems,
89 ProtectionSystem::kWidevine)) {
90 pssh_generators->emplace_back(
new WidevinePsshGenerator(
91 static_cast<FourCC
>(encryption_params.protection_scheme)));
94 if (has_flag(encryption_params.protection_systems,
95 ProtectionSystem::kFairPlay)) {
96 no_pssh_systems->emplace_back(std::begin(kFairPlaySystemId),
97 std::end(kFairPlaySystemId));
102 if (has_flag(encryption_params.protection_systems,
103 ProtectionSystem::kMarlin)) {
104 no_pssh_systems->emplace_back(std::begin(kMarlinSystemId),
105 std::end(kMarlinSystemId));
108 if (pssh_generators->empty() && no_pssh_systems->empty() &&
109 (encryption_params.key_provider != KeyProvider::kRawKey ||
110 encryption_params.raw_key.pssh.empty())) {
111 pssh_generators->emplace_back(
new CommonPsshGenerator());
115 void AddProtectionSystemIfNotExist(
116 const ProtectionSystemSpecificInfo& pssh_info,
117 EncryptionConfig* encryption_config) {
118 for (
const auto& info : encryption_config->key_system_info) {
119 if (info.system_id == pssh_info.system_id)
122 encryption_config->key_system_info.push_back(pssh_info);
125 Status FillProtectionSystemInfo(
const EncryptionParams& encryption_params,
126 const EncryptionKey& encryption_key,
127 EncryptionConfig* encryption_config) {
129 if (encryption_key.key_ids.empty())
132 std::vector<std::unique_ptr<PsshGenerator>> pssh_generators;
133 std::vector<std::vector<uint8_t>> no_pssh_systems;
134 FillPsshGenerators(encryption_params, &pssh_generators, &no_pssh_systems);
136 encryption_config->key_system_info = encryption_key.key_system_info;
137 for (
const auto& pssh_generator : pssh_generators) {
138 const bool support_multiple_keys = pssh_generator->SupportMultipleKeys();
139 if (support_multiple_keys) {
140 ProtectionSystemSpecificInfo info;
141 RETURN_IF_ERROR(pssh_generator->GeneratePsshFromKeyIds(
142 encryption_key.key_ids, &info));
143 AddProtectionSystemIfNotExist(info, encryption_config);
145 ProtectionSystemSpecificInfo info;
146 RETURN_IF_ERROR(pssh_generator->GeneratePsshFromKeyIdAndKey(
147 encryption_key.key_id, encryption_key.key, &info));
148 AddProtectionSystemIfNotExist(info, encryption_config);
152 for (
const auto& no_pssh_system : no_pssh_systems) {
153 ProtectionSystemSpecificInfo info;
154 info.system_id = no_pssh_system;
155 AddProtectionSystemIfNotExist(info, encryption_config);
163 EncryptionHandler::EncryptionHandler(
const EncryptionParams& encryption_params,
164 KeySource* key_source)
165 : encryption_params_(encryption_params),
167 static_cast<FourCC>(encryption_params.protection_scheme)),
168 key_source_(key_source),
169 subsample_generator_(
170 new SubsampleGenerator(encryption_params.vp9_subsample_encryption)),
171 encryptor_factory_(new AesEncryptorFactory) {}
173 EncryptionHandler::~EncryptionHandler() =
default;
177 return Status(error::INVALID_ARGUMENT,
"Stream label function not set.");
179 if (num_input_streams() != 1 || next_output_stream_index() != 1) {
180 return Status(error::INVALID_ARGUMENT,
181 "Expects exactly one input and output.");
187 switch (stream_data->stream_data_type) {
188 case StreamDataType::kStreamInfo:
189 return ProcessStreamInfo(*stream_data->stream_info);
190 case StreamDataType::kSegmentInfo: {
191 std::shared_ptr<SegmentInfo> segment_info(
new SegmentInfo(
192 *stream_data->segment_info));
194 segment_info->is_encrypted = remaining_clear_lead_ <= 0;
196 const bool key_rotation_enabled = crypto_period_duration_ != 0;
197 if (key_rotation_enabled)
198 segment_info->key_rotation_encryption_config = encryption_config_;
199 if (!segment_info->is_subsegment) {
200 if (key_rotation_enabled)
201 check_new_crypto_period_ =
true;
202 if (remaining_clear_lead_ > 0)
203 remaining_clear_lead_ -= segment_info->duration;
208 case StreamDataType::kMediaSample:
209 return ProcessMediaSample(std::move(stream_data->media_sample));
211 VLOG(3) <<
"Stream data type "
212 <<
static_cast<int>(stream_data->stream_data_type) <<
" ignored.";
213 return Dispatch(std::move(stream_data));
218 if (clear_info.is_encrypted()) {
219 return Status(error::INVALID_ARGUMENT,
220 "Input stream is already encrypted.");
223 DCHECK_NE(kStreamUnknown, clear_info.stream_type());
224 DCHECK_NE(kStreamText, clear_info.stream_type());
225 std::shared_ptr<StreamInfo> stream_info = clear_info.
Clone();
227 subsample_generator_->Initialize(protection_scheme_, *stream_info));
229 remaining_clear_lead_ =
231 crypto_period_duration_ =
232 encryption_params_.crypto_period_duration_in_seconds *
233 stream_info->time_scale();
234 codec_ = stream_info->codec();
235 stream_label_ = GetStreamLabelForEncryption(
238 SetupProtectionPattern(stream_info->stream_type());
240 EncryptionKey encryption_key;
241 const bool key_rotation_enabled = crypto_period_duration_ != 0;
242 if (key_rotation_enabled) {
243 check_new_crypto_period_ =
true;
245 encryption_key.key_id.assign(std::begin(kKeyRotationDefaultKeyId),
246 std::end(kKeyRotationDefaultKeyId));
247 encryption_key.key.assign(std::begin(kKeyRotationDefaultKey),
248 std::end(kKeyRotationDefaultKey));
249 encryption_key.iv.assign(std::begin(kKeyRotationDefaultIv),
250 std::end(kKeyRotationDefaultIv));
252 RETURN_IF_ERROR(key_source_->
GetKey(stream_label_, &encryption_key));
254 if (!CreateEncryptor(encryption_key))
255 return Status(error::ENCRYPTION_FAILURE,
"Failed to create encryptor");
257 stream_info->set_is_encrypted(
true);
259 stream_info->set_encryption_config(*encryption_config_);
264 Status EncryptionHandler::ProcessMediaSample(
265 std::shared_ptr<const MediaSample> clear_sample) {
266 DCHECK(clear_sample);
270 std::vector<SubsampleEntry> subsamples;
271 RETURN_IF_ERROR(subsample_generator_->GenerateSubsamples(
272 clear_sample->data(), clear_sample->data_size(), &subsamples));
277 if (check_new_crypto_period_) {
280 const int64_t dts = std::max(clear_sample->dts(),
static_cast<int64_t
>(0));
281 const int64_t current_crypto_period_index = dts / crypto_period_duration_;
282 const uint32_t crypto_period_duration_in_seconds =
283 static_cast<uint32_t
>(encryption_params_.crypto_period_duration_in_seconds);
284 if (current_crypto_period_index != prev_crypto_period_index_) {
285 EncryptionKey encryption_key;
287 current_crypto_period_index, crypto_period_duration_in_seconds,
288 stream_label_, &encryption_key));
289 if (!CreateEncryptor(encryption_key))
290 return Status(error::ENCRYPTION_FAILURE,
"Failed to create encryptor");
291 prev_crypto_period_index_ = current_crypto_period_index;
293 check_new_crypto_period_ =
false;
298 if (remaining_clear_lead_ > 0) {
302 std::shared_ptr<uint8_t> cipher_sample_data(
303 new uint8_t[clear_sample->data_size()], std::default_delete<uint8_t[]>());
305 const uint8_t* source = clear_sample->data();
306 uint8_t* dest = cipher_sample_data.get();
307 if (!subsamples.empty()) {
308 size_t total_size = 0;
309 for (
const SubsampleEntry& subsample : subsamples) {
310 if (subsample.clear_bytes > 0) {
311 memcpy(dest, source, subsample.clear_bytes);
312 source += subsample.clear_bytes;
313 dest += subsample.clear_bytes;
314 total_size += subsample.clear_bytes;
316 if (subsample.cipher_bytes > 0) {
317 EncryptBytes(source, subsample.cipher_bytes, dest);
318 source += subsample.cipher_bytes;
319 dest += subsample.cipher_bytes;
320 total_size += subsample.cipher_bytes;
323 DCHECK_EQ(total_size, clear_sample->data_size());
325 EncryptBytes(source, clear_sample->data_size(), dest);
328 std::shared_ptr<MediaSample> cipher_sample(clear_sample->Clone());
329 cipher_sample->TransferData(std::move(cipher_sample_data),
330 clear_sample->data_size());
335 cipher_sample->set_is_encrypted(
true);
336 std::unique_ptr<DecryptConfig> decrypt_config(
new DecryptConfig(
337 encryption_config_->key_id, encryptor_->iv(), subsamples,
338 protection_scheme_, crypt_byte_block_, skip_byte_block_));
339 cipher_sample->set_decrypt_config(std::move(decrypt_config));
341 encryptor_->UpdateIv();
346 void EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
347 if (stream_type == kStreamVideo &&
348 IsPatternEncryptionScheme(protection_scheme_)) {
355 crypt_byte_block_ = 0u;
356 skip_byte_block_ = 0u;
360 bool EncryptionHandler::CreateEncryptor(
const EncryptionKey& encryption_key) {
361 std::unique_ptr<AesCryptor> encryptor = encryptor_factory_->CreateEncryptor(
362 protection_scheme_, crypt_byte_block_, skip_byte_block_, codec_,
363 encryption_key.key, encryption_key.iv);
366 encryptor_ = std::move(encryptor);
368 encryption_config_.reset(
new EncryptionConfig);
369 encryption_config_->protection_scheme = protection_scheme_;
370 encryption_config_->crypt_byte_block = crypt_byte_block_;
371 encryption_config_->skip_byte_block = skip_byte_block_;
373 const std::vector<uint8_t>& iv = encryptor_->iv();
374 if (encryptor_->use_constant_iv()) {
375 encryption_config_->per_sample_iv_size = 0;
376 encryption_config_->constant_iv = iv;
378 encryption_config_->per_sample_iv_size =
static_cast<uint8_t
>(iv.size());
381 encryption_config_->key_id = encryption_key.key_id;
382 const auto status = FillProtectionSystemInfo(
383 encryption_params_, encryption_key, encryption_config_.get());
387 void EncryptionHandler::EncryptBytes(
const uint8_t* source,
393 CHECK(encryptor_->Crypt(source, source_size, dest));
396 void EncryptionHandler::InjectSubsampleGeneratorForTesting(
397 std::unique_ptr<SubsampleGenerator> generator) {
398 subsample_generator_ = std::move(generator);
401 void EncryptionHandler::InjectEncryptorFactoryForTesting(
402 std::unique_ptr<AesEncryptorFactory> encryptor_factory) {
403 encryptor_factory_ = std::move(encryptor_factory);