| OLD | NEW |
| 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/aes_decryptor.h" | 5 #include "media/cdm/aes_decryptor.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <list> | 8 #include <list> |
| 9 #include <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 typedef std::list<std::pair<std::string, DecryptionKey*> > KeyList; | 40 typedef std::list<std::pair<std::string, DecryptionKey*> > KeyList; |
| 41 | 41 |
| 42 public: | 42 public: |
| 43 SessionIdDecryptionKeyMap() {} | 43 SessionIdDecryptionKeyMap() {} |
| 44 ~SessionIdDecryptionKeyMap() { STLDeleteValues(&key_list_); } | 44 ~SessionIdDecryptionKeyMap() { STLDeleteValues(&key_list_); } |
| 45 | 45 |
| 46 // Replaces value if |session_id| is already present, or adds it if not. | 46 // Replaces value if |session_id| is already present, or adds it if not. |
| 47 // This |decryption_key| becomes the latest until another insertion or | 47 // This |decryption_key| becomes the latest until another insertion or |
| 48 // |session_id| is erased. | 48 // |session_id| is erased. |
| 49 void Insert(const std::string& session_id, | 49 void Insert(const std::string& session_id, |
| 50 scoped_ptr<DecryptionKey> decryption_key); | 50 std::unique_ptr<DecryptionKey> decryption_key); |
| 51 | 51 |
| 52 // Deletes the entry for |session_id| if present. | 52 // Deletes the entry for |session_id| if present. |
| 53 void Erase(const std::string& session_id); | 53 void Erase(const std::string& session_id); |
| 54 | 54 |
| 55 // Returns whether the list is empty | 55 // Returns whether the list is empty |
| 56 bool Empty() const { return key_list_.empty(); } | 56 bool Empty() const { return key_list_.empty(); } |
| 57 | 57 |
| 58 // Returns the last inserted DecryptionKey. | 58 // Returns the last inserted DecryptionKey. |
| 59 DecryptionKey* LatestDecryptionKey() { | 59 DecryptionKey* LatestDecryptionKey() { |
| 60 DCHECK(!key_list_.empty()); | 60 DCHECK(!key_list_.empty()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 72 // Deletes the entry pointed to by |position|. | 72 // Deletes the entry pointed to by |position|. |
| 73 void Erase(KeyList::iterator position); | 73 void Erase(KeyList::iterator position); |
| 74 | 74 |
| 75 KeyList key_list_; | 75 KeyList key_list_; |
| 76 | 76 |
| 77 DISALLOW_COPY_AND_ASSIGN(SessionIdDecryptionKeyMap); | 77 DISALLOW_COPY_AND_ASSIGN(SessionIdDecryptionKeyMap); |
| 78 }; | 78 }; |
| 79 | 79 |
| 80 void AesDecryptor::SessionIdDecryptionKeyMap::Insert( | 80 void AesDecryptor::SessionIdDecryptionKeyMap::Insert( |
| 81 const std::string& session_id, | 81 const std::string& session_id, |
| 82 scoped_ptr<DecryptionKey> decryption_key) { | 82 std::unique_ptr<DecryptionKey> decryption_key) { |
| 83 KeyList::iterator it = Find(session_id); | 83 KeyList::iterator it = Find(session_id); |
| 84 if (it != key_list_.end()) | 84 if (it != key_list_.end()) |
| 85 Erase(it); | 85 Erase(it); |
| 86 DecryptionKey* raw_ptr = decryption_key.release(); | 86 DecryptionKey* raw_ptr = decryption_key.release(); |
| 87 key_list_.push_front(std::make_pair(session_id, raw_ptr)); | 87 key_list_.push_front(std::make_pair(session_id, raw_ptr)); |
| 88 } | 88 } |
| 89 | 89 |
| 90 void AesDecryptor::SessionIdDecryptionKeyMap::Erase( | 90 void AesDecryptor::SessionIdDecryptionKeyMap::Erase( |
| 91 const std::string& session_id) { | 91 const std::string& session_id) { |
| 92 KeyList::iterator it = Find(session_id); | 92 KeyList::iterator it = Find(session_id); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 return DecoderBuffer::CopyFrom(reinterpret_cast<const uint8_t*>(sample), | 201 return DecoderBuffer::CopyFrom(reinterpret_cast<const uint8_t*>(sample), |
| 202 sample_size); | 202 sample_size); |
| 203 } | 203 } |
| 204 | 204 |
| 205 // The encrypted portions of all subsamples must form a contiguous block, | 205 // The encrypted portions of all subsamples must form a contiguous block, |
| 206 // such that an encrypted subsample that ends away from a block boundary is | 206 // such that an encrypted subsample that ends away from a block boundary is |
| 207 // immediately followed by the start of the next encrypted subsample. We | 207 // immediately followed by the start of the next encrypted subsample. We |
| 208 // copy all encrypted subsamples to a contiguous buffer, decrypt them, then | 208 // copy all encrypted subsamples to a contiguous buffer, decrypt them, then |
| 209 // copy the decrypted bytes over the encrypted bytes in the output. | 209 // copy the decrypted bytes over the encrypted bytes in the output. |
| 210 // TODO(strobe): attempt to reduce number of memory copies | 210 // TODO(strobe): attempt to reduce number of memory copies |
| 211 scoped_ptr<uint8_t[]> encrypted_bytes(new uint8_t[total_encrypted_size]); | 211 std::unique_ptr<uint8_t[]> encrypted_bytes(new uint8_t[total_encrypted_size]); |
| 212 CopySubsamples(subsamples, kSrcContainsClearBytes, | 212 CopySubsamples(subsamples, kSrcContainsClearBytes, |
| 213 reinterpret_cast<const uint8_t*>(sample), | 213 reinterpret_cast<const uint8_t*>(sample), |
| 214 encrypted_bytes.get()); | 214 encrypted_bytes.get()); |
| 215 | 215 |
| 216 base::StringPiece encrypted_text( | 216 base::StringPiece encrypted_text( |
| 217 reinterpret_cast<const char*>(encrypted_bytes.get()), | 217 reinterpret_cast<const char*>(encrypted_bytes.get()), |
| 218 total_encrypted_size); | 218 total_encrypted_size); |
| 219 std::string decrypted_text; | 219 std::string decrypted_text; |
| 220 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { | 220 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { |
| 221 DVLOG(1) << "Could not decrypt data."; | 221 DVLOG(1) << "Could not decrypt data."; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 242 // with |security_origin|. | 242 // with |security_origin|. |
| 243 DCHECK(!session_message_cb_.is_null()); | 243 DCHECK(!session_message_cb_.is_null()); |
| 244 DCHECK(!session_closed_cb_.is_null()); | 244 DCHECK(!session_closed_cb_.is_null()); |
| 245 DCHECK(!session_keys_change_cb_.is_null()); | 245 DCHECK(!session_keys_change_cb_.is_null()); |
| 246 } | 246 } |
| 247 | 247 |
| 248 AesDecryptor::~AesDecryptor() { | 248 AesDecryptor::~AesDecryptor() { |
| 249 key_map_.clear(); | 249 key_map_.clear(); |
| 250 } | 250 } |
| 251 | 251 |
| 252 void AesDecryptor::SetServerCertificate(const std::vector<uint8_t>& certificate, | 252 void AesDecryptor::SetServerCertificate( |
| 253 scoped_ptr<SimpleCdmPromise> promise) { | 253 const std::vector<uint8_t>& certificate, |
| 254 std::unique_ptr<SimpleCdmPromise> promise) { |
| 254 promise->reject( | 255 promise->reject( |
| 255 NOT_SUPPORTED_ERROR, 0, "SetServerCertificate() is not supported."); | 256 NOT_SUPPORTED_ERROR, 0, "SetServerCertificate() is not supported."); |
| 256 } | 257 } |
| 257 | 258 |
| 258 void AesDecryptor::CreateSessionAndGenerateRequest( | 259 void AesDecryptor::CreateSessionAndGenerateRequest( |
| 259 SessionType session_type, | 260 SessionType session_type, |
| 260 EmeInitDataType init_data_type, | 261 EmeInitDataType init_data_type, |
| 261 const std::vector<uint8_t>& init_data, | 262 const std::vector<uint8_t>& init_data, |
| 262 scoped_ptr<NewSessionCdmPromise> promise) { | 263 std::unique_ptr<NewSessionCdmPromise> promise) { |
| 263 std::string session_id(base::UintToString(next_session_id_++)); | 264 std::string session_id(base::UintToString(next_session_id_++)); |
| 264 valid_sessions_.insert(session_id); | 265 valid_sessions_.insert(session_id); |
| 265 | 266 |
| 266 // For now, the AesDecryptor does not care about |session_type|. | 267 // For now, the AesDecryptor does not care about |session_type|. |
| 267 // TODO(jrummell): Validate |session_type|. | 268 // TODO(jrummell): Validate |session_type|. |
| 268 | 269 |
| 269 std::vector<uint8_t> message; | 270 std::vector<uint8_t> message; |
| 270 // TODO(jrummell): Since unprefixed will never send NULL, remove this check | 271 // TODO(jrummell): Since unprefixed will never send NULL, remove this check |
| 271 // when prefixed EME is removed (http://crbug.com/249976). | 272 // when prefixed EME is removed (http://crbug.com/249976). |
| 272 if (!init_data.empty()) { | 273 if (!init_data.empty()) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 | 312 |
| 312 promise->resolve(session_id); | 313 promise->resolve(session_id); |
| 313 | 314 |
| 314 // No URL needed for license requests. | 315 // No URL needed for license requests. |
| 315 GURL empty_gurl; | 316 GURL empty_gurl; |
| 316 session_message_cb_.Run(session_id, LICENSE_REQUEST, message, empty_gurl); | 317 session_message_cb_.Run(session_id, LICENSE_REQUEST, message, empty_gurl); |
| 317 } | 318 } |
| 318 | 319 |
| 319 void AesDecryptor::LoadSession(SessionType session_type, | 320 void AesDecryptor::LoadSession(SessionType session_type, |
| 320 const std::string& session_id, | 321 const std::string& session_id, |
| 321 scoped_ptr<NewSessionCdmPromise> promise) { | 322 std::unique_ptr<NewSessionCdmPromise> promise) { |
| 322 // TODO(xhwang): Change this to NOTREACHED() when blink checks for key systems | 323 // TODO(xhwang): Change this to NOTREACHED() when blink checks for key systems |
| 323 // that do not support loadSession. See http://crbug.com/342481 | 324 // that do not support loadSession. See http://crbug.com/342481 |
| 324 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported."); | 325 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported."); |
| 325 } | 326 } |
| 326 | 327 |
| 327 void AesDecryptor::UpdateSession(const std::string& session_id, | 328 void AesDecryptor::UpdateSession(const std::string& session_id, |
| 328 const std::vector<uint8_t>& response, | 329 const std::vector<uint8_t>& response, |
| 329 scoped_ptr<SimpleCdmPromise> promise) { | 330 std::unique_ptr<SimpleCdmPromise> promise) { |
| 330 CHECK(!response.empty()); | 331 CHECK(!response.empty()); |
| 331 | 332 |
| 332 // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed. | 333 // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed. |
| 333 if (valid_sessions_.find(session_id) == valid_sessions_.end()) { | 334 if (valid_sessions_.find(session_id) == valid_sessions_.end()) { |
| 334 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist."); | 335 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist."); |
| 335 return; | 336 return; |
| 336 } | 337 } |
| 337 | 338 |
| 338 std::string key_string(response.begin(), response.end()); | 339 std::string key_string(response.begin(), response.end()); |
| 339 | 340 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 keys_info.push_back( | 394 keys_info.push_back( |
| 394 new CdmKeyInformation(item.first, CdmKeyInformation::USABLE, 0)); | 395 new CdmKeyInformation(item.first, CdmKeyInformation::USABLE, 0)); |
| 395 } | 396 } |
| 396 } | 397 } |
| 397 } | 398 } |
| 398 | 399 |
| 399 session_keys_change_cb_.Run(session_id, key_added, std::move(keys_info)); | 400 session_keys_change_cb_.Run(session_id, key_added, std::move(keys_info)); |
| 400 } | 401 } |
| 401 | 402 |
| 402 void AesDecryptor::CloseSession(const std::string& session_id, | 403 void AesDecryptor::CloseSession(const std::string& session_id, |
| 403 scoped_ptr<SimpleCdmPromise> promise) { | 404 std::unique_ptr<SimpleCdmPromise> promise) { |
| 404 // Validate that this is a reference to an active session and then forget it. | 405 // Validate that this is a reference to an active session and then forget it. |
| 405 std::set<std::string>::iterator it = valid_sessions_.find(session_id); | 406 std::set<std::string>::iterator it = valid_sessions_.find(session_id); |
| 406 DCHECK(it != valid_sessions_.end()); | 407 DCHECK(it != valid_sessions_.end()); |
| 407 | 408 |
| 408 valid_sessions_.erase(it); | 409 valid_sessions_.erase(it); |
| 409 | 410 |
| 410 // Close the session. | 411 // Close the session. |
| 411 DeleteKeysForSession(session_id); | 412 DeleteKeysForSession(session_id); |
| 412 promise->resolve(); | 413 promise->resolve(); |
| 413 session_closed_cb_.Run(session_id); | 414 session_closed_cb_.Run(session_id); |
| 414 } | 415 } |
| 415 | 416 |
| 416 void AesDecryptor::RemoveSession(const std::string& session_id, | 417 void AesDecryptor::RemoveSession(const std::string& session_id, |
| 417 scoped_ptr<SimpleCdmPromise> promise) { | 418 std::unique_ptr<SimpleCdmPromise> promise) { |
| 418 // AesDecryptor doesn't keep any persistent data, so this should be | 419 // AesDecryptor doesn't keep any persistent data, so this should be |
| 419 // NOT_REACHED(). | 420 // NOT_REACHED(). |
| 420 // TODO(jrummell): Make sure persistent session types are rejected. | 421 // TODO(jrummell): Make sure persistent session types are rejected. |
| 421 // http://crbug.com/384152. | 422 // http://crbug.com/384152. |
| 422 // | 423 // |
| 423 // However, v0.1b calls to CancelKeyRequest() will call this, so close the | 424 // However, v0.1b calls to CancelKeyRequest() will call this, so close the |
| 424 // session, if it exists. | 425 // session, if it exists. |
| 425 // TODO(jrummell): Remove the close() call when prefixed EME is removed. | 426 // TODO(jrummell): Remove the close() call when prefixed EME is removed. |
| 426 // http://crbug.com/249976. | 427 // http://crbug.com/249976. |
| 427 if (valid_sessions_.find(session_id) != valid_sessions_.end()) { | 428 if (valid_sessions_.find(session_id) != valid_sessions_.end()) { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 | 529 |
| 529 void AesDecryptor::DeinitializeDecoder(StreamType stream_type) { | 530 void AesDecryptor::DeinitializeDecoder(StreamType stream_type) { |
| 530 // AesDecryptor does not support audio/video decoding, but since this can be | 531 // AesDecryptor does not support audio/video decoding, but since this can be |
| 531 // called any time after InitializeAudioDecoder/InitializeVideoDecoder, | 532 // called any time after InitializeAudioDecoder/InitializeVideoDecoder, |
| 532 // nothing to be done here. | 533 // nothing to be done here. |
| 533 } | 534 } |
| 534 | 535 |
| 535 bool AesDecryptor::AddDecryptionKey(const std::string& session_id, | 536 bool AesDecryptor::AddDecryptionKey(const std::string& session_id, |
| 536 const std::string& key_id, | 537 const std::string& key_id, |
| 537 const std::string& key_string) { | 538 const std::string& key_string) { |
| 538 scoped_ptr<DecryptionKey> decryption_key(new DecryptionKey(key_string)); | 539 std::unique_ptr<DecryptionKey> decryption_key(new DecryptionKey(key_string)); |
| 539 if (!decryption_key->Init()) { | 540 if (!decryption_key->Init()) { |
| 540 DVLOG(1) << "Could not initialize decryption key."; | 541 DVLOG(1) << "Could not initialize decryption key."; |
| 541 return false; | 542 return false; |
| 542 } | 543 } |
| 543 | 544 |
| 544 base::AutoLock auto_lock(key_map_lock_); | 545 base::AutoLock auto_lock(key_map_lock_); |
| 545 KeyIdToSessionKeysMap::iterator key_id_entry = key_map_.find(key_id); | 546 KeyIdToSessionKeysMap::iterator key_id_entry = key_map_.find(key_id); |
| 546 if (key_id_entry != key_map_.end()) { | 547 if (key_id_entry != key_map_.end()) { |
| 547 key_id_entry->second->Insert(session_id, std::move(decryption_key)); | 548 key_id_entry->second->Insert(session_id, std::move(decryption_key)); |
| 548 return true; | 549 return true; |
| 549 } | 550 } |
| 550 | 551 |
| 551 // |key_id| not found, so need to create new entry. | 552 // |key_id| not found, so need to create new entry. |
| 552 scoped_ptr<SessionIdDecryptionKeyMap> inner_map( | 553 std::unique_ptr<SessionIdDecryptionKeyMap> inner_map( |
| 553 new SessionIdDecryptionKeyMap()); | 554 new SessionIdDecryptionKeyMap()); |
| 554 inner_map->Insert(session_id, std::move(decryption_key)); | 555 inner_map->Insert(session_id, std::move(decryption_key)); |
| 555 key_map_.add(key_id, std::move(inner_map)); | 556 key_map_.add(key_id, std::move(inner_map)); |
| 556 return true; | 557 return true; |
| 557 } | 558 } |
| 558 | 559 |
| 559 AesDecryptor::DecryptionKey* AesDecryptor::GetKey_Locked( | 560 AesDecryptor::DecryptionKey* AesDecryptor::GetKey_Locked( |
| 560 const std::string& key_id) const { | 561 const std::string& key_id) const { |
| 561 key_map_lock_.AssertAcquired(); | 562 key_map_lock_.AssertAcquired(); |
| 562 KeyIdToSessionKeysMap::const_iterator key_id_found = key_map_.find(key_id); | 563 KeyIdToSessionKeysMap::const_iterator key_id_found = key_map_.find(key_id); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 607 bool AesDecryptor::DecryptionKey::Init() { | 608 bool AesDecryptor::DecryptionKey::Init() { |
| 608 CHECK(!secret_.empty()); | 609 CHECK(!secret_.empty()); |
| 609 decryption_key_.reset(crypto::SymmetricKey::Import( | 610 decryption_key_.reset(crypto::SymmetricKey::Import( |
| 610 crypto::SymmetricKey::AES, secret_)); | 611 crypto::SymmetricKey::AES, secret_)); |
| 611 if (!decryption_key_) | 612 if (!decryption_key_) |
| 612 return false; | 613 return false; |
| 613 return true; | 614 return true; |
| 614 } | 615 } |
| 615 | 616 |
| 616 } // namespace media | 617 } // namespace media |
| OLD | NEW |