aes_decryptor.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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 3// found in the LICENSE file. 4 5#include "media/cdm/aes_decryptor.h" 6 7#include <vector> 8 9#include "base/base64.h" 10#include "base/json/json_reader.h" 11#include "base/logging.h" 12#include "base/stl_util.h" 13#include "base/strings/string_number_conversions.h" 14#include "base/strings/string_util.h" 15#include "base/values.h" 16#include "crypto/encryptor.h" 17#include "crypto/symmetric_key.h" 18#include "media/base/audio_decoder_config.h" 19#include "media/base/decoder_buffer.h" 20#include "media/base/decrypt_config.h" 21#include "media/base/video_decoder_config.h" 22#include "media/base/video_frame.h" 23 24namespace media { 25 26uint32 AesDecryptor::next_session_id_ = 1; 27 28enum ClearBytesBufferSel { 29 kSrcContainsClearBytes, 30 kDstContainsClearBytes 31}; 32 33typedef std::vector<std::pair<std::string, std::string> > JWKKeys; 34 35static void CopySubsamples(const std::vector<SubsampleEntry>& subsamples, 36 const ClearBytesBufferSel sel, 37 const uint8* src, 38 uint8* dst) { 39 for (size_t i = 0; i < subsamples.size(); i++) { 40 const SubsampleEntry& subsample = subsamples[i]; 41 if (sel == kSrcContainsClearBytes) { 42 src += subsample.clear_bytes; 43 } else { 44 dst += subsample.clear_bytes; 45 } 46 memcpy(dst, src, subsample.cypher_bytes); 47 src += subsample.cypher_bytes; 48 dst += subsample.cypher_bytes; 49 } 50} 51 52// Helper to decode a base64 string. EME spec doesn't allow padding characters, 53// but base::Base64Decode() requires them. So check that they're not there, and 54// then add them before calling base::Base64Decode(). 55static bool DecodeBase64(std::string encoded_text, std::string* decoded_text) { 56 const char base64_padding = '='; 57 58 // TODO(jrummell): Enable this after layout tests have been updated to not 59 // include trailing padding characters. 60 // if (encoded_text.back() == base64_padding) 61 // return false; 62 63 // Add pad characters so length of |encoded_text| is exactly a multiple of 4. 64 size_t num_last_grouping_chars = encoded_text.length() % 4; 65 if (num_last_grouping_chars > 0) 66 encoded_text.append(4 - num_last_grouping_chars, base64_padding); 67 68 return base::Base64Decode(encoded_text, decoded_text); 69} 70 71// Processes a JSON Web Key to extract the key id and key value. Adds the 72// id/value pair to |jwk_keys| and returns true on success. 73static bool ProcessSymmetricKeyJWK(const DictionaryValue& jwk, 74 JWKKeys* jwk_keys) { 75 // A symmetric keys JWK looks like the following in JSON: 76 // { "kty":"oct", 77 // "kid":"AAECAwQFBgcICQoLDA0ODxAREhM", 78 // "k":"FBUWFxgZGhscHR4fICEiIw" } 79 // There may be other properties specified, but they are ignored. 80 // Ref: http://tools.ietf.org/html/draft-ietf-jose-json-web-key-14 81 // and: 82 // http://tools.ietf.org/html/draft-jones-jose-json-private-and-symmetric-key-00 83 84 // Have found a JWK, start by checking that it is a symmetric key. 85 std::string type; 86 if (!jwk.GetString("kty", &type) || type != "oct") { 87 DVLOG(1) << "JWK is not a symmetric key"; 88 return false; 89 } 90 91 // Get the key id and actual key parameters. 92 std::string encoded_key_id; 93 std::string encoded_key; 94 if (!jwk.GetString("kid", &encoded_key_id)) { 95 DVLOG(1) << "Missing 'kid' parameter"; 96 return false; 97 } 98 if (!jwk.GetString("k", &encoded_key)) { 99 DVLOG(1) << "Missing 'k' parameter"; 100 return false; 101 } 102 103 // Key ID and key are base64-encoded strings, so decode them. 104 std::string decoded_key_id; 105 std::string decoded_key; 106 if (!DecodeBase64(encoded_key_id, &decoded_key_id) || 107 decoded_key_id.empty()) { 108 DVLOG(1) << "Invalid 'kid' value"; 109 return false; 110 } 111 if (!DecodeBase64(encoded_key, &decoded_key) || 112 decoded_key.length() != 113 static_cast<size_t>(DecryptConfig::kDecryptionKeySize)) { 114 DVLOG(1) << "Invalid length of 'k' " << decoded_key.length(); 115 return false; 116 } 117 118 // Add the decoded key ID and the decoded key to the list. 119 jwk_keys->push_back(std::make_pair(decoded_key_id, decoded_key)); 120 return true; 121} 122 123// Extracts the JSON Web Keys from a JSON Web Key Set. If |input| looks like 124// a valid JWK Set, then true is returned and |jwk_keys| is updated to contain 125// the list of keys found. Otherwise return false. 126static bool ExtractJWKKeys(const std::string& input, JWKKeys* jwk_keys) { 127 // TODO(jrummell): The EME spec references a smaller set of allowed ASCII 128 // values. Verify with spec that the smaller character set is needed. 129 if (!IsStringASCII(input)) 130 return false; 131 132 scoped_ptr<Value> root(base::JSONReader().ReadToValue(input)); 133 if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) 134 return false; 135 136 // A JSON Web Key Set looks like the following in JSON: 137 // { "keys": [ JWK1, JWK2, ... ] } 138 // (See ProcessSymmetricKeyJWK() for description of JWK.) 139 // There may be other properties specified, but they are ignored. 140 // Locate the set from the dictionary. 141 DictionaryValue* dictionary = static_cast<DictionaryValue*>(root.get()); 142 ListValue* list_val = NULL; 143 if (!dictionary->GetList("keys", &list_val)) { 144 DVLOG(1) << "Missing 'keys' parameter or not a list in JWK Set"; 145 return false; 146 } 147 148 // Create a local list of keys, so that |jwk_keys| only gets updated on 149 // success. 150 JWKKeys local_keys; 151 for (size_t i = 0; i < list_val->GetSize(); ++i) { 152 DictionaryValue* jwk = NULL; 153 if (!list_val->GetDictionary(i, &jwk)) { 154 DVLOG(1) << "Unable to access 'keys'[" << i << "] in JWK Set"; 155 return false; 156 } 157 if (!ProcessSymmetricKeyJWK(*jwk, &local_keys)) { 158 DVLOG(1) << "Error from 'keys'[" << i << "]"; 159 return false; 160 } 161 } 162 163 // Successfully processed all JWKs in the set. 164 jwk_keys->swap(local_keys); 165 return true; 166} 167 168// Decrypts |input| using |key|. Returns a DecoderBuffer with the decrypted 169// data if decryption succeeded or NULL if decryption failed. 170static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input, 171 crypto::SymmetricKey* key) { 172 CHECK(input.data_size()); 173 CHECK(input.decrypt_config()); 174 CHECK(key); 175 176 crypto::Encryptor encryptor; 177 if (!encryptor.Init(key, crypto::Encryptor::CTR, "")) { 178 DVLOG(1) << "Could not initialize decryptor."; 179 return NULL; 180 } 181 182 DCHECK_EQ(input.decrypt_config()->iv().size(), 183 static_cast<size_t>(DecryptConfig::kDecryptionKeySize)); 184 if (!encryptor.SetCounter(input.decrypt_config()->iv())) { 185 DVLOG(1) << "Could not set counter block."; 186 return NULL; 187 } 188 189 const int data_offset = input.decrypt_config()->data_offset(); 190 const char* sample = 191 reinterpret_cast<const char*>(input.data() + data_offset); 192 int sample_size = input.data_size() - data_offset; 193 194 DCHECK_GT(sample_size, 0) << "No sample data to be decrypted."; 195 if (sample_size <= 0) 196 return NULL; 197 198 if (input.decrypt_config()->subsamples().empty()) { 199 std::string decrypted_text; 200 base::StringPiece encrypted_text(sample, sample_size); 201 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { 202 DVLOG(1) << "Could not decrypt data."; 203 return NULL; 204 } 205 206 // TODO(xhwang): Find a way to avoid this data copy. 207 return DecoderBuffer::CopyFrom( 208 reinterpret_cast<const uint8*>(decrypted_text.data()), 209 decrypted_text.size()); 210 } 211 212 const std::vector<SubsampleEntry>& subsamples = 213 input.decrypt_config()->subsamples(); 214 215 int total_clear_size = 0; 216 int total_encrypted_size = 0; 217 for (size_t i = 0; i < subsamples.size(); i++) { 218 total_clear_size += subsamples[i].clear_bytes; 219 total_encrypted_size += subsamples[i].cypher_bytes; 220 } 221 if (total_clear_size + total_encrypted_size != sample_size) { 222 DVLOG(1) << "Subsample sizes do not equal input size"; 223 return NULL; 224 } 225 226 // No need to decrypt if there is no encrypted data. 227 if (total_encrypted_size <= 0) { 228 return DecoderBuffer::CopyFrom(reinterpret_cast<const uint8*>(sample), 229 sample_size); 230 } 231 232 // The encrypted portions of all subsamples must form a contiguous block, 233 // such that an encrypted subsample that ends away from a block boundary is 234 // immediately followed by the start of the next encrypted subsample. We 235 // copy all encrypted subsamples to a contiguous buffer, decrypt them, then 236 // copy the decrypted bytes over the encrypted bytes in the output. 237 // TODO(strobe): attempt to reduce number of memory copies 238 scoped_ptr<uint8[]> encrypted_bytes(new uint8[total_encrypted_size]); 239 CopySubsamples(subsamples, kSrcContainsClearBytes, 240 reinterpret_cast<const uint8*>(sample), encrypted_bytes.get()); 241 242 base::StringPiece encrypted_text( 243 reinterpret_cast<const char*>(encrypted_bytes.get()), 244 total_encrypted_size); 245 std::string decrypted_text; 246 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { 247 DVLOG(1) << "Could not decrypt data."; 248 return NULL; 249 } 250 DCHECK_EQ(decrypted_text.size(), encrypted_text.size()); 251 252 scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom( 253 reinterpret_cast<const uint8*>(sample), sample_size); 254 CopySubsamples(subsamples, kDstContainsClearBytes, 255 reinterpret_cast<const uint8*>(decrypted_text.data()), 256 output->writable_data()); 257 return output; 258} 259 260AesDecryptor::AesDecryptor(const KeyAddedCB& key_added_cb, 261 const KeyErrorCB& key_error_cb, 262 const KeyMessageCB& key_message_cb) 263 : key_added_cb_(key_added_cb), 264 key_error_cb_(key_error_cb), 265 key_message_cb_(key_message_cb) { 266} 267 268AesDecryptor::~AesDecryptor() { 269 STLDeleteValues(&key_map_); 270} 271 272bool AesDecryptor::GenerateKeyRequest(const std::string& type, 273 const uint8* init_data, 274 int init_data_length) { 275 std::string session_id_string(base::UintToString(next_session_id_++)); 276 277 // For now, the AesDecryptor does not care about |type|; 278 // just fire the event with the |init_data| as the request. 279 std::vector<uint8> message; 280 if (init_data && init_data_length) 281 message.assign(init_data, init_data + init_data_length); 282 283 key_message_cb_.Run(session_id_string, message, std::string()); 284 return true; 285} 286 287void AesDecryptor::AddKey(const uint8* key, 288 int key_length, 289 const uint8* init_data, 290 int init_data_length, 291 const std::string& session_id) { 292 CHECK(key); 293 CHECK_GT(key_length, 0); 294 295 // AddKey() is called from update(), where the key(s) are passed as a JSON 296 // Web Key (JWK) set. Each JWK needs to be a symmetric key ('kty' = "oct"), 297 // with 'kid' being the base64-encoded key id, and 'k' being the 298 // base64-encoded key. 299 // 300 // For backwards compatibility with v0.1b of the spec (where |key| is the raw 301 // key and |init_data| is the key id), if |key| is not valid JSON, then 302 // attempt to process it as a raw key. 303 304 // TODO(xhwang): Add |session_id| check after we figure out how: 305 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=16550 306 307 std::string key_string(reinterpret_cast<const char*>(key), key_length); 308 JWKKeys jwk_keys; 309 if (ExtractJWKKeys(key_string, &jwk_keys)) { 310 // Since |key| represents valid JSON, init_data must be empty. 311 DCHECK(!init_data); 312 DCHECK_EQ(init_data_length, 0); 313 314 // Make sure that at least one key was extracted. 315 if (jwk_keys.empty()) { 316 key_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); 317 return; 318 } 319 for (JWKKeys::iterator it = jwk_keys.begin() ; it != jwk_keys.end(); ++it) { 320 if (!AddDecryptionKey(it->first, it->second)) { 321 key_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); 322 return; 323 } 324 } 325 } else { 326 // v0.1b backwards compatibility support. 327 // TODO(jrummell): Remove this code once v0.1b no longer supported. 328 329 if (key_string.length() != 330 static_cast<size_t>(DecryptConfig::kDecryptionKeySize)) { 331 DVLOG(1) << "Invalid key length: " << key_string.length(); 332 key_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); 333 return; 334 } 335 336 // TODO(xhwang): Fix the decryptor to accept no |init_data|. See 337 // http://crbug.com/123265. Until then, ensure a non-empty value is passed. 338 static const uint8 kDummyInitData[1] = {0}; 339 if (!init_data) { 340 init_data = kDummyInitData; 341 init_data_length = arraysize(kDummyInitData); 342 } 343 344 // TODO(xhwang): For now, use |init_data| for key ID. Make this more spec 345 // compliant later (http://crbug.com/123262, http://crbug.com/123265). 346 std::string key_id_string(reinterpret_cast<const char*>(init_data), 347 init_data_length); 348 if (!AddDecryptionKey(key_id_string, key_string)) { 349 // Error logged in AddDecryptionKey() 350 key_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0); 351 return; 352 } 353 } 354 355 if (!new_audio_key_cb_.is_null()) 356 new_audio_key_cb_.Run(); 357 358 if (!new_video_key_cb_.is_null()) 359 new_video_key_cb_.Run(); 360 361 key_added_cb_.Run(session_id); 362} 363 364void AesDecryptor::CancelKeyRequest(const std::string& session_id) { 365} 366 367Decryptor* AesDecryptor::GetDecryptor() { 368 return this; 369} 370 371void AesDecryptor::RegisterNewKeyCB(StreamType stream_type, 372 const NewKeyCB& new_key_cb) { 373 switch (stream_type) { 374 case kAudio: 375 new_audio_key_cb_ = new_key_cb; 376 break; 377 case kVideo: 378 new_video_key_cb_ = new_key_cb; 379 break; 380 default: 381 NOTREACHED(); 382 } 383} 384 385void AesDecryptor::Decrypt(StreamType stream_type, 386 const scoped_refptr<DecoderBuffer>& encrypted, 387 const DecryptCB& decrypt_cb) { 388 CHECK(encrypted->decrypt_config()); 389 390 scoped_refptr<DecoderBuffer> decrypted; 391 // An empty iv string signals that the frame is unencrypted. 392 if (encrypted->decrypt_config()->iv().empty()) { 393 int data_offset = encrypted->decrypt_config()->data_offset(); 394 decrypted = DecoderBuffer::CopyFrom(encrypted->data() + data_offset, 395 encrypted->data_size() - data_offset); 396 } else { 397 const std::string& key_id = encrypted->decrypt_config()->key_id(); 398 DecryptionKey* key = GetKey(key_id); 399 if (!key) { 400 DVLOG(1) << "Could not find a matching key for the given key ID."; 401 decrypt_cb.Run(kNoKey, NULL); 402 return; 403 } 404 405 crypto::SymmetricKey* decryption_key = key->decryption_key(); 406 decrypted = DecryptData(*encrypted.get(), decryption_key); 407 if (!decrypted.get()) { 408 DVLOG(1) << "Decryption failed."; 409 decrypt_cb.Run(kError, NULL); 410 return; 411 } 412 } 413 414 decrypted->set_timestamp(encrypted->timestamp()); 415 decrypted->set_duration(encrypted->duration()); 416 decrypt_cb.Run(kSuccess, decrypted); 417} 418 419void AesDecryptor::CancelDecrypt(StreamType stream_type) { 420 // Decrypt() calls the DecryptCB synchronously so there's nothing to cancel. 421} 422 423void AesDecryptor::InitializeAudioDecoder(const AudioDecoderConfig& config, 424 const DecoderInitCB& init_cb) { 425 // AesDecryptor does not support audio decoding. 426 init_cb.Run(false); 427} 428 429void AesDecryptor::InitializeVideoDecoder(const VideoDecoderConfig& config, 430 const DecoderInitCB& init_cb) { 431 // AesDecryptor does not support video decoding. 432 init_cb.Run(false); 433} 434 435void AesDecryptor::DecryptAndDecodeAudio( 436 const scoped_refptr<DecoderBuffer>& encrypted, 437 const AudioDecodeCB& audio_decode_cb) { 438 NOTREACHED() << "AesDecryptor does not support audio decoding"; 439} 440 441void AesDecryptor::DecryptAndDecodeVideo( 442 const scoped_refptr<DecoderBuffer>& encrypted, 443 const VideoDecodeCB& video_decode_cb) { 444 NOTREACHED() << "AesDecryptor does not support video decoding"; 445} 446 447void AesDecryptor::ResetDecoder(StreamType stream_type) { 448 NOTREACHED() << "AesDecryptor does not support audio/video decoding"; 449} 450 451void AesDecryptor::DeinitializeDecoder(StreamType stream_type) { 452 NOTREACHED() << "AesDecryptor does not support audio/video decoding"; 453} 454 455bool AesDecryptor::AddDecryptionKey(const std::string& key_id, 456 const std::string& key_string) { 457 scoped_ptr<DecryptionKey> decryption_key(new DecryptionKey(key_string)); 458 if (!decryption_key) { 459 DVLOG(1) << "Could not create key."; 460 return false; 461 } 462 463 if (!decryption_key->Init()) { 464 DVLOG(1) << "Could not initialize decryption key."; 465 return false; 466 } 467 468 base::AutoLock auto_lock(key_map_lock_); 469 KeyMap::iterator found = key_map_.find(key_id); 470 if (found != key_map_.end()) { 471 delete found->second; 472 key_map_.erase(found); 473 } 474 key_map_[key_id] = decryption_key.release(); 475 return true; 476} 477 478AesDecryptor::DecryptionKey* AesDecryptor::GetKey( 479 const std::string& key_id) const { 480 base::AutoLock auto_lock(key_map_lock_); 481 KeyMap::const_iterator found = key_map_.find(key_id); 482 if (found == key_map_.end()) 483 return NULL; 484 485 return found->second; 486} 487 488AesDecryptor::DecryptionKey::DecryptionKey(const std::string& secret) 489 : secret_(secret) { 490} 491 492AesDecryptor::DecryptionKey::~DecryptionKey() {} 493 494bool AesDecryptor::DecryptionKey::Init() { 495 CHECK(!secret_.empty()); 496 decryption_key_.reset(crypto::SymmetricKey::Import( 497 crypto::SymmetricKey::AES, secret_)); 498 if (!decryption_key_) 499 return false; 500 return true; 501} 502 503} // namespace media 504