Shaka Packager SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
webm_crypto_helpers.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "packager/media/formats/webm/webm_crypto_helpers.h"
6 
7 #include "packager/base/logging.h"
8 #include "packager/base/sys_byteorder.h"
9 #include "packager/media/base/buffer_reader.h"
10 #include "packager/media/formats/webm/webm_constants.h"
11 
12 namespace shaka {
13 namespace media {
14 namespace {
15 
16 // Generates a 16 byte CTR counter block. The CTR counter block format is a
17 // CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV.
18 // |iv_size| is the size of |iv| in btyes. Returns a string of
19 // kDecryptionKeySize bytes.
20 std::vector<uint8_t> GenerateWebMCounterBlock(const uint8_t* iv, int iv_size) {
21  std::vector<uint8_t> counter_block(iv, iv + iv_size);
22  counter_block.insert(counter_block.end(),
24  return counter_block;
25 }
26 
27 } // namespace anonymous
28 
29 // TODO(tinskip): Add unit test for this function.
30 bool WebMCreateDecryptConfig(const uint8_t* data,
31  int data_size,
32  const uint8_t* key_id,
33  size_t key_id_size,
34  std::unique_ptr<DecryptConfig>* decrypt_config,
35  int* data_offset) {
36  int header_size = kWebMSignalByteSize;
37  if (data_size < header_size) {
38  DVLOG(1) << "Empty WebM sample.";
39  return false;
40  }
41  uint8_t signal_byte = data[0];
42 
43  if (signal_byte & kWebMEncryptedSignal) {
44  // Encrypted sample.
45  header_size += kWebMIvSize;
46  if (data_size < header_size) {
47  DVLOG(1) << "Encrypted WebM sample too small to hold IV: " << data_size;
48  return false;
49  }
50  std::vector<SubsampleEntry> subsamples;
51  if (signal_byte & kWebMPartitionedSignal) {
52  // Encrypted sample with subsamples / partitioning.
53  header_size += kWebMNumPartitionsSize;
54  if (data_size < header_size) {
55  DVLOG(1)
56  << "Encrypted WebM sample too small to hold number of partitions: "
57  << data_size;
58  return false;
59  }
60  uint8_t num_partitions = data[kWebMSignalByteSize + kWebMIvSize];
61  BufferReader offsets_buffer(data + header_size, data_size - header_size);
62  header_size += num_partitions * kWebMPartitionOffsetSize;
63  uint32_t subsample_offset = 0;
64  bool encrypted_subsample = false;
65  uint16_t clear_size = 0;
66  uint32_t encrypted_size = 0;
67  for (uint8_t partition_idx = 0; partition_idx < num_partitions;
68  ++partition_idx) {
69  uint32_t partition_offset;
70  if (!offsets_buffer.Read4(&partition_offset)) {
71  DVLOG(1)
72  << "Encrypted WebM sample too small to hold partition offsets: "
73  << data_size;
74  return false;
75  }
76  if (partition_offset < subsample_offset) {
77  DVLOG(1) << "Partition offsets out of order.";
78  return false;
79  }
80  if (encrypted_subsample) {
81  encrypted_size = partition_offset - subsample_offset;
82  subsamples.push_back(SubsampleEntry(clear_size, encrypted_size));
83  } else {
84  clear_size = partition_offset - subsample_offset;
85  if (partition_idx == (num_partitions - 1)) {
86  encrypted_size = data_size - header_size - subsample_offset - clear_size;
87  subsamples.push_back(SubsampleEntry(clear_size, encrypted_size));
88  }
89  }
90  subsample_offset = partition_offset;
91  encrypted_subsample = !encrypted_subsample;
92  }
93  if (!(num_partitions % 2)) {
94  // Even number of partitions. Add one last all-clear subsample.
95  clear_size = data_size - header_size - subsample_offset;
96  encrypted_size = 0;
97  subsamples.push_back(SubsampleEntry(clear_size, encrypted_size));
98  }
99  }
100  decrypt_config->reset(new DecryptConfig(
101  std::vector<uint8_t>(key_id, key_id + key_id_size),
102  GenerateWebMCounterBlock(data + kWebMSignalByteSize, kWebMIvSize),
103  subsamples));
104  } else {
105  // Clear sample.
106  decrypt_config->reset();
107  }
108 
109  *data_offset = header_size;
110  return true;
111 }
112 
113 } // namespace media
114 } // namespace shaka
static const size_t kDecryptionKeySize
Keys are always 128 bits.