Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: media/cdm/json_web_key.cc

Issue 798583003: Encrypted Media: Check "alg":"A128KW" in AesDecryptor. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix AesDecryptorTest. Created 5 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/cdm/aes_decryptor_unittest.cc ('k') | media/cdm/json_web_key_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/cdm/json_web_key.h" 5 #include "media/cdm/json_web_key.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
9 #include "base/json/json_string_value_serializer.h" 9 #include "base/json/json_string_value_serializer.h"
10 #include "base/json/string_escape.h" 10 #include "base/json/string_escape.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
14 #include "base/values.h" 14 #include "base/values.h"
15 15
16 namespace media { 16 namespace media {
17 17
18 const char kKeysTag[] = "keys"; 18 const char kKeysTag[] = "keys";
19 const char kKeyTypeTag[] = "kty"; 19 const char kKeyTypeTag[] = "kty";
20 const char kSymmetricKeyValue[] = "oct"; 20 const char kKeyTypeOct[] = "oct"; // Octet sequence.
21 const char kAlgTag[] = "alg";
22 const char kAlgA128KW[] = "A128KW"; // AES key wrap using a 128-bit key.
21 const char kKeyTag[] = "k"; 23 const char kKeyTag[] = "k";
22 const char kKeyIdTag[] = "kid"; 24 const char kKeyIdTag[] = "kid";
23 const char kKeyIdsTag[] = "kids"; 25 const char kKeyIdsTag[] = "kids";
24 const char kBase64Padding = '='; 26 const char kBase64Padding = '=';
25 const char kTypeTag[] = "type"; 27 const char kTypeTag[] = "type";
26 const char kPersistentType[] = "persistent"; 28 const char kPersistentType[] = "persistent";
27 const char kTemporaryType[] = "temporary"; 29 const char kTemporaryType[] = "temporary";
28 30
29 // Encodes |input| into a base64 string without padding. 31 // Encodes |input| into a base64 string without padding.
30 static std::string EncodeBase64(const uint8* input, int input_length) { 32 static std::string EncodeBase64(const uint8* input, int input_length) {
31 std::string encoded_text; 33 std::string encoded_text;
32 base::Base64Encode( 34 base::Base64Encode(
33 std::string(reinterpret_cast<const char*>(input), input_length), 35 std::string(reinterpret_cast<const char*>(input), input_length),
34 &encoded_text); 36 &encoded_text);
35 37
36 // Remove any padding characters added by Base64Encode(). 38 // Remove any padding characters added by Base64Encode().
37 size_t found = encoded_text.find_last_not_of(kBase64Padding); 39 size_t found = encoded_text.find_last_not_of(kBase64Padding);
38 if (found != std::string::npos) 40 if (found != std::string::npos)
39 encoded_text.erase(found + 1); 41 encoded_text.erase(found + 1);
40 42
41 return encoded_text; 43 return encoded_text;
42 } 44 }
43 45
44 // Decodes an unpadded base64 string. Returns empty string on error. 46 // Decodes an unpadded base64 string. Returns empty string on error.
45 static std::string DecodeBase64(const std::string& encoded_text) { 47 static std::string DecodeBase64(const std::string& encoded_text) {
46 // EME spec doesn't allow padding characters. 48 // EME spec doesn't allow padding characters.
47 if (encoded_text.find_first_of(kBase64Padding) != std::string::npos) 49 if (encoded_text.find_first_of(kBase64Padding) != std::string::npos) {
50 DVLOG(1) << "Padding characters not allowed: " << encoded_text;
48 return std::string(); 51 return std::string();
52 }
49 53
50 // Since base::Base64Decode() requires padding characters, add them so length 54 // Since base::Base64Decode() requires padding characters, add them so length
51 // of |encoded_text| is exactly a multiple of 4. 55 // of |encoded_text| is exactly a multiple of 4.
52 size_t num_last_grouping_chars = encoded_text.length() % 4; 56 size_t num_last_grouping_chars = encoded_text.length() % 4;
53 std::string modified_text = encoded_text; 57 std::string modified_text = encoded_text;
54 if (num_last_grouping_chars > 0) 58 if (num_last_grouping_chars > 0)
55 modified_text.append(4 - num_last_grouping_chars, kBase64Padding); 59 modified_text.append(4 - num_last_grouping_chars, kBase64Padding);
56 60
57 std::string decoded_text; 61 std::string decoded_text;
58 if (!base::Base64Decode(modified_text, &decoded_text)) 62 if (!base::Base64Decode(modified_text, &decoded_text)) {
63 DVLOG(1) << "Base64 decoding failed on: " << modified_text;
59 return std::string(); 64 return std::string();
65 }
60 66
61 return decoded_text; 67 return decoded_text;
62 } 68 }
63 69
64 std::string GenerateJWKSet(const uint8* key, int key_length, 70 std::string GenerateJWKSet(const uint8* key, int key_length,
65 const uint8* key_id, int key_id_length) { 71 const uint8* key_id, int key_id_length) {
66 // Both |key| and |key_id| need to be base64 encoded strings in the JWK. 72 // Both |key| and |key_id| need to be base64 encoded strings in the JWK.
67 std::string key_base64 = EncodeBase64(key, key_length); 73 std::string key_base64 = EncodeBase64(key, key_length);
68 std::string key_id_base64 = EncodeBase64(key_id, key_id_length); 74 std::string key_id_base64 = EncodeBase64(key_id, key_id_length);
69 75
70 // Create the JWK, and wrap it into a JWK Set. 76 // Create the JWK, and wrap it into a JWK Set.
71 scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue()); 77 scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue());
72 jwk->SetString(kKeyTypeTag, kSymmetricKeyValue); 78 jwk->SetString(kKeyTypeTag, kKeyTypeOct);
79 jwk->SetString(kAlgTag, kAlgA128KW);
73 jwk->SetString(kKeyTag, key_base64); 80 jwk->SetString(kKeyTag, key_base64);
74 jwk->SetString(kKeyIdTag, key_id_base64); 81 jwk->SetString(kKeyIdTag, key_id_base64);
75 scoped_ptr<base::ListValue> list(new base::ListValue()); 82 scoped_ptr<base::ListValue> list(new base::ListValue());
76 list->Append(jwk.release()); 83 list->Append(jwk.release());
77 base::DictionaryValue jwk_set; 84 base::DictionaryValue jwk_set;
78 jwk_set.Set(kKeysTag, list.release()); 85 jwk_set.Set(kKeysTag, list.release());
79 86
80 // Finally serialize |jwk_set| into a string and return it. 87 // Finally serialize |jwk_set| into a string and return it.
81 std::string serialized_jwk; 88 std::string serialized_jwk;
82 JSONStringValueSerializer serializer(&serialized_jwk); 89 JSONStringValueSerializer serializer(&serialized_jwk);
83 serializer.Serialize(jwk_set); 90 serializer.Serialize(jwk_set);
84 return serialized_jwk; 91 return serialized_jwk;
85 } 92 }
86 93
87 // Processes a JSON Web Key to extract the key id and key value. Sets |jwk_key| 94 // Processes a JSON Web Key to extract the key id and key value. Sets |jwk_key|
88 // to the id/value pair and returns true on success. 95 // to the id/value pair and returns true on success.
89 static bool ConvertJwkToKeyPair(const base::DictionaryValue& jwk, 96 static bool ConvertJwkToKeyPair(const base::DictionaryValue& jwk,
90 KeyIdAndKeyPair* jwk_key) { 97 KeyIdAndKeyPair* jwk_key) {
91 // Have found a JWK, start by checking that it is a symmetric key.
92 std::string type; 98 std::string type;
93 if (!jwk.GetString(kKeyTypeTag, &type) || type != kSymmetricKeyValue) { 99 if (!jwk.GetString(kKeyTypeTag, &type) || type != kKeyTypeOct) {
94 DVLOG(1) << "JWK is not a symmetric key"; 100 DVLOG(1) << "Missing or invalid '" << kKeyTypeTag << "': " << type;
95 return false; 101 return false;
96 } 102 }
97 103
104 std::string alg;
105 if (!jwk.GetString(kAlgTag, &alg) || alg != kAlgA128KW) {
106 DVLOG(1) << "Missing or invalid '" << kAlgTag << "': " << alg;
107 return false;
108 }
109
98 // Get the key id and actual key parameters. 110 // Get the key id and actual key parameters.
99 std::string encoded_key_id; 111 std::string encoded_key_id;
100 std::string encoded_key; 112 std::string encoded_key;
101 if (!jwk.GetString(kKeyIdTag, &encoded_key_id)) { 113 if (!jwk.GetString(kKeyIdTag, &encoded_key_id)) {
102 DVLOG(1) << "Missing '" << kKeyIdTag << "' parameter"; 114 DVLOG(1) << "Missing '" << kKeyIdTag << "' parameter";
103 return false; 115 return false;
104 } 116 }
105 if (!jwk.GetString(kKeyTag, &encoded_key)) { 117 if (!jwk.GetString(kKeyTag, &encoded_key)) {
106 DVLOG(1) << "Missing '" << kKeyTag << "' parameter"; 118 DVLOG(1) << "Missing '" << kKeyTag << "' parameter";
107 return false; 119 return false;
(...skipping 13 matching lines...) Expand all
121 } 133 }
122 134
123 // Add the decoded key ID and the decoded key to the list. 135 // Add the decoded key ID and the decoded key to the list.
124 *jwk_key = std::make_pair(raw_key_id, raw_key); 136 *jwk_key = std::make_pair(raw_key_id, raw_key);
125 return true; 137 return true;
126 } 138 }
127 139
128 bool ExtractKeysFromJWKSet(const std::string& jwk_set, 140 bool ExtractKeysFromJWKSet(const std::string& jwk_set,
129 KeyIdAndKeyPairs* keys, 141 KeyIdAndKeyPairs* keys,
130 MediaKeys::SessionType* session_type) { 142 MediaKeys::SessionType* session_type) {
131 if (!base::IsStringASCII(jwk_set)) 143 if (!base::IsStringASCII(jwk_set)) {
144 DVLOG(1) << "Non ASCII JWK Set: " << jwk_set;
132 return false; 145 return false;
146 }
133 147
134 scoped_ptr<base::Value> root(base::JSONReader().ReadToValue(jwk_set)); 148 scoped_ptr<base::Value> root(base::JSONReader().ReadToValue(jwk_set));
135 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) 149 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) {
150 DVLOG(1) << "Not valid JSON: " << jwk_set << ", root: " << root.get();
136 return false; 151 return false;
152 }
137 153
138 // Locate the set from the dictionary. 154 // Locate the set from the dictionary.
139 base::DictionaryValue* dictionary = 155 base::DictionaryValue* dictionary =
140 static_cast<base::DictionaryValue*>(root.get()); 156 static_cast<base::DictionaryValue*>(root.get());
141 base::ListValue* list_val = NULL; 157 base::ListValue* list_val = NULL;
142 if (!dictionary->GetList(kKeysTag, &list_val)) { 158 if (!dictionary->GetList(kKeysTag, &list_val)) {
143 DVLOG(1) << "Missing '" << kKeysTag 159 DVLOG(1) << "Missing '" << kKeysTag
144 << "' parameter or not a list in JWK Set"; 160 << "' parameter or not a list in JWK Set";
145 return false; 161 return false;
146 } 162 }
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 // Convert the serialized license request into std::vector and return it. 230 // Convert the serialized license request into std::vector and return it.
215 std::vector<uint8> result(json.begin(), json.end()); 231 std::vector<uint8> result(json.begin(), json.end());
216 license->swap(result); 232 license->swap(result);
217 } 233 }
218 234
219 bool ExtractFirstKeyIdFromLicenseRequest(const std::vector<uint8>& license, 235 bool ExtractFirstKeyIdFromLicenseRequest(const std::vector<uint8>& license,
220 std::vector<uint8>* first_key) { 236 std::vector<uint8>* first_key) {
221 const std::string license_as_str( 237 const std::string license_as_str(
222 reinterpret_cast<const char*>(!license.empty() ? &license[0] : NULL), 238 reinterpret_cast<const char*>(!license.empty() ? &license[0] : NULL),
223 license.size()); 239 license.size());
224 if (!base::IsStringASCII(license_as_str)) 240 if (!base::IsStringASCII(license_as_str)) {
241 DVLOG(1) << "Non ASCII license: " << license_as_str;
225 return false; 242 return false;
243 }
226 244
227 scoped_ptr<base::Value> root(base::JSONReader().ReadToValue(license_as_str)); 245 scoped_ptr<base::Value> root(base::JSONReader().ReadToValue(license_as_str));
228 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) 246 if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY) {
247 DVLOG(1) << "Not valid JSON: " << license_as_str;
229 return false; 248 return false;
249 }
230 250
231 // Locate the set from the dictionary. 251 // Locate the set from the dictionary.
232 base::DictionaryValue* dictionary = 252 base::DictionaryValue* dictionary =
233 static_cast<base::DictionaryValue*>(root.get()); 253 static_cast<base::DictionaryValue*>(root.get());
234 base::ListValue* list_val = NULL; 254 base::ListValue* list_val = NULL;
235 if (!dictionary->GetList(kKeyIdsTag, &list_val)) { 255 if (!dictionary->GetList(kKeyIdsTag, &list_val)) {
236 DVLOG(1) << "Missing '" << kKeyIdsTag << "' parameter or not a list"; 256 DVLOG(1) << "Missing '" << kKeyIdsTag << "' parameter or not a list";
237 return false; 257 return false;
238 } 258 }
239 259
(...skipping 14 matching lines...) Expand all
254 DVLOG(1) << "Invalid '" << kKeyIdsTag << "' value: " << encoded_key; 274 DVLOG(1) << "Invalid '" << kKeyIdsTag << "' value: " << encoded_key;
255 return false; 275 return false;
256 } 276 }
257 277
258 std::vector<uint8> result(decoded_string.begin(), decoded_string.end()); 278 std::vector<uint8> result(decoded_string.begin(), decoded_string.end());
259 first_key->swap(result); 279 first_key->swap(result);
260 return true; 280 return true;
261 } 281 }
262 282
263 } // namespace media 283 } // namespace media
OLDNEW
« no previous file with comments | « media/cdm/aes_decryptor_unittest.cc ('k') | media/cdm/json_web_key_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698