OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/formats/webm/webm_crypto_helpers.h" | 5 #include "media/formats/webm/webm_crypto_helpers.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/sys_byteorder.h" | 10 #include "base/sys_byteorder.h" |
11 #include "media/base/decrypt_config.h" | 11 #include "media/base/decrypt_config.h" |
12 #include "media/formats/webm/webm_constants.h" | 12 #include "media/formats/webm/webm_constants.h" |
13 | 13 |
14 namespace media { | 14 namespace media { |
15 namespace { | 15 namespace { |
16 | 16 |
17 // Generates a 16 byte CTR counter block. The CTR counter block format is a | 17 // Generates a 16 byte CTR counter block. The CTR counter block format is a |
18 // CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV. | 18 // CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV. |
19 // |iv_size| is the size of |iv| in btyes. Returns a string of | 19 // |iv_size| is the size of |iv| in btyes. Returns a string of |
20 // kDecryptionKeySize bytes. | 20 // kDecryptionKeySize bytes. |
21 std::string GenerateWebMCounterBlock(const uint8_t* iv, int iv_size) { | 21 std::string GenerateWebMCounterBlock(const uint8_t* iv, int iv_size) { |
22 std::string counter_block(reinterpret_cast<const char*>(iv), iv_size); | 22 std::string counter_block(reinterpret_cast<const char*>(iv), iv_size); |
23 counter_block.append(DecryptConfig::kDecryptionKeySize - iv_size, 0); | 23 counter_block.append(DecryptConfig::kDecryptionKeySize - iv_size, 0); |
24 return counter_block; | 24 return counter_block; |
25 } | 25 } |
26 | 26 |
27 uint32_t ReadInteger(const uint8_t* buf, int size) { | |
tinskip1
2016/08/17 19:28:25
Does not exists elsewhere?
inline?
kqyang
2016/08/18 19:39:53
There is a BufferReader in src/media/formats/mp4/b
| |
28 // Read in the big-endian integer. | |
29 uint32_t value = 0; | |
30 for (int i = 0; i < size; ++i) | |
31 value = (value << 8) | buf[i]; | |
32 return value; | |
33 } | |
34 | |
35 bool ExtractSubsamples(const uint8_t* buf, | |
36 size_t frame_data_size, | |
37 size_t num_partitions, | |
38 std::vector<SubsampleEntry>* subsample_entries) { | |
39 subsample_entries->clear(); | |
40 uint32_t clear_bytes = 0; | |
41 // Partition is the wall between alternating sections. Partition offsets are | |
42 // relative to the start of the actual frame data. | |
43 // Size of clear/cipher sections can be calculated from the difference between | |
44 // adjacent partition offsets. | |
45 // Here is an example with 4 partitions (5 sections): | |
46 // "clear |1 cipher |2 clear |3 cipher |4 clear" | |
47 // With the first and the last implicit partition included: | |
48 // "|0 clear |1 cipher |2 clear |3 cipher |4 clear |5" | |
49 // where partition_offset_0 = 0, partition_offset_5 = frame_data_size | |
50 // There are three subsamples in the above example: | |
51 // Subsample0.clear_bytes = partition_offset_1 - partition_offset_0 | |
52 // Subsample0.cipher_bytes = partition_offset_2 - partition_offset_1 | |
53 // ... | |
54 // Subsample2.clear_bytes = partition_offset_5 - partition_offset_4 | |
55 // Subsample2.cipher_bytes = 0 | |
56 uint32_t partition_offset = 0; | |
57 for (size_t i = 0, offset = 0; i <= num_partitions; ++i) { | |
58 const uint32_t prev_partition_offset = partition_offset; | |
59 partition_offset = | |
60 (i == num_partitions) | |
61 ? frame_data_size | |
62 : ReadInteger(buf + offset, kWebMEncryptedFramePartitionOffsetSize); | |
63 offset += kWebMEncryptedFramePartitionOffsetSize; | |
64 if (partition_offset < prev_partition_offset) { | |
65 DVLOG(1) << "Partition should not be decreasing " << prev_partition_offset | |
66 << " " << partition_offset; | |
67 return false; | |
68 } | |
69 | |
70 uint32_t cipher_bytes = 0; | |
71 bool new_subsample_entry = false; | |
72 // Alternating clear and cipher sections. | |
73 if ((i % 2) == 0) { | |
74 clear_bytes = partition_offset - prev_partition_offset; | |
75 // Generate a new subsample when finishing reading partition offsets. | |
76 new_subsample_entry = i == num_partitions; | |
77 } else { | |
78 cipher_bytes = partition_offset - prev_partition_offset; | |
79 // Generate a new subsample after seeing a cipher section. | |
80 new_subsample_entry = true; | |
81 } | |
82 | |
83 if (new_subsample_entry) { | |
84 if (clear_bytes == 0 && cipher_bytes == 0) { | |
85 DVLOG(1) << "Not expecting >2 partitions with the same offsets."; | |
86 return false; | |
87 } | |
88 subsample_entries->push_back(SubsampleEntry(clear_bytes, cipher_bytes)); | |
89 } | |
90 } | |
91 return true; | |
92 } | |
93 | |
27 } // namespace anonymous | 94 } // namespace anonymous |
28 | 95 |
29 bool WebMCreateDecryptConfig(const uint8_t* data, | 96 bool WebMCreateDecryptConfig(const uint8_t* data, |
30 int data_size, | 97 int data_size, |
31 const uint8_t* key_id, | 98 const uint8_t* key_id, |
32 int key_id_size, | 99 int key_id_size, |
33 std::unique_ptr<DecryptConfig>* decrypt_config, | 100 std::unique_ptr<DecryptConfig>* decrypt_config, |
34 int* data_offset) { | 101 int* data_offset) { |
35 if (data_size < kWebMSignalByteSize) { | 102 if (data_size < kWebMSignalByteSize) { |
36 DVLOG(1) << "Got a block from an encrypted stream with no data."; | 103 DVLOG(1) << "Got a block from an encrypted stream with no data."; |
37 return false; | 104 return false; |
38 } | 105 } |
39 | 106 |
40 uint8_t signal_byte = data[0]; | 107 const uint8_t signal_byte = data[0]; |
41 int frame_offset = sizeof(signal_byte); | 108 int frame_offset = sizeof(signal_byte); |
42 | 109 |
43 // Setting the DecryptConfig object of the buffer while leaving the | 110 // Setting the DecryptConfig object of the buffer while leaving the |
44 // initialization vector empty will tell the decryptor that the frame is | 111 // initialization vector empty will tell the decryptor that the frame is |
45 // unencrypted. | 112 // unencrypted. |
46 std::string counter_block; | 113 std::string counter_block; |
114 std::vector<SubsampleEntry> subsample_entries; | |
47 | 115 |
48 if (signal_byte & kWebMFlagEncryptedFrame) { | 116 if (signal_byte & kWebMFlagEncryptedFrame) { |
49 if (data_size < kWebMSignalByteSize + kWebMIvSize) { | 117 if (data_size < kWebMSignalByteSize + kWebMIvSize) { |
50 DVLOG(1) << "Got an encrypted block with not enough data " << data_size; | 118 DVLOG(1) << "Got an encrypted block with not enough data " << data_size; |
51 return false; | 119 return false; |
52 } | 120 } |
53 counter_block = GenerateWebMCounterBlock(data + frame_offset, kWebMIvSize); | 121 counter_block = GenerateWebMCounterBlock(data + frame_offset, kWebMIvSize); |
54 frame_offset += kWebMIvSize; | 122 frame_offset += kWebMIvSize; |
123 | |
124 if (signal_byte & kWebMFlagEncryptedFramePartitioned) { | |
125 if (data_size < frame_offset + kWebMEncryptedFrameNumPartitionsSize) { | |
126 DVLOG(1) << "Got a partitioned encrypted block with not enough data " | |
127 << data_size; | |
128 return false; | |
129 } | |
130 | |
131 const size_t num_partitions = data[frame_offset]; | |
132 if (num_partitions == 0) { | |
133 DVLOG(1) << "Got a partitioned encrypted block with 0 partitions."; | |
134 return false; | |
135 } | |
136 frame_offset += kWebMEncryptedFrameNumPartitionsSize; | |
137 const uint8_t* partition_data_start = data + frame_offset; | |
138 frame_offset += kWebMEncryptedFramePartitionOffsetSize * num_partitions; | |
139 if (data_size <= frame_offset) { | |
140 DVLOG(1) << "Got a partitioned encrypted block with " << num_partitions | |
141 << " partitions but not enough data " << data_size; | |
142 return false; | |
143 } | |
144 const size_t frame_data_size = data_size - frame_offset; | |
145 if (!ExtractSubsamples(partition_data_start, frame_data_size, | |
146 num_partitions, &subsample_entries)) { | |
147 return false; | |
148 } | |
149 } | |
55 } | 150 } |
56 | 151 |
57 decrypt_config->reset(new DecryptConfig( | 152 decrypt_config->reset(new DecryptConfig( |
58 std::string(reinterpret_cast<const char*>(key_id), key_id_size), | 153 std::string(reinterpret_cast<const char*>(key_id), key_id_size), |
59 counter_block, | 154 counter_block, subsample_entries)); |
60 std::vector<SubsampleEntry>())); | |
61 *data_offset = frame_offset; | 155 *data_offset = frame_offset; |
62 | 156 |
63 return true; | 157 return true; |
64 } | 158 } |
65 | 159 |
66 } // namespace media | 160 } // namespace media |
OLD | NEW |