Chromium Code Reviews| 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 |