Shaka Packager SDK
encryption_handler.cc
1 // Copyright 2017 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/crypto/encryption_handler.h>
8 
9 #include <algorithm>
10 #include <cstddef>
11 #include <cstdint>
12 
13 #include <absl/log/check.h>
14 
15 #include <packager/macros/logging.h>
16 #include <packager/macros/status.h>
17 #include <packager/media/base/aes_encryptor.h>
18 #include <packager/media/base/audio_stream_info.h>
19 #include <packager/media/base/common_pssh_generator.h>
20 #include <packager/media/base/key_source.h>
21 #include <packager/media/base/media_sample.h>
22 #include <packager/media/base/playready_pssh_generator.h>
23 #include <packager/media/base/protection_system_ids.h>
24 #include <packager/media/base/video_stream_info.h>
25 #include <packager/media/base/widevine_pssh_generator.h>
26 #include <packager/media/crypto/aes_encryptor_factory.h>
27 #include <packager/media/crypto/subsample_generator.h>
28 
29 namespace shaka {
30 namespace media {
31 
32 namespace {
33 // The encryption handler only supports a single output.
34 const size_t kStreamIndex = 0;
35 
36 // The default KID, KEY and IV for key rotation are all 0s.
37 // They are placeholders and are not really being used to encrypt data.
38 const uint8_t kKeyRotationDefaultKeyId[] = {
39  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40 };
41 const uint8_t kKeyRotationDefaultKey[] = {
42  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43 };
44 const uint8_t kKeyRotationDefaultIv[] = {
45  0, 0, 0, 0, 0, 0, 0, 0,
46 };
47 
48 std::string GetStreamLabelForEncryption(
49  const StreamInfo& stream_info,
50  const std::function<std::string(
51  const EncryptionParams::EncryptedStreamAttributes& stream_attributes)>&
52  stream_label_func) {
53  EncryptionParams::EncryptedStreamAttributes stream_attributes;
54  if (stream_info.stream_type() == kStreamAudio) {
55  stream_attributes.stream_type =
56  EncryptionParams::EncryptedStreamAttributes::kAudio;
57  } else if (stream_info.stream_type() == kStreamVideo) {
58  const VideoStreamInfo& video_stream_info =
59  static_cast<const VideoStreamInfo&>(stream_info);
60  stream_attributes.stream_type =
61  EncryptionParams::EncryptedStreamAttributes::kVideo;
62  stream_attributes.oneof.video.width = video_stream_info.width();
63  stream_attributes.oneof.video.height = video_stream_info.height();
64  }
65  return stream_label_func(stream_attributes);
66 }
67 
68 bool IsPatternEncryptionScheme(FourCC protection_scheme) {
69  return protection_scheme == kAppleSampleAesProtectionScheme ||
70  protection_scheme == FOURCC_cbcs || protection_scheme == FOURCC_cens;
71 }
72 
73 void FillPsshGenerators(
74  const EncryptionParams& encryption_params,
75  std::vector<std::unique_ptr<PsshGenerator>>* pssh_generators,
76  std::vector<std::vector<uint8_t>>* no_pssh_systems) {
77  if (has_flag(encryption_params.protection_systems,
78  ProtectionSystem::kCommon)) {
79  pssh_generators->emplace_back(new CommonPsshGenerator());
80  }
81 
82  if (has_flag(encryption_params.protection_systems,
83  ProtectionSystem::kPlayReady)) {
84  pssh_generators->emplace_back(new PlayReadyPsshGenerator(
85  encryption_params.playready_extra_header_data,
86  static_cast<FourCC>(encryption_params.protection_scheme)));
87  }
88 
89  if (has_flag(encryption_params.protection_systems,
90  ProtectionSystem::kWidevine)) {
91  pssh_generators->emplace_back(new WidevinePsshGenerator(
92  static_cast<FourCC>(encryption_params.protection_scheme)));
93  }
94 
95  if (has_flag(encryption_params.protection_systems,
96  ProtectionSystem::kFairPlay)) {
97  no_pssh_systems->emplace_back(std::begin(kFairPlaySystemId),
98  std::end(kFairPlaySystemId));
99  }
100  // We only support Marlin Adaptive Streaming Specification – Simple Profile
101  // with Implicit Content ID Mapping, which does not need a PSSH. Marlin
102  // specific PSSH with Explicit Content ID Mapping is not generated.
103  if (has_flag(encryption_params.protection_systems,
104  ProtectionSystem::kMarlin)) {
105  no_pssh_systems->emplace_back(std::begin(kMarlinSystemId),
106  std::end(kMarlinSystemId));
107  }
108 
109  if (pssh_generators->empty() && no_pssh_systems->empty() &&
110  (encryption_params.key_provider != KeyProvider::kRawKey ||
111  encryption_params.raw_key.pssh.empty())) {
112  pssh_generators->emplace_back(new CommonPsshGenerator());
113  }
114 }
115 
116 void AddProtectionSystemIfNotExist(
117  const ProtectionSystemSpecificInfo& pssh_info,
118  EncryptionConfig* encryption_config) {
119  for (const auto& info : encryption_config->key_system_info) {
120  if (info.system_id == pssh_info.system_id)
121  return;
122  }
123  encryption_config->key_system_info.push_back(pssh_info);
124 }
125 
126 Status FillProtectionSystemInfo(const EncryptionParams& encryption_params,
127  const EncryptionKey& encryption_key,
128  EncryptionConfig* encryption_config) {
129  // If generating dummy keys for key rotation, don't generate PSSH info.
130  if (encryption_key.key_ids.empty())
131  return Status::OK;
132 
133  std::vector<std::unique_ptr<PsshGenerator>> pssh_generators;
134  std::vector<std::vector<uint8_t>> no_pssh_systems;
135  FillPsshGenerators(encryption_params, &pssh_generators, &no_pssh_systems);
136 
137  encryption_config->key_system_info = encryption_key.key_system_info;
138  for (const auto& pssh_generator : pssh_generators) {
139  const bool support_multiple_keys = pssh_generator->SupportMultipleKeys();
140  if (support_multiple_keys) {
141  ProtectionSystemSpecificInfo info;
142  RETURN_IF_ERROR(pssh_generator->GeneratePsshFromKeyIds(
143  encryption_key.key_ids, &info));
144  AddProtectionSystemIfNotExist(info, encryption_config);
145  } else {
146  ProtectionSystemSpecificInfo info;
147  RETURN_IF_ERROR(pssh_generator->GeneratePsshFromKeyIdAndKey(
148  encryption_key.key_id, encryption_key.key, &info));
149  AddProtectionSystemIfNotExist(info, encryption_config);
150  }
151  }
152 
153  for (const auto& no_pssh_system : no_pssh_systems) {
154  ProtectionSystemSpecificInfo info;
155  info.system_id = no_pssh_system;
156  AddProtectionSystemIfNotExist(info, encryption_config);
157  }
158 
159  return Status::OK;
160 }
161 
162 } // namespace
163 
164 EncryptionHandler::EncryptionHandler(const EncryptionParams& encryption_params,
165  KeySource* key_source)
166  : encryption_params_(encryption_params),
167  protection_scheme_(
168  static_cast<FourCC>(encryption_params.protection_scheme)),
169  key_source_(key_source),
170  subsample_generator_(
171  new SubsampleGenerator(encryption_params.vp9_subsample_encryption)),
172  encryptor_factory_(new AesEncryptorFactory) {}
173 
174 EncryptionHandler::~EncryptionHandler() = default;
175 
176 Status EncryptionHandler::InitializeInternal() {
177  if (!encryption_params_.stream_label_func) {
178  return Status(error::INVALID_ARGUMENT, "Stream label function not set.");
179  }
180  if (num_input_streams() != 1 || next_output_stream_index() != 1) {
181  return Status(error::INVALID_ARGUMENT,
182  "Expects exactly one input and output.");
183  }
184  return Status::OK;
185 }
186 
187 Status EncryptionHandler::Process(std::unique_ptr<StreamData> stream_data) {
188  switch (stream_data->stream_data_type) {
189  case StreamDataType::kStreamInfo:
190  return ProcessStreamInfo(*stream_data->stream_info);
191  case StreamDataType::kSegmentInfo: {
192  std::shared_ptr<SegmentInfo> segment_info(new SegmentInfo(
193  *stream_data->segment_info));
194 
195  segment_info->is_encrypted = remaining_clear_lead_ <= 0;
196 
197  const bool key_rotation_enabled = crypto_period_duration_ != 0;
198  if (key_rotation_enabled)
199  segment_info->key_rotation_encryption_config = encryption_config_;
200  if (!segment_info->is_subsegment) {
201  if (key_rotation_enabled)
202  check_new_crypto_period_ = true;
203  if (remaining_clear_lead_ > 0)
204  remaining_clear_lead_ -= segment_info->duration;
205  }
206 
207  return DispatchSegmentInfo(kStreamIndex, segment_info);
208  }
209  case StreamDataType::kMediaSample:
210  return ProcessMediaSample(std::move(stream_data->media_sample));
211  default:
212  VLOG(3) << "Stream data type "
213  << static_cast<int>(stream_data->stream_data_type) << " ignored.";
214  return Dispatch(std::move(stream_data));
215  }
216 }
217 
218 Status EncryptionHandler::ProcessStreamInfo(const StreamInfo& clear_info) {
219  if (clear_info.is_encrypted()) {
220  return Status(error::INVALID_ARGUMENT,
221  "Input stream is already encrypted.");
222  }
223 
224  DCHECK_NE(kStreamUnknown, clear_info.stream_type());
225  DCHECK_NE(kStreamText, clear_info.stream_type());
226  std::shared_ptr<StreamInfo> stream_info = clear_info.Clone();
227  RETURN_IF_ERROR(
228  subsample_generator_->Initialize(protection_scheme_, *stream_info));
229 
230  remaining_clear_lead_ =
231  encryption_params_.clear_lead_in_seconds * stream_info->time_scale();
232  crypto_period_duration_ =
233  encryption_params_.crypto_period_duration_in_seconds *
234  stream_info->time_scale();
235  codec_ = stream_info->codec();
236  stream_label_ = GetStreamLabelForEncryption(
237  *stream_info, encryption_params_.stream_label_func);
238 
239  SetupProtectionPattern(stream_info->stream_type());
240 
241  EncryptionKey encryption_key;
242  const bool key_rotation_enabled = crypto_period_duration_ != 0;
243  if (key_rotation_enabled) {
244  check_new_crypto_period_ = true;
245  // Setup dummy key id, key and iv to signal encryption for key rotation.
246  encryption_key.key_id.assign(std::begin(kKeyRotationDefaultKeyId),
247  std::end(kKeyRotationDefaultKeyId));
248  encryption_key.key.assign(std::begin(kKeyRotationDefaultKey),
249  std::end(kKeyRotationDefaultKey));
250  encryption_key.iv.assign(std::begin(kKeyRotationDefaultIv),
251  std::end(kKeyRotationDefaultIv));
252  } else {
253  RETURN_IF_ERROR(key_source_->GetKey(stream_label_, &encryption_key));
254  }
255  if (!CreateEncryptor(encryption_key))
256  return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
257 
258  stream_info->set_is_encrypted(true);
259  stream_info->set_has_clear_lead(encryption_params_.clear_lead_in_seconds > 0);
260  stream_info->set_encryption_config(*encryption_config_);
261 
262  return DispatchStreamInfo(kStreamIndex, stream_info);
263 }
264 
265 Status EncryptionHandler::ProcessMediaSample(
266  std::shared_ptr<const MediaSample> clear_sample) {
267  DCHECK(clear_sample);
268 
269  // Process the frame even if the frame is not encrypted as the next
270  // (encrypted) frame may be dependent on this clear frame.
271  std::vector<SubsampleEntry> subsamples;
272  RETURN_IF_ERROR(subsample_generator_->GenerateSubsamples(
273  clear_sample->data(), clear_sample->data_size(), &subsamples));
274 
275  // Need to setup the encryptor for new segments even if this segment does not
276  // need to be encrypted, so we can signal encryption metadata earlier to
277  // allows clients to prefetch the keys.
278  if (check_new_crypto_period_) {
279  // |dts| can be negative, e.g. after EditList adjustments. Normalized to 0
280  // in that case.
281  const int64_t dts = std::max(clear_sample->dts(), static_cast<int64_t>(0));
282  const int64_t current_crypto_period_index = dts / crypto_period_duration_;
283  const int32_t crypto_period_duration_in_seconds = static_cast<int32_t>(
284  encryption_params_.crypto_period_duration_in_seconds);
285  if (current_crypto_period_index != prev_crypto_period_index_) {
286  EncryptionKey encryption_key;
287  RETURN_IF_ERROR(key_source_->GetCryptoPeriodKey(
288  current_crypto_period_index, crypto_period_duration_in_seconds,
289  stream_label_, &encryption_key));
290  if (!CreateEncryptor(encryption_key))
291  return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
292  prev_crypto_period_index_ = current_crypto_period_index;
293  }
294  check_new_crypto_period_ = false;
295  }
296 
297  // Since there is no encryption needed right now, send the clear copy
298  // downstream so we can save the costs of copying it.
299  if (remaining_clear_lead_ > 0) {
300  return DispatchMediaSample(kStreamIndex, std::move(clear_sample));
301  }
302 
303  size_t ciphertext_size =
304  encryptor_->RequiredOutputSize(clear_sample->data_size());
305 
306  std::shared_ptr<uint8_t> cipher_sample_data(new uint8_t[ciphertext_size],
307  std::default_delete<uint8_t[]>());
308 
309  const uint8_t* source = clear_sample->data();
310  uint8_t* dest = cipher_sample_data.get();
311  if (!subsamples.empty()) {
312  size_t total_size = 0;
313  for (const SubsampleEntry& subsample : subsamples) {
314  if (subsample.clear_bytes > 0) {
315  // clear_bytes is the number of bytes to leave in the clear
316  memcpy(dest, source, subsample.clear_bytes);
317  source += subsample.clear_bytes;
318  dest += subsample.clear_bytes;
319  total_size += subsample.clear_bytes;
320  }
321  if (subsample.cipher_bytes > 0) {
322  // cipher_bytes is the number of bytes we want to encrypt
323  EncryptBytes(source, subsample.cipher_bytes, dest, ciphertext_size);
324  source += subsample.cipher_bytes;
325  dest += subsample.cipher_bytes;
326  total_size += subsample.cipher_bytes;
327  }
328  }
329  DCHECK_EQ(total_size, clear_sample->data_size());
330  } else {
331  EncryptBytes(source, clear_sample->data_size(), dest, ciphertext_size);
332  }
333 
334  std::shared_ptr<MediaSample> cipher_sample(clear_sample->Clone());
335  cipher_sample->TransferData(std::move(cipher_sample_data),
336  clear_sample->data_size());
337 
338  // Finish initializing the sample before sending it downstream. We must
339  // wait until now to finish the initialization as we will lose access to
340  // |decrypt_config| once we set it.
341  cipher_sample->set_is_encrypted(true);
342  std::unique_ptr<DecryptConfig> decrypt_config(new DecryptConfig(
343  encryption_config_->key_id, encryptor_->iv(), subsamples,
344  protection_scheme_, crypt_byte_block_, skip_byte_block_));
345  cipher_sample->set_decrypt_config(std::move(decrypt_config));
346 
347  encryptor_->UpdateIv();
348 
349  return DispatchMediaSample(kStreamIndex, std::move(cipher_sample));
350 }
351 
352 void EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
353  if (stream_type == kStreamVideo &&
354  IsPatternEncryptionScheme(protection_scheme_)) {
355  crypt_byte_block_ = encryption_params_.crypt_byte_block;
356  skip_byte_block_ = encryption_params_.skip_byte_block;
357  } else {
358  // Audio stream in pattern encryption scheme does not use pattern; it uses
359  // whole-block full sample encryption instead. Non-pattern encryption does
360  // not have pattern.
361  crypt_byte_block_ = 0u;
362  skip_byte_block_ = 0u;
363  }
364 }
365 
366 bool EncryptionHandler::CreateEncryptor(const EncryptionKey& encryption_key) {
367  std::unique_ptr<AesCryptor> encryptor = encryptor_factory_->CreateEncryptor(
368  protection_scheme_, crypt_byte_block_, skip_byte_block_, codec_,
369  encryption_key.key, encryption_key.iv);
370  if (!encryptor)
371  return false;
372  encryptor_ = std::move(encryptor);
373 
374  encryption_config_.reset(new EncryptionConfig);
375  encryption_config_->protection_scheme = protection_scheme_;
376  encryption_config_->crypt_byte_block = crypt_byte_block_;
377  encryption_config_->skip_byte_block = skip_byte_block_;
378 
379  const std::vector<uint8_t>& iv = encryptor_->iv();
380  if (encryptor_->use_constant_iv()) {
381  encryption_config_->per_sample_iv_size = 0;
382  encryption_config_->constant_iv = iv;
383  } else {
384  encryption_config_->per_sample_iv_size = static_cast<uint8_t>(iv.size());
385  }
386 
387  encryption_config_->key_id = encryption_key.key_id;
388  const auto status = FillProtectionSystemInfo(
389  encryption_params_, encryption_key, encryption_config_.get());
390  return status.ok();
391 }
392 
393 void EncryptionHandler::EncryptBytes(const uint8_t* source,
394  size_t source_size,
395  uint8_t* dest,
396  size_t dest_size) {
397  DCHECK(source);
398  DCHECK(dest);
399  DCHECK(encryptor_);
400  CHECK(encryptor_->Crypt(source, source_size, dest, &dest_size));
401 }
402 
403 void EncryptionHandler::InjectSubsampleGeneratorForTesting(
404  std::unique_ptr<SubsampleGenerator> generator) {
405  subsample_generator_ = std::move(generator);
406 }
407 
408 void EncryptionHandler::InjectEncryptorFactoryForTesting(
409  std::unique_ptr<AesEncryptorFactory> encryptor_factory) {
410  encryptor_factory_ = std::move(encryptor_factory);
411 }
412 
413 } // namespace media
414 } // namespace shaka
Abstract class holds stream information.
Definition: stream_info.h:71
virtual std::unique_ptr< StreamInfo > Clone() const =0
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66