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) { | |
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 partition_offset = 0; | |
41 uint32_t clear_bytes = 0; | |
42 // N partitions means N+1 sections (alternating between clear and cipher | |
43 // sections). | |
44 for (size_t i = 0, offset = 0; i <= num_partitions; ++i) { | |
45 const uint32_t prev_partition_offset = partition_offset; | |
46 partition_offset = | |
47 (i == num_partitions) | |
48 ? frame_data_size | |
chcunningham
2016/07/29 21:32:41
I don't follow this bit. Is the offset for the las
chcunningham
2016/07/29 22:26:22
We chatted, and this works, I was just confused ab
kqyang
2016/08/02 00:07:23
Done.
| |
49 : ReadInteger(buf + offset, kWebMEncryptedFramePartitionSize); | |
50 offset += kWebMEncryptedFramePartitionSize; | |
51 if (partition_offset < prev_partition_offset) { | |
52 DVLOG(1) << "Partition should not be decreasing " << prev_partition_offset | |
53 << " " << partition_offset; | |
54 return false; | |
55 } | |
56 | |
57 uint32_t encrypted_bytes = 0; | |
58 bool new_subsample_entry = false; | |
59 // Alternating clear and cipher sections. | |
60 if ((i % 2) == 0) { | |
61 clear_bytes = partition_offset - prev_partition_offset; | |
62 // Generate a new subsample when finishing reading partitions. | |
63 new_subsample_entry = i == num_partitions; | |
64 } else { | |
65 encrypted_bytes = partition_offset - prev_partition_offset; | |
66 // Generate a new subsample after seeing a cipher section. | |
67 new_subsample_entry = true; | |
68 } | |
69 | |
70 if (new_subsample_entry) { | |
71 if (clear_bytes == 0 && encrypted_bytes == 0) { | |
72 DVLOG(1) << "Not expecting >2 partitions with the same offsets."; | |
73 return false; | |
74 } | |
75 subsample_entries->push_back( | |
76 SubsampleEntry(clear_bytes, encrypted_bytes)); | |
77 } | |
78 } | |
79 return true; | |
80 } | |
81 | |
27 } // namespace anonymous | 82 } // namespace anonymous |
28 | 83 |
29 bool WebMCreateDecryptConfig(const uint8_t* data, | 84 bool WebMCreateDecryptConfig(const uint8_t* data, |
30 int data_size, | 85 int data_size, |
31 const uint8_t* key_id, | 86 const uint8_t* key_id, |
32 int key_id_size, | 87 int key_id_size, |
33 std::unique_ptr<DecryptConfig>* decrypt_config, | 88 std::unique_ptr<DecryptConfig>* decrypt_config, |
34 int* data_offset) { | 89 int* data_offset) { |
35 if (data_size < kWebMSignalByteSize) { | 90 if (data_size < kWebMSignalByteSize) { |
36 DVLOG(1) << "Got a block from an encrypted stream with no data."; | 91 DVLOG(1) << "Got a block from an encrypted stream with no data."; |
37 return false; | 92 return false; |
38 } | 93 } |
39 | 94 |
40 uint8_t signal_byte = data[0]; | 95 const uint8_t signal_byte = data[0]; |
41 int frame_offset = sizeof(signal_byte); | 96 int frame_offset = sizeof(signal_byte); |
42 | 97 |
43 // Setting the DecryptConfig object of the buffer while leaving the | 98 // Setting the DecryptConfig object of the buffer while leaving the |
44 // initialization vector empty will tell the decryptor that the frame is | 99 // initialization vector empty will tell the decryptor that the frame is |
45 // unencrypted. | 100 // unencrypted. |
46 std::string counter_block; | 101 std::string counter_block; |
102 std::vector<SubsampleEntry> subsample_entries; | |
47 | 103 |
48 if (signal_byte & kWebMFlagEncryptedFrame) { | 104 if (signal_byte & kWebMFlagEncryptedFrame) { |
49 if (data_size < kWebMSignalByteSize + kWebMIvSize) { | 105 if (data_size < kWebMSignalByteSize + kWebMIvSize) { |
50 DVLOG(1) << "Got an encrypted block with not enough data " << data_size; | 106 DVLOG(1) << "Got an encrypted block with not enough data " << data_size; |
51 return false; | 107 return false; |
52 } | 108 } |
53 counter_block = GenerateWebMCounterBlock(data + frame_offset, kWebMIvSize); | 109 counter_block = GenerateWebMCounterBlock(data + frame_offset, kWebMIvSize); |
54 frame_offset += kWebMIvSize; | 110 frame_offset += kWebMIvSize; |
111 | |
112 if (signal_byte & kWebMFlagEncryptedFramePartitioned) { | |
113 if (data_size < frame_offset + kWebMEncryptedFrameNumPartitionSize) { | |
114 DVLOG(1) << "Got a partitioned encrypted block with not enough data " | |
115 << data_size; | |
116 return false; | |
117 } | |
118 | |
119 const size_t num_partitions = data[frame_offset]; | |
120 if (num_partitions == 0) { | |
121 DVLOG(1) << "Got a partitioned encrypted block with 0 partitions."; | |
122 return false; | |
123 } | |
124 frame_offset += kWebMEncryptedFrameNumPartitionSize; | |
125 const uint8_t* partition_data_start = data + frame_offset; | |
126 frame_offset += kWebMEncryptedFramePartitionSize * num_partitions; | |
chcunningham
2016/07/29 21:32:41
kWebMEncryptedFramePartitionSize ... might be conf
kqyang
2016/08/02 00:07:23
Renamed to kWebMEncryptedFramePartitionOffsetSize
| |
127 if (data_size <= frame_offset) { | |
128 DVLOG(1) << "Got a partitioned encrypted block with " << num_partitions | |
129 << " partitions but not enough data " << data_size; | |
130 return false; | |
131 } | |
132 const size_t frame_data_size = data_size - frame_offset; | |
133 if (!ExtractSubsamples(partition_data_start, frame_data_size, | |
134 num_partitions, &subsample_entries)) { | |
135 return false; | |
136 } | |
137 } | |
55 } | 138 } |
56 | 139 |
57 decrypt_config->reset(new DecryptConfig( | 140 decrypt_config->reset(new DecryptConfig( |
58 std::string(reinterpret_cast<const char*>(key_id), key_id_size), | 141 std::string(reinterpret_cast<const char*>(key_id), key_id_size), |
59 counter_block, | 142 counter_block, subsample_entries)); |
60 std::vector<SubsampleEntry>())); | |
61 *data_offset = frame_offset; | 143 *data_offset = frame_offset; |
62 | 144 |
63 return true; | 145 return true; |
64 } | 146 } |
65 | 147 |
66 } // namespace media | 148 } // namespace media |
OLD | NEW |