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