Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / media / cdm / cenc_utils.cc
bloba59c19ce9bc93bb6f62d2b6f7aca13a4a6466c5a
1 // Copyright 2015 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.
5 #include "media/cdm/cenc_utils.h"
7 #include "media/base/bit_reader.h"
9 namespace media {
11 // The initialization data for encrypted media files using the ISO Common
12 // Encryption ('cenc') protection scheme may contain one or more protection
13 // system specific header ('pssh') boxes.
14 // ref: https://w3c.github.io/encrypted-media/cenc-format.html
16 // The format of a 'pssh' box is as follows:
17 // unsigned int(32) size;
18 // unsigned int(32) type = "pssh";
19 // if (size==1) {
20 // unsigned int(64) largesize;
21 // } else if (size==0) {
22 // -- box extends to end of file
23 // }
24 // unsigned int(8) version;
25 // bit(24) flags;
26 // unsigned int(8)[16] SystemID;
27 // if (version > 0)
28 // {
29 // unsigned int(32) KID_count;
30 // {
31 // unsigned int(8)[16] KID;
32 // } [KID_count]
33 // }
34 // unsigned int(32) DataSize;
35 // unsigned int(8)[DataSize] Data;
37 // Minimum size of a 'pssh' box includes all the required fields (size, type,
38 // version, flags, SystemID, DataSize).
39 const int kMinimumBoxSizeInBytes = 32;
41 // SystemID for the Common System.
42 // https://w3c.github.io/encrypted-media/cenc-format.html#common-system
43 const uint8 kCommonSystemId[] = { 0x10, 0x77, 0xef, 0xec,
44 0xc0, 0xb2, 0x4d, 0x02,
45 0xac, 0xe3, 0x3c, 0x1e,
46 0x52, 0xe2, 0xfb, 0x4b };
48 #define RCHECK(x) \
49 do { \
50 if (!(x)) \
51 return false; \
52 } while (0)
54 // Helper function to read up to 32 bits from a bit stream.
55 static uint32 ReadBits(BitReader* reader, int num_bits) {
56 DCHECK_GE(reader->bits_available(), num_bits);
57 DCHECK((num_bits > 0) && (num_bits <= 32));
58 uint32 value;
59 reader->ReadBits(num_bits, &value);
60 return value;
63 // Checks whether the next 16 bytes matches the Common SystemID.
64 // Assumes |reader| has enough data.
65 static bool IsCommonSystemID(BitReader* reader) {
66 for (uint32 i = 0; i < arraysize(kCommonSystemId); ++i) {
67 if (ReadBits(reader, 8) != kCommonSystemId[i])
68 return false;
70 return true;
73 // Checks that |reader| contains a valid 'ppsh' box header. |reader| is updated
74 // to point to the content immediately following the box header. Returns true
75 // if the header looks valid and |reader| contains enough data for the size of
76 // header. |size| is updated as the computed size of the box header. Otherwise
77 // false is returned.
78 static bool ValidBoxHeader(BitReader* reader, uint32* size) {
79 // Enough data for a miniumum size 'pssh' box?
80 uint32 available_bytes = reader->bits_available() / 8;
81 RCHECK(available_bytes >= kMinimumBoxSizeInBytes);
83 *size = ReadBits(reader, 32);
85 // Must be a 'pssh' box or else fail.
86 RCHECK(ReadBits(reader, 8) == 'p');
87 RCHECK(ReadBits(reader, 8) == 's');
88 RCHECK(ReadBits(reader, 8) == 's');
89 RCHECK(ReadBits(reader, 8) == 'h');
91 if (*size == 1) {
92 // If largesize > 2**32 it is too big.
93 RCHECK(ReadBits(reader, 32) == 0);
94 *size = ReadBits(reader, 32);
95 } else if (*size == 0) {
96 *size = available_bytes;
99 // Check that the buffer contains at least size bytes.
100 return available_bytes >= *size;
103 bool ValidatePsshInput(const uint8* input, size_t input_length) {
104 size_t offset = 0;
105 while (offset < input_length) {
106 // Create a BitReader over the remaining part of the buffer.
107 BitReader reader(input + offset, input_length - offset);
108 uint32 size;
109 RCHECK(ValidBoxHeader(&reader, &size));
111 // Update offset to point at the next 'pssh' box (may not be one).
112 offset += size;
115 // Only valid if this contains 0 or more 'pssh' boxes.
116 return offset == input_length;
119 bool GetKeyIdsForCommonSystemId(const uint8* input,
120 int input_length,
121 std::vector<std::vector<uint8>>* key_ids) {
122 int offset = 0;
123 std::vector<std::vector<uint8>> result;
125 while (offset < input_length) {
126 // Create a BitReader over the remaining part of the buffer.
127 BitReader reader(input + offset, input_length - offset);
128 uint32 size;
129 RCHECK(ValidBoxHeader(&reader, &size));
131 // Update offset to point at the next 'pssh' box (may not be one).
132 offset += size;
134 // Check the version, as KIDs only available if version > 0.
135 uint8 version = ReadBits(&reader, 8);
136 if (version == 0)
137 continue;
139 // flags must be 0. If not, assume incorrect 'pssh' box and move to the
140 // next one.
141 if (ReadBits(&reader, 24) != 0)
142 continue;
144 // Validate SystemID
145 RCHECK(static_cast<uint32>(reader.bits_available()) >=
146 arraysize(kCommonSystemId) * 8);
147 if (!IsCommonSystemID(&reader))
148 continue; // Not Common System, so try the next pssh box.
150 // Since version > 0, next field is the KID_count.
151 RCHECK(static_cast<uint32>(reader.bits_available()) >= sizeof(uint32) * 8);
152 uint32 count = ReadBits(&reader, 32);
154 if (count == 0)
155 continue;
157 // Make sure there is enough data for all the KIDs specified, and then
158 // extract them.
159 RCHECK(static_cast<uint32>(reader.bits_available()) > count * 16 * 8);
160 while (count > 0) {
161 std::vector<uint8> key;
162 key.reserve(16);
163 for (int i = 0; i < 16; ++i) {
164 key.push_back(ReadBits(&reader, 8));
166 result.push_back(key);
167 --count;
170 // Don't bother checking DataSize and Data.
173 key_ids->swap(result);
175 // TODO(jrummell): This should return true only if there was at least one
176 // key ID present. However, numerous test files don't contain the 'pssh' box
177 // for Common Format, so no keys are found. http://crbug.com/460308
178 return true;
181 } // namespace media