Home | History | Annotate | Download | only in cdm
      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 <list>
      8 #include <vector>
      9 
     10 #include "base/logging.h"
     11 #include "base/stl_util.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "crypto/encryptor.h"
     14 #include "crypto/symmetric_key.h"
     15 #include "media/base/audio_decoder_config.h"
     16 #include "media/base/decoder_buffer.h"
     17 #include "media/base/decrypt_config.h"
     18 #include "media/base/video_decoder_config.h"
     19 #include "media/base/video_frame.h"
     20 #include "media/cdm/json_web_key.h"
     21 
     22 namespace media {
     23 
     24 // Keeps track of the session IDs and DecryptionKeys. The keys are ordered by
     25 // insertion time (last insertion is first). It takes ownership of the
     26 // DecryptionKeys.
     27 class AesDecryptor::SessionIdDecryptionKeyMap {
     28   // Use a std::list to actually hold the data. Insertion is always done
     29   // at the front, so the "latest" decryption key is always the first one
     30   // in the list.
     31   typedef std::list<std::pair<uint32, DecryptionKey*> > KeyList;
     32 
     33  public:
     34   SessionIdDecryptionKeyMap() {}
     35   ~SessionIdDecryptionKeyMap() { STLDeleteValues(&key_list_); }
     36 
     37   // Replaces value if |session_id| is already present, or adds it if not.
     38   // This |decryption_key| becomes the latest until another insertion or
     39   // |session_id| is erased.
     40   void Insert(uint32 session_id, scoped_ptr<DecryptionKey> decryption_key);
     41 
     42   // Deletes the entry for |session_id| if present.
     43   void Erase(const uint32 session_id);
     44 
     45   // Returns whether the list is empty
     46   bool Empty() const { return key_list_.empty(); }
     47 
     48   // Returns the last inserted DecryptionKey.
     49   DecryptionKey* LatestDecryptionKey() {
     50     DCHECK(!key_list_.empty());
     51     return key_list_.begin()->second;
     52   }
     53 
     54  private:
     55   // Searches the list for an element with |session_id|.
     56   KeyList::iterator Find(const uint32 session_id);
     57 
     58   // Deletes the entry pointed to by |position|.
     59   void Erase(KeyList::iterator position);
     60 
     61   KeyList key_list_;
     62 
     63   DISALLOW_COPY_AND_ASSIGN(SessionIdDecryptionKeyMap);
     64 };
     65 
     66 void AesDecryptor::SessionIdDecryptionKeyMap::Insert(
     67     uint32 session_id,
     68     scoped_ptr<DecryptionKey> decryption_key) {
     69   KeyList::iterator it = Find(session_id);
     70   if (it != key_list_.end())
     71     Erase(it);
     72   DecryptionKey* raw_ptr = decryption_key.release();
     73   key_list_.push_front(std::make_pair(session_id, raw_ptr));
     74 }
     75 
     76 void AesDecryptor::SessionIdDecryptionKeyMap::Erase(const uint32 session_id) {
     77   KeyList::iterator it = Find(session_id);
     78   if (it == key_list_.end())
     79     return;
     80   Erase(it);
     81 }
     82 
     83 AesDecryptor::SessionIdDecryptionKeyMap::KeyList::iterator
     84 AesDecryptor::SessionIdDecryptionKeyMap::Find(const uint32 session_id) {
     85   for (KeyList::iterator it = key_list_.begin(); it != key_list_.end(); ++it) {
     86     if (it->first == session_id)
     87       return it;
     88   }
     89   return key_list_.end();
     90 }
     91 
     92 void AesDecryptor::SessionIdDecryptionKeyMap::Erase(
     93     KeyList::iterator position) {
     94   DCHECK(position->second);
     95   delete position->second;
     96   key_list_.erase(position);
     97 }
     98 
     99 uint32 AesDecryptor::next_web_session_id_ = 1;
    100 
    101 enum ClearBytesBufferSel {
    102   kSrcContainsClearBytes,
    103   kDstContainsClearBytes
    104 };
    105 
    106 static void CopySubsamples(const std::vector<SubsampleEntry>& subsamples,
    107                            const ClearBytesBufferSel sel,
    108                            const uint8* src,
    109                            uint8* dst) {
    110   for (size_t i = 0; i < subsamples.size(); i++) {
    111     const SubsampleEntry& subsample = subsamples[i];
    112     if (sel == kSrcContainsClearBytes) {
    113       src += subsample.clear_bytes;
    114     } else {
    115       dst += subsample.clear_bytes;
    116     }
    117     memcpy(dst, src, subsample.cypher_bytes);
    118     src += subsample.cypher_bytes;
    119     dst += subsample.cypher_bytes;
    120   }
    121 }
    122 
    123 // Decrypts |input| using |key|.  Returns a DecoderBuffer with the decrypted
    124 // data if decryption succeeded or NULL if decryption failed.
    125 static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input,
    126                                                 crypto::SymmetricKey* key) {
    127   CHECK(input.data_size());
    128   CHECK(input.decrypt_config());
    129   CHECK(key);
    130 
    131   crypto::Encryptor encryptor;
    132   if (!encryptor.Init(key, crypto::Encryptor::CTR, "")) {
    133     DVLOG(1) << "Could not initialize decryptor.";
    134     return NULL;
    135   }
    136 
    137   DCHECK_EQ(input.decrypt_config()->iv().size(),
    138             static_cast<size_t>(DecryptConfig::kDecryptionKeySize));
    139   if (!encryptor.SetCounter(input.decrypt_config()->iv())) {
    140     DVLOG(1) << "Could not set counter block.";
    141     return NULL;
    142   }
    143 
    144   const int data_offset = input.decrypt_config()->data_offset();
    145   const char* sample =
    146       reinterpret_cast<const char*>(input.data() + data_offset);
    147   DCHECK_GT(input.data_size(), data_offset);
    148   size_t sample_size = static_cast<size_t>(input.data_size() - data_offset);
    149 
    150   DCHECK_GT(sample_size, 0U) << "No sample data to be decrypted.";
    151   if (sample_size == 0)
    152     return NULL;
    153 
    154   if (input.decrypt_config()->subsamples().empty()) {
    155     std::string decrypted_text;
    156     base::StringPiece encrypted_text(sample, sample_size);
    157     if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) {
    158       DVLOG(1) << "Could not decrypt data.";
    159       return NULL;
    160     }
    161 
    162     // TODO(xhwang): Find a way to avoid this data copy.
    163     return DecoderBuffer::CopyFrom(
    164         reinterpret_cast<const uint8*>(decrypted_text.data()),
    165         decrypted_text.size());
    166   }
    167 
    168   const std::vector<SubsampleEntry>& subsamples =
    169       input.decrypt_config()->subsamples();
    170 
    171   size_t total_clear_size = 0;
    172   size_t total_encrypted_size = 0;
    173   for (size_t i = 0; i < subsamples.size(); i++) {
    174     total_clear_size += subsamples[i].clear_bytes;
    175     total_encrypted_size += subsamples[i].cypher_bytes;
    176     // Check for overflow. This check is valid because *_size is unsigned.
    177     DCHECK(total_clear_size >= subsamples[i].clear_bytes);
    178     if (total_encrypted_size < subsamples[i].cypher_bytes)
    179       return NULL;
    180   }
    181   size_t total_size = total_clear_size + total_encrypted_size;
    182   if (total_size < total_clear_size || total_size != sample_size) {
    183     DVLOG(1) << "Subsample sizes do not equal input size";
    184     return NULL;
    185   }
    186 
    187   // No need to decrypt if there is no encrypted data.
    188   if (total_encrypted_size <= 0) {
    189     return DecoderBuffer::CopyFrom(reinterpret_cast<const uint8*>(sample),
    190                                    sample_size);
    191   }
    192 
    193   // The encrypted portions of all subsamples must form a contiguous block,
    194   // such that an encrypted subsample that ends away from a block boundary is
    195   // immediately followed by the start of the next encrypted subsample. We
    196   // copy all encrypted subsamples to a contiguous buffer, decrypt them, then
    197   // copy the decrypted bytes over the encrypted bytes in the output.
    198   // TODO(strobe): attempt to reduce number of memory copies
    199   scoped_ptr<uint8[]> encrypted_bytes(new uint8[total_encrypted_size]);
    200   CopySubsamples(subsamples, kSrcContainsClearBytes,
    201                  reinterpret_cast<const uint8*>(sample), encrypted_bytes.get());
    202 
    203   base::StringPiece encrypted_text(
    204       reinterpret_cast<const char*>(encrypted_bytes.get()),
    205       total_encrypted_size);
    206   std::string decrypted_text;
    207   if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) {
    208     DVLOG(1) << "Could not decrypt data.";
    209     return NULL;
    210   }
    211   DCHECK_EQ(decrypted_text.size(), encrypted_text.size());
    212 
    213   scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom(
    214       reinterpret_cast<const uint8*>(sample), sample_size);
    215   CopySubsamples(subsamples, kDstContainsClearBytes,
    216                  reinterpret_cast<const uint8*>(decrypted_text.data()),
    217                  output->writable_data());
    218   return output;
    219 }
    220 
    221 AesDecryptor::AesDecryptor(const SessionCreatedCB& session_created_cb,
    222                            const SessionMessageCB& session_message_cb,
    223                            const SessionReadyCB& session_ready_cb,
    224                            const SessionClosedCB& session_closed_cb,
    225                            const SessionErrorCB& session_error_cb)
    226     : session_created_cb_(session_created_cb),
    227       session_message_cb_(session_message_cb),
    228       session_ready_cb_(session_ready_cb),
    229       session_closed_cb_(session_closed_cb),
    230       session_error_cb_(session_error_cb) {}
    231 
    232 AesDecryptor::~AesDecryptor() {
    233   key_map_.clear();
    234 }
    235 
    236 bool AesDecryptor::CreateSession(uint32 session_id,
    237                                  const std::string& type,
    238                                  const uint8* init_data,
    239                                  int init_data_length) {
    240   // Validate that this is a new session.
    241   DCHECK(valid_sessions_.find(session_id) == valid_sessions_.end());
    242   valid_sessions_.insert(session_id);
    243 
    244   std::string web_session_id_string(base::UintToString(next_web_session_id_++));
    245 
    246   // For now, the AesDecryptor does not care about |type|;
    247   // just fire the event with the |init_data| as the request.
    248   std::vector<uint8> message;
    249   if (init_data && init_data_length)
    250     message.assign(init_data, init_data + init_data_length);
    251 
    252   session_created_cb_.Run(session_id, web_session_id_string);
    253   session_message_cb_.Run(session_id, message, std::string());
    254   return true;
    255 }
    256 
    257 void AesDecryptor::UpdateSession(uint32 session_id,
    258                                  const uint8* response,
    259                                  int response_length) {
    260   CHECK(response);
    261   CHECK_GT(response_length, 0);
    262   DCHECK(valid_sessions_.find(session_id) != valid_sessions_.end());
    263 
    264   std::string key_string(reinterpret_cast<const char*>(response),
    265                          response_length);
    266   KeyIdAndKeyPairs keys;
    267   if (!ExtractKeysFromJWKSet(key_string, &keys)) {
    268     session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0);
    269     return;
    270   }
    271 
    272   // Make sure that at least one key was extracted.
    273   if (keys.empty()) {
    274     session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0);
    275     return;
    276   }
    277 
    278   for (KeyIdAndKeyPairs::iterator it = keys.begin(); it != keys.end(); ++it) {
    279     if (it->second.length() !=
    280         static_cast<size_t>(DecryptConfig::kDecryptionKeySize)) {
    281       DVLOG(1) << "Invalid key length: " << key_string.length();
    282       session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0);
    283       return;
    284     }
    285     if (!AddDecryptionKey(session_id, it->first, it->second)) {
    286       session_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0);
    287       return;
    288     }
    289   }
    290 
    291   if (!new_audio_key_cb_.is_null())
    292     new_audio_key_cb_.Run();
    293 
    294   if (!new_video_key_cb_.is_null())
    295     new_video_key_cb_.Run();
    296 
    297   session_ready_cb_.Run(session_id);
    298 }
    299 
    300 void AesDecryptor::ReleaseSession(uint32 session_id) {
    301   // Validate that this is a reference to an active session and then forget it.
    302   std::set<uint32>::iterator it = valid_sessions_.find(session_id);
    303   DCHECK(it != valid_sessions_.end());
    304   valid_sessions_.erase(it);
    305 
    306   DeleteKeysForSession(session_id);
    307   session_closed_cb_.Run(session_id);
    308 }
    309 
    310 Decryptor* AesDecryptor::GetDecryptor() {
    311   return this;
    312 }
    313 
    314 void AesDecryptor::RegisterNewKeyCB(StreamType stream_type,
    315                                     const NewKeyCB& new_key_cb) {
    316   switch (stream_type) {
    317     case kAudio:
    318       new_audio_key_cb_ = new_key_cb;
    319       break;
    320     case kVideo:
    321       new_video_key_cb_ = new_key_cb;
    322       break;
    323     default:
    324       NOTREACHED();
    325   }
    326 }
    327 
    328 void AesDecryptor::Decrypt(StreamType stream_type,
    329                            const scoped_refptr<DecoderBuffer>& encrypted,
    330                            const DecryptCB& decrypt_cb) {
    331   CHECK(encrypted->decrypt_config());
    332 
    333   scoped_refptr<DecoderBuffer> decrypted;
    334   // An empty iv string signals that the frame is unencrypted.
    335   if (encrypted->decrypt_config()->iv().empty()) {
    336     int data_offset = encrypted->decrypt_config()->data_offset();
    337     decrypted = DecoderBuffer::CopyFrom(encrypted->data() + data_offset,
    338                                         encrypted->data_size() - data_offset);
    339   } else {
    340     const std::string& key_id = encrypted->decrypt_config()->key_id();
    341     DecryptionKey* key = GetKey(key_id);
    342     if (!key) {
    343       DVLOG(1) << "Could not find a matching key for the given key ID.";
    344       decrypt_cb.Run(kNoKey, NULL);
    345       return;
    346     }
    347 
    348     crypto::SymmetricKey* decryption_key = key->decryption_key();
    349     decrypted = DecryptData(*encrypted.get(), decryption_key);
    350     if (!decrypted.get()) {
    351       DVLOG(1) << "Decryption failed.";
    352       decrypt_cb.Run(kError, NULL);
    353       return;
    354     }
    355   }
    356 
    357   decrypted->set_timestamp(encrypted->timestamp());
    358   decrypted->set_duration(encrypted->duration());
    359   decrypt_cb.Run(kSuccess, decrypted);
    360 }
    361 
    362 void AesDecryptor::CancelDecrypt(StreamType stream_type) {
    363   // Decrypt() calls the DecryptCB synchronously so there's nothing to cancel.
    364 }
    365 
    366 void AesDecryptor::InitializeAudioDecoder(const AudioDecoderConfig& config,
    367                                           const DecoderInitCB& init_cb) {
    368   // AesDecryptor does not support audio decoding.
    369   init_cb.Run(false);
    370 }
    371 
    372 void AesDecryptor::InitializeVideoDecoder(const VideoDecoderConfig& config,
    373                                           const DecoderInitCB& init_cb) {
    374   // AesDecryptor does not support video decoding.
    375   init_cb.Run(false);
    376 }
    377 
    378 void AesDecryptor::DecryptAndDecodeAudio(
    379     const scoped_refptr<DecoderBuffer>& encrypted,
    380     const AudioDecodeCB& audio_decode_cb) {
    381   NOTREACHED() << "AesDecryptor does not support audio decoding";
    382 }
    383 
    384 void AesDecryptor::DecryptAndDecodeVideo(
    385     const scoped_refptr<DecoderBuffer>& encrypted,
    386     const VideoDecodeCB& video_decode_cb) {
    387   NOTREACHED() << "AesDecryptor does not support video decoding";
    388 }
    389 
    390 void AesDecryptor::ResetDecoder(StreamType stream_type) {
    391   NOTREACHED() << "AesDecryptor does not support audio/video decoding";
    392 }
    393 
    394 void AesDecryptor::DeinitializeDecoder(StreamType stream_type) {
    395   NOTREACHED() << "AesDecryptor does not support audio/video decoding";
    396 }
    397 
    398 bool AesDecryptor::AddDecryptionKey(const uint32 session_id,
    399                                     const std::string& key_id,
    400                                     const std::string& key_string) {
    401   scoped_ptr<DecryptionKey> decryption_key(new DecryptionKey(key_string));
    402   if (!decryption_key) {
    403     DVLOG(1) << "Could not create key.";
    404     return false;
    405   }
    406 
    407   if (!decryption_key->Init()) {
    408     DVLOG(1) << "Could not initialize decryption key.";
    409     return false;
    410   }
    411 
    412   base::AutoLock auto_lock(key_map_lock_);
    413   KeyIdToSessionKeysMap::iterator key_id_entry = key_map_.find(key_id);
    414   if (key_id_entry != key_map_.end()) {
    415     key_id_entry->second->Insert(session_id, decryption_key.Pass());
    416     return true;
    417   }
    418 
    419   // |key_id| not found, so need to create new entry.
    420   scoped_ptr<SessionIdDecryptionKeyMap> inner_map(
    421       new SessionIdDecryptionKeyMap());
    422   inner_map->Insert(session_id, decryption_key.Pass());
    423   key_map_.add(key_id, inner_map.Pass());
    424   return true;
    425 }
    426 
    427 AesDecryptor::DecryptionKey* AesDecryptor::GetKey(
    428     const std::string& key_id) const {
    429   base::AutoLock auto_lock(key_map_lock_);
    430   KeyIdToSessionKeysMap::const_iterator key_id_found = key_map_.find(key_id);
    431   if (key_id_found == key_map_.end())
    432     return NULL;
    433 
    434   // Return the key from the "latest" session_id entry.
    435   return key_id_found->second->LatestDecryptionKey();
    436 }
    437 
    438 void AesDecryptor::DeleteKeysForSession(const uint32 session_id) {
    439   base::AutoLock auto_lock(key_map_lock_);
    440 
    441   // Remove all keys associated with |session_id|. Since the data is optimized
    442   // for access in GetKey(), we need to look at each entry in |key_map_|.
    443   KeyIdToSessionKeysMap::iterator it = key_map_.begin();
    444   while (it != key_map_.end()) {
    445     it->second->Erase(session_id);
    446     if (it->second->Empty()) {
    447       // Need to get rid of the entry for this key_id. This will mess up the
    448       // iterator, so we need to increment it first.
    449       KeyIdToSessionKeysMap::iterator current = it;
    450       ++it;
    451       key_map_.erase(current);
    452     } else {
    453       ++it;
    454     }
    455   }
    456 }
    457 
    458 AesDecryptor::DecryptionKey::DecryptionKey(const std::string& secret)
    459     : secret_(secret) {
    460 }
    461 
    462 AesDecryptor::DecryptionKey::~DecryptionKey() {}
    463 
    464 bool AesDecryptor::DecryptionKey::Init() {
    465   CHECK(!secret_.empty());
    466   decryption_key_.reset(crypto::SymmetricKey::Import(
    467       crypto::SymmetricKey::AES, secret_));
    468   if (!decryption_key_)
    469     return false;
    470   return true;
    471 }
    472 
    473 }  // namespace media
    474