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