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