DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
encryption_handler.cc
1 // Copyright 2017 Google Inc. 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 <stddef.h>
10 #include <stdint.h>
11 
12 #include <limits>
13 
14 #include "packager/media/base/aes_encryptor.h"
15 #include "packager/media/base/aes_pattern_cryptor.h"
16 #include "packager/media/base/key_source.h"
17 #include "packager/media/base/media_sample.h"
18 #include "packager/media/base/video_stream_info.h"
19 #include "packager/media/codecs/video_slice_header_parser.h"
20 #include "packager/media/codecs/vp8_parser.h"
21 #include "packager/media/codecs/vp9_parser.h"
22 
23 namespace shaka {
24 namespace media {
25 
26 namespace {
27 const size_t kCencBlockSize = 16u;
28 
29 // The default KID for key rotation is all 0s.
30 const uint8_t kKeyRotationDefaultKeyId[] = {
31  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32 };
33 
34 // Adds one or more subsamples to |*subsamples|. This may add more than one
35 // if one of the values overflows the integer in the subsample.
36 void AddSubsample(uint64_t clear_bytes,
37  uint64_t cipher_bytes,
38  DecryptConfig* decrypt_config) {
39  CHECK_LT(cipher_bytes, std::numeric_limits<uint32_t>::max());
40  const uint64_t kUInt16Max = std::numeric_limits<uint16_t>::max();
41  while (clear_bytes > kUInt16Max) {
42  decrypt_config->AddSubsample(kUInt16Max, 0);
43  clear_bytes -= kUInt16Max;
44  }
45 
46  if (clear_bytes > 0 || cipher_bytes > 0)
47  decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
48 }
49 
50 uint8_t GetNaluLengthSize(const StreamInfo& stream_info) {
51  if (stream_info.stream_type() != kStreamVideo)
52  return 0;
53 
54  const VideoStreamInfo& video_stream_info =
55  static_cast<const VideoStreamInfo&>(stream_info);
56  return video_stream_info.nalu_length_size();
57 }
58 
59 KeySource::TrackType GetTrackTypeForEncryption(const StreamInfo& stream_info,
60  uint32_t max_sd_pixels,
61  uint32_t max_hd_pixels,
62  uint32_t max_uhd1_pixels) {
63  if (stream_info.stream_type() == kStreamAudio)
64  return KeySource::TRACK_TYPE_AUDIO;
65 
66  if (stream_info.stream_type() != kStreamVideo)
67  return KeySource::TRACK_TYPE_UNKNOWN;
68 
69  DCHECK_EQ(kStreamVideo, stream_info.stream_type());
70  const VideoStreamInfo& video_stream_info =
71  static_cast<const VideoStreamInfo&>(stream_info);
72  uint32_t pixels = video_stream_info.width() * video_stream_info.height();
73  if (pixels <= max_sd_pixels) {
74  return KeySource::TRACK_TYPE_SD;
75  } else if (pixels <= max_hd_pixels) {
76  return KeySource::TRACK_TYPE_HD;
77  } else if (pixels <= max_uhd1_pixels) {
78  return KeySource::TRACK_TYPE_UHD1;
79  }
80  return KeySource::TRACK_TYPE_UHD2;
81 }
82 } // namespace
83 
84 EncryptionHandler::EncryptionHandler(
85  const EncryptionOptions& encryption_options,
86  KeySource* key_source)
87  : encryption_options_(encryption_options), key_source_(key_source) {}
88 
89 EncryptionHandler::~EncryptionHandler() {}
90 
92  if (num_input_streams() != 1 || next_output_stream_index() != 1) {
93  return Status(error::INVALID_ARGUMENT,
94  "Expects exactly one input and output.");
95  }
96  return Status::OK;
97 }
98 
99 Status EncryptionHandler::Process(std::unique_ptr<StreamData> stream_data) {
100  Status status;
101  switch (stream_data->stream_data_type) {
102  case StreamDataType::kStreamInfo:
103  status = ProcessStreamInfo(stream_data->stream_info.get());
104  break;
105  case StreamDataType::kSegmentInfo: {
106  SegmentInfo* segment_info = stream_data->segment_info.get();
107  segment_info->is_encrypted = remaining_clear_lead_ <= 0;
108 
109  const bool key_rotation_enabled = crypto_period_duration_ != 0;
110  if (key_rotation_enabled)
111  segment_info->key_rotation_encryption_config = encryption_config_;
112  if (!segment_info->is_subsegment) {
113  if (key_rotation_enabled)
114  check_new_crypto_period_ = true;
115  if (remaining_clear_lead_ > 0)
116  remaining_clear_lead_ -= segment_info->duration;
117  }
118  break;
119  }
120  case StreamDataType::kMediaSample:
121  status = ProcessMediaSample(stream_data->media_sample.get());
122  break;
123  default:
124  VLOG(3) << "Stream data type "
125  << static_cast<int>(stream_data->stream_data_type) << " ignored.";
126  break;
127  }
128  return status.ok() ? Dispatch(std::move(stream_data)) : status;
129 }
130 
131 Status EncryptionHandler::ProcessStreamInfo(StreamInfo* stream_info) {
132  if (stream_info->is_encrypted()) {
133  return Status(error::INVALID_ARGUMENT,
134  "Input stream is already encrypted.");
135  }
136 
137  remaining_clear_lead_ =
138  encryption_options_.clear_lead_in_seconds * stream_info->time_scale();
139  crypto_period_duration_ =
140  encryption_options_.crypto_period_duration_in_seconds *
141  stream_info->time_scale();
142  codec_ = stream_info->codec();
143  nalu_length_size_ = GetNaluLengthSize(*stream_info);
144  track_type_ = GetTrackTypeForEncryption(
145  *stream_info, encryption_options_.max_sd_pixels,
146  encryption_options_.max_hd_pixels, encryption_options_.max_uhd1_pixels);
147  switch (codec_) {
148  case kCodecVP9:
149  if (encryption_options_.vp9_subsample_encryption)
150  vpx_parser_.reset(new VP9Parser);
151  break;
152  case kCodecH264:
153  header_parser_.reset(new H264VideoSliceHeaderParser);
154  break;
155  case kCodecH265:
156  header_parser_.reset(new H265VideoSliceHeaderParser);
157  break;
158  default:
159  // Other codecs should have nalu length size == 0.
160  if (nalu_length_size_ > 0) {
161  LOG(WARNING) << "Unknown video codec '" << codec_ << "'";
162  return Status(error::ENCRYPTION_FAILURE, "Unknown video codec.");
163  }
164  }
165  if (header_parser_) {
166  CHECK_NE(nalu_length_size_, 0u) << "AnnexB stream is not supported yet";
167  if (!header_parser_->Initialize(stream_info->codec_config())) {
168  return Status(error::ENCRYPTION_FAILURE,
169  "Fail to read SPS and PPS data.");
170  }
171  }
172 
173  Status status = SetupProtectionPattern(stream_info->stream_type());
174  if (!status.ok())
175  return status;
176 
177  EncryptionKey encryption_key;
178  const bool key_rotation_enabled = crypto_period_duration_ != 0;
179  if (key_rotation_enabled) {
180  check_new_crypto_period_ = true;
181  // Setup dummy key id and key to signal encryption for key rotation.
182  encryption_key.key_id.assign(
183  kKeyRotationDefaultKeyId,
184  kKeyRotationDefaultKeyId + sizeof(kKeyRotationDefaultKeyId));
185  // The key is not really used to encrypt any data. It is there just for
186  // convenience.
187  encryption_key.key = encryption_key.key_id;
188  } else {
189  status = key_source_->GetKey(track_type_, &encryption_key);
190  if (!status.ok())
191  return status;
192  }
193  if (!CreateEncryptor(encryption_key))
194  return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
195 
196  stream_info->set_is_encrypted(true);
197  stream_info->set_has_clear_lead(encryption_options_.clear_lead_in_seconds >
198  0);
199  stream_info->set_encryption_config(*encryption_config_);
200  return Status::OK;
201 }
202 
203 Status EncryptionHandler::ProcessMediaSample(MediaSample* sample) {
204  // We need to parse the frame (which also updates the vpx parser) even if the
205  // frame is not encrypted as the next (encrypted) frame may be dependent on
206  // this clear frame.
207  std::vector<VPxFrameInfo> vpx_frames;
208  if (vpx_parser_ &&
209  !vpx_parser_->Parse(sample->data(), sample->data_size(), &vpx_frames)) {
210  return Status(error::ENCRYPTION_FAILURE, "Failed to parse vpx frame.");
211  }
212 
213  // Need to setup the encryptor for new segments even if this segment does not
214  // need to be encrypted, so we can signal encryption metadata earlier to
215  // allows clients to prefetch the keys.
216  if (check_new_crypto_period_) {
217  const int64_t current_crypto_period_index =
218  sample->dts() / crypto_period_duration_;
219  if (current_crypto_period_index != prev_crypto_period_index_) {
220  EncryptionKey encryption_key;
221  Status status = key_source_->GetCryptoPeriodKey(
222  current_crypto_period_index, track_type_, &encryption_key);
223  if (!status.ok())
224  return status;
225  if (!CreateEncryptor(encryption_key))
226  return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
227  }
228  check_new_crypto_period_ = false;
229  }
230 
231  if (remaining_clear_lead_ > 0)
232  return Status::OK;
233 
234  std::unique_ptr<DecryptConfig> decrypt_config(new DecryptConfig(
235  encryption_config_->key_id, encryptor_->iv(),
236  std::vector<SubsampleEntry>(), encryption_options_.protection_scheme,
237  crypt_byte_block_, skip_byte_block_));
238  bool result = true;
239  if (vpx_parser_) {
240  result = EncryptVpxFrame(vpx_frames, sample, decrypt_config.get());
241  if (result) {
242  DCHECK_EQ(decrypt_config->GetTotalSizeOfSubsamples(),
243  sample->data_size());
244  }
245  } else if (header_parser_) {
246  result = EncryptNalFrame(sample, decrypt_config.get());
247  if (result) {
248  DCHECK_EQ(decrypt_config->GetTotalSizeOfSubsamples(),
249  sample->data_size());
250  }
251  } else {
252  if (sample->data_size() > leading_clear_bytes_size_) {
253  EncryptBytes(sample->writable_data() + leading_clear_bytes_size_,
254  sample->data_size() - leading_clear_bytes_size_);
255  }
256  }
257  if (!result)
258  return Status(error::ENCRYPTION_FAILURE, "Failed to encrypt samples.");
259  sample->set_is_encrypted(true);
260  sample->set_decrypt_config(std::move(decrypt_config));
261  encryptor_->UpdateIv();
262  return Status::OK;
263 }
264 
265 Status EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
266  switch (encryption_options_.protection_scheme) {
267  case kAppleSampleAesProtectionScheme: {
268  const size_t kH264LeadingClearBytesSize = 32u;
269  const size_t kSmallNalUnitSize = 32u + 16u;
270  const size_t kAudioLeadingClearBytesSize = 16u;
271  switch (codec_) {
272  case kCodecH264:
273  // Apple Sample AES uses 1:9 pattern for video.
274  crypt_byte_block_ = 1u;
275  skip_byte_block_ = 9u;
276  leading_clear_bytes_size_ = kH264LeadingClearBytesSize;
277  min_protected_data_size_ = kSmallNalUnitSize + 1u;
278  break;
279  case kCodecAAC:
280  FALLTHROUGH_INTENDED;
281  case kCodecAC3:
282  // Audio is whole sample encrypted. We could not use a
283  // crypto_byte_block_ of 1 here as if there is one crypto block
284  // remaining, it need not be encrypted for video but it needs to be
285  // encrypted for audio.
286  crypt_byte_block_ = 0u;
287  skip_byte_block_ = 0u;
288  leading_clear_bytes_size_ = kAudioLeadingClearBytesSize;
289  min_protected_data_size_ = leading_clear_bytes_size_ + 1u;
290  break;
291  default:
292  return Status(error::ENCRYPTION_FAILURE,
293  "Only AAC/AC3 and H264 are supported in Sample AES.");
294  }
295  break;
296  }
297  case FOURCC_cbcs:
298  FALLTHROUGH_INTENDED;
299  case FOURCC_cens:
300  if (stream_type == kStreamVideo) {
301  // Use 1:9 pattern for video.
302  crypt_byte_block_ = 1u;
303  skip_byte_block_ = 9u;
304  } else {
305  // Tracks other than video are protected using whole-block full-sample
306  // encryption, which is essentially a pattern of 1:0. Note that this may
307  // not be the same as the non-pattern based encryption counterparts,
308  // e.g. in 'cens' for full sample encryption, the whole sample is
309  // encrypted up to the last 16-byte boundary, see 23001-7:2016(E) 9.7;
310  // while in 'cenc' for full sample encryption, the last partial 16-byte
311  // block is also encrypted, see 23001-7:2016(E) 9.4.2. Another
312  // difference is the use of constant iv.
313  crypt_byte_block_ = 1u;
314  skip_byte_block_ = 0u;
315  }
316  break;
317  default:
318  // Not using pattern encryption.
319  crypt_byte_block_ = 0u;
320  skip_byte_block_ = 0u;
321  }
322  return Status::OK;
323 }
324 
325 bool EncryptionHandler::CreateEncryptor(const EncryptionKey& encryption_key) {
326  std::unique_ptr<AesCryptor> encryptor;
327  switch (encryption_options_.protection_scheme) {
328  case FOURCC_cenc:
329  encryptor.reset(new AesCtrEncryptor);
330  break;
331  case FOURCC_cbc1:
332  encryptor.reset(new AesCbcEncryptor(kNoPadding));
333  break;
334  case FOURCC_cens:
335  encryptor.reset(new AesPatternCryptor(
336  crypt_byte_block_, skip_byte_block_,
338  AesCryptor::kDontUseConstantIv,
339  std::unique_ptr<AesCryptor>(new AesCtrEncryptor())));
340  break;
341  case FOURCC_cbcs:
342  encryptor.reset(new AesPatternCryptor(
343  crypt_byte_block_, skip_byte_block_,
345  AesCryptor::kUseConstantIv,
346  std::unique_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
347  break;
348  case kAppleSampleAesProtectionScheme:
349  if (crypt_byte_block_ == 0 && skip_byte_block_ == 0) {
350  encryptor.reset(
351  new AesCbcEncryptor(kNoPadding, AesCryptor::kUseConstantIv));
352  } else {
353  encryptor.reset(new AesPatternCryptor(
354  crypt_byte_block_, skip_byte_block_,
356  AesCryptor::kUseConstantIv,
357  std::unique_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
358  }
359  break;
360  default:
361  LOG(ERROR) << "Unsupported protection scheme.";
362  return false;
363  }
364 
365  std::vector<uint8_t> iv = encryption_key.iv;
366  if (iv.empty()) {
367  if (!AesCryptor::GenerateRandomIv(encryption_options_.protection_scheme,
368  &iv)) {
369  LOG(ERROR) << "Failed to generate random iv.";
370  return false;
371  }
372  }
373  const bool initialized =
374  encryptor->InitializeWithIv(encryption_key.key, iv);
375  encryptor_ = std::move(encryptor);
376 
377  encryption_config_.reset(new EncryptionConfig);
378  encryption_config_->protection_scheme = encryption_options_.protection_scheme;
379  encryption_config_->crypt_byte_block = crypt_byte_block_;
380  encryption_config_->skip_byte_block = skip_byte_block_;
381  if (encryptor_->use_constant_iv()) {
382  encryption_config_->per_sample_iv_size = 0;
383  encryption_config_->constant_iv = iv;
384  } else {
385  encryption_config_->per_sample_iv_size = static_cast<uint8_t>(iv.size());
386  }
387  encryption_config_->key_id = encryption_key.key_id;
388  encryption_config_->key_system_info = encryption_key.key_system_info;
389  return initialized;
390 }
391 
392 bool EncryptionHandler::EncryptVpxFrame(
393  const std::vector<VPxFrameInfo>& vpx_frames,
394  MediaSample* sample,
395  DecryptConfig* decrypt_config) {
396  uint8_t* data = sample->writable_data();
397  for (const VPxFrameInfo& frame : vpx_frames) {
398  uint16_t clear_bytes =
399  static_cast<uint16_t>(frame.uncompressed_header_size);
400  uint32_t cipher_bytes = static_cast<uint32_t>(
401  frame.frame_size - frame.uncompressed_header_size);
402 
403  // "VP Codec ISO Media File Format Binding" document requires that the
404  // encrypted bytes of each frame within the superframe must be block
405  // aligned so that the counter state can be computed for each frame
406  // within the superframe.
407  // ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
408  // The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
409  // avoid partial blocks in Subsamples.
410  // For consistency, apply block alignment to all frames.
411  const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
412  clear_bytes += misalign_bytes;
413  cipher_bytes -= misalign_bytes;
414 
415  decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
416  if (cipher_bytes > 0)
417  EncryptBytes(data + clear_bytes, cipher_bytes);
418  data += frame.frame_size;
419  }
420  // Add subsample for the superframe index if exists.
421  const bool is_superframe = vpx_frames.size() > 1;
422  if (is_superframe) {
423  size_t index_size = sample->data() + sample->data_size() - data;
424  DCHECK_LE(index_size, 2 + vpx_frames.size() * 4);
425  DCHECK_GE(index_size, 2 + vpx_frames.size() * 1);
426  uint16_t clear_bytes = static_cast<uint16_t>(index_size);
427  uint32_t cipher_bytes = 0;
428  decrypt_config->AddSubsample(clear_bytes, cipher_bytes);
429  }
430  return true;
431 }
432 
433 bool EncryptionHandler::EncryptNalFrame(MediaSample* sample,
434  DecryptConfig* decrypt_config) {
435  DCHECK_NE(nalu_length_size_, 0u);
436  DCHECK(header_parser_);
437  const Nalu::CodecType nalu_type =
438  (codec_ == kCodecH265) ? Nalu::kH265 : Nalu::kH264;
439  NaluReader reader(nalu_type, nalu_length_size_, sample->writable_data(),
440  sample->data_size());
441 
442  // Store the current length of clear data. This is used to squash
443  // multiple unencrypted NAL units into fewer subsample entries.
444  uint64_t accumulated_clear_bytes = 0;
445 
446  Nalu nalu;
447  NaluReader::Result result;
448  while ((result = reader.Advance(&nalu)) == NaluReader::kOk) {
449  const uint64_t nalu_total_size = nalu.header_size() + nalu.payload_size();
450  if (nalu.is_video_slice() && nalu_total_size >= min_protected_data_size_) {
451  uint64_t current_clear_bytes = leading_clear_bytes_size_;
452  if (current_clear_bytes == 0) {
453  // For video-slice NAL units, encrypt the video slice. This skips
454  // the frame header.
455  const int64_t video_slice_header_size =
456  header_parser_->GetHeaderSize(nalu);
457  if (video_slice_header_size < 0) {
458  LOG(ERROR) << "Failed to read slice header.";
459  return false;
460  }
461  current_clear_bytes = nalu.header_size() + video_slice_header_size;
462  }
463  uint64_t cipher_bytes = nalu_total_size - current_clear_bytes;
464 
465  // ISO/IEC 23001-7:2016 10.2 'cbc1' 10.3 'cens'
466  // The BytesOfProtectedData size SHALL be a multiple of 16 bytes to
467  // avoid partial blocks in Subsamples.
468  // CMAF requires 'cenc' scheme BytesOfProtectedData SHALL be a multiple
469  // of 16 bytes; while 'cbcs' scheme BytesOfProtectedData SHALL start on
470  // the first byte of video data following the slice header.
471  if (encryption_options_.protection_scheme == FOURCC_cbc1 ||
472  encryption_options_.protection_scheme == FOURCC_cens ||
473  encryption_options_.protection_scheme == FOURCC_cenc) {
474  const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
475  current_clear_bytes += misalign_bytes;
476  cipher_bytes -= misalign_bytes;
477  }
478 
479  const uint8_t* nalu_data = nalu.data() + current_clear_bytes;
480  EncryptBytes(const_cast<uint8_t*>(nalu_data), cipher_bytes);
481 
482  AddSubsample(
483  accumulated_clear_bytes + nalu_length_size_ + current_clear_bytes,
484  cipher_bytes, decrypt_config);
485  accumulated_clear_bytes = 0;
486  } else {
487  // For non-video-slice or small NAL units, don't encrypt.
488  accumulated_clear_bytes += nalu_length_size_ + nalu_total_size;
489  }
490  }
491  if (result != NaluReader::kEOStream) {
492  LOG(ERROR) << "Failed to parse NAL units.";
493  return false;
494  }
495  AddSubsample(accumulated_clear_bytes, 0, decrypt_config);
496  return true;
497 }
498 
499 void EncryptionHandler::EncryptBytes(uint8_t* data, size_t size) {
500  DCHECK(encryptor_);
501  CHECK(encryptor_->Crypt(data, size, data));
502 }
503 
504 void EncryptionHandler::InjectVpxParserForTesting(
505  std::unique_ptr<VPxParser> vpx_parser) {
506  vpx_parser_ = std::move(vpx_parser);
507 }
508 
509 void EncryptionHandler::InjectVideoSliceHeaderParserForTesting(
510  std::unique_ptr<VideoSliceHeaderParser> header_parser) {
511  header_parser_ = std::move(header_parser);
512 }
513 
514 } // namespace media
515 } // namespace shaka
Abstract class holds stream information.
Definition: stream_info.h:57
Status Dispatch(std::unique_ptr< StreamData > stream_data)
virtual Status GetCryptoPeriodKey(uint32_t crypto_period_index, TrackType track_type, EncryptionKey *key)=0
virtual Status GetKey(TrackType track_type, EncryptionKey *key)=0
Status Process(std::unique_ptr< StreamData > stream_data) override
static bool GenerateRandomIv(FourCC protection_scheme, std::vector< uint8_t > *iv)
Definition: aes_cryptor.cc:107
double clear_lead_in_seconds
Clear lead duration in seconds.
FourCC protection_scheme
The protection scheme: 'cenc', 'cens', 'cbc1', 'cbcs'.