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.
5 #include "media/cdm/aes_decryptor.h"
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"
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
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
31 typedef std::list
<std::pair
<uint32
, DecryptionKey
*> > KeyList
;
34 SessionIdDecryptionKeyMap() {}
35 ~SessionIdDecryptionKeyMap() { STLDeleteValues(&key_list_
); }
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
);
42 // Deletes the entry for |session_id| if present.
43 void Erase(const uint32 session_id
);
45 // Returns whether the list is empty
46 bool Empty() const { return key_list_
.empty(); }
48 // Returns the last inserted DecryptionKey.
49 DecryptionKey
* LatestDecryptionKey() {
50 DCHECK(!key_list_
.empty());
51 return key_list_
.begin()->second
;
55 // Searches the list for an element with |session_id|.
56 KeyList::iterator
Find(const uint32 session_id
);
58 // Deletes the entry pointed to by |position|.
59 void Erase(KeyList::iterator position
);
63 DISALLOW_COPY_AND_ASSIGN(SessionIdDecryptionKeyMap
);
66 void AesDecryptor::SessionIdDecryptionKeyMap::Insert(
68 scoped_ptr
<DecryptionKey
> decryption_key
) {
69 KeyList::iterator it
= Find(session_id
);
70 if (it
!= key_list_
.end())
72 DecryptionKey
* raw_ptr
= decryption_key
.release();
73 key_list_
.push_front(std::make_pair(session_id
, raw_ptr
));
76 void AesDecryptor::SessionIdDecryptionKeyMap::Erase(const uint32 session_id
) {
77 KeyList::iterator it
= Find(session_id
);
78 if (it
== key_list_
.end())
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
)
89 return key_list_
.end();
92 void AesDecryptor::SessionIdDecryptionKeyMap::Erase(
93 KeyList::iterator position
) {
94 DCHECK(position
->second
);
95 delete position
->second
;
96 key_list_
.erase(position
);
99 uint32
AesDecryptor::next_web_session_id_
= 1;
101 enum ClearBytesBufferSel
{
102 kSrcContainsClearBytes
,
103 kDstContainsClearBytes
106 static void CopySubsamples(const std::vector
<SubsampleEntry
>& subsamples
,
107 const ClearBytesBufferSel sel
,
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
;
115 dst
+= subsample
.clear_bytes
;
117 memcpy(dst
, src
, subsample
.cypher_bytes
);
118 src
+= subsample
.cypher_bytes
;
119 dst
+= subsample
.cypher_bytes
;
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());
131 crypto::Encryptor encryptor
;
132 if (!encryptor
.Init(key
, crypto::Encryptor::CTR
, "")) {
133 DVLOG(1) << "Could not initialize decryptor.";
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.";
144 const char* sample
= reinterpret_cast<const char*>(input
.data());
145 size_t sample_size
= static_cast<size_t>(input
.data_size());
147 DCHECK_GT(sample_size
, 0U) << "No sample data to be decrypted.";
148 if (sample_size
== 0)
151 if (input
.decrypt_config()->subsamples().empty()) {
152 std::string decrypted_text
;
153 base::StringPiece
encrypted_text(sample
, sample_size
);
154 if (!encryptor
.Decrypt(encrypted_text
, &decrypted_text
)) {
155 DVLOG(1) << "Could not decrypt data.";
159 // TODO(xhwang): Find a way to avoid this data copy.
160 return DecoderBuffer::CopyFrom(
161 reinterpret_cast<const uint8
*>(decrypted_text
.data()),
162 decrypted_text
.size());
165 const std::vector
<SubsampleEntry
>& subsamples
=
166 input
.decrypt_config()->subsamples();
168 size_t total_clear_size
= 0;
169 size_t total_encrypted_size
= 0;
170 for (size_t i
= 0; i
< subsamples
.size(); i
++) {
171 total_clear_size
+= subsamples
[i
].clear_bytes
;
172 total_encrypted_size
+= subsamples
[i
].cypher_bytes
;
173 // Check for overflow. This check is valid because *_size is unsigned.
174 DCHECK(total_clear_size
>= subsamples
[i
].clear_bytes
);
175 if (total_encrypted_size
< subsamples
[i
].cypher_bytes
)
178 size_t total_size
= total_clear_size
+ total_encrypted_size
;
179 if (total_size
< total_clear_size
|| total_size
!= sample_size
) {
180 DVLOG(1) << "Subsample sizes do not equal input size";
184 // No need to decrypt if there is no encrypted data.
185 if (total_encrypted_size
<= 0) {
186 return DecoderBuffer::CopyFrom(reinterpret_cast<const uint8
*>(sample
),
190 // The encrypted portions of all subsamples must form a contiguous block,
191 // such that an encrypted subsample that ends away from a block boundary is
192 // immediately followed by the start of the next encrypted subsample. We
193 // copy all encrypted subsamples to a contiguous buffer, decrypt them, then
194 // copy the decrypted bytes over the encrypted bytes in the output.
195 // TODO(strobe): attempt to reduce number of memory copies
196 scoped_ptr
<uint8
[]> encrypted_bytes(new uint8
[total_encrypted_size
]);
197 CopySubsamples(subsamples
, kSrcContainsClearBytes
,
198 reinterpret_cast<const uint8
*>(sample
), encrypted_bytes
.get());
200 base::StringPiece
encrypted_text(
201 reinterpret_cast<const char*>(encrypted_bytes
.get()),
202 total_encrypted_size
);
203 std::string decrypted_text
;
204 if (!encryptor
.Decrypt(encrypted_text
, &decrypted_text
)) {
205 DVLOG(1) << "Could not decrypt data.";
208 DCHECK_EQ(decrypted_text
.size(), encrypted_text
.size());
210 scoped_refptr
<DecoderBuffer
> output
= DecoderBuffer::CopyFrom(
211 reinterpret_cast<const uint8
*>(sample
), sample_size
);
212 CopySubsamples(subsamples
, kDstContainsClearBytes
,
213 reinterpret_cast<const uint8
*>(decrypted_text
.data()),
214 output
->writable_data());
218 AesDecryptor::AesDecryptor(const SessionCreatedCB
& session_created_cb
,
219 const SessionMessageCB
& session_message_cb
,
220 const SessionReadyCB
& session_ready_cb
,
221 const SessionClosedCB
& session_closed_cb
,
222 const SessionErrorCB
& session_error_cb
)
223 : session_created_cb_(session_created_cb
),
224 session_message_cb_(session_message_cb
),
225 session_ready_cb_(session_ready_cb
),
226 session_closed_cb_(session_closed_cb
),
227 session_error_cb_(session_error_cb
) {}
229 AesDecryptor::~AesDecryptor() {
233 bool AesDecryptor::CreateSession(uint32 session_id
,
234 const std::string
& content_type
,
235 const uint8
* init_data
,
236 int init_data_length
) {
237 // Validate that this is a new session.
238 DCHECK(valid_sessions_
.find(session_id
) == valid_sessions_
.end());
239 valid_sessions_
.insert(session_id
);
241 std::string
web_session_id_string(base::UintToString(next_web_session_id_
++));
243 // For now, the AesDecryptor does not care about |content_type|;
244 // just fire the event with the |init_data| as the request.
245 std::vector
<uint8
> message
;
246 if (init_data
&& init_data_length
)
247 message
.assign(init_data
, init_data
+ init_data_length
);
249 session_created_cb_
.Run(session_id
, web_session_id_string
);
250 session_message_cb_
.Run(session_id
, message
, std::string());
254 void AesDecryptor::LoadSession(uint32 session_id
,
255 const std::string
& web_session_id
) {
256 // TODO(xhwang): Change this to NOTREACHED() when blink checks for key systems
257 // that do not support loadSession. See http://crbug.com/342481
258 session_error_cb_
.Run(session_id
, MediaKeys::kUnknownError
, 0);
261 void AesDecryptor::UpdateSession(uint32 session_id
,
262 const uint8
* response
,
263 int response_length
) {
265 CHECK_GT(response_length
, 0);
266 DCHECK(valid_sessions_
.find(session_id
) != valid_sessions_
.end());
268 std::string
key_string(reinterpret_cast<const char*>(response
),
270 KeyIdAndKeyPairs keys
;
271 if (!ExtractKeysFromJWKSet(key_string
, &keys
)) {
272 session_error_cb_
.Run(session_id
, MediaKeys::kUnknownError
, 0);
276 // Make sure that at least one key was extracted.
278 session_error_cb_
.Run(session_id
, MediaKeys::kUnknownError
, 0);
282 for (KeyIdAndKeyPairs::iterator it
= keys
.begin(); it
!= keys
.end(); ++it
) {
283 if (it
->second
.length() !=
284 static_cast<size_t>(DecryptConfig::kDecryptionKeySize
)) {
285 DVLOG(1) << "Invalid key length: " << key_string
.length();
286 session_error_cb_
.Run(session_id
, MediaKeys::kUnknownError
, 0);
289 if (!AddDecryptionKey(session_id
, it
->first
, it
->second
)) {
290 session_error_cb_
.Run(session_id
, MediaKeys::kUnknownError
, 0);
296 base::AutoLock
auto_lock(new_key_cb_lock_
);
298 if (!new_audio_key_cb_
.is_null())
299 new_audio_key_cb_
.Run();
301 if (!new_video_key_cb_
.is_null())
302 new_video_key_cb_
.Run();
305 session_ready_cb_
.Run(session_id
);
308 void AesDecryptor::ReleaseSession(uint32 session_id
) {
309 // Validate that this is a reference to an active session and then forget it.
310 std::set
<uint32
>::iterator it
= valid_sessions_
.find(session_id
);
311 DCHECK(it
!= valid_sessions_
.end());
312 valid_sessions_
.erase(it
);
314 DeleteKeysForSession(session_id
);
315 session_closed_cb_
.Run(session_id
);
318 Decryptor
* AesDecryptor::GetDecryptor() {
322 void AesDecryptor::RegisterNewKeyCB(StreamType stream_type
,
323 const NewKeyCB
& new_key_cb
) {
324 base::AutoLock
auto_lock(new_key_cb_lock_
);
326 switch (stream_type
) {
328 new_audio_key_cb_
= new_key_cb
;
331 new_video_key_cb_
= new_key_cb
;
338 void AesDecryptor::Decrypt(StreamType stream_type
,
339 const scoped_refptr
<DecoderBuffer
>& encrypted
,
340 const DecryptCB
& decrypt_cb
) {
341 CHECK(encrypted
->decrypt_config());
343 scoped_refptr
<DecoderBuffer
> decrypted
;
344 // An empty iv string signals that the frame is unencrypted.
345 if (encrypted
->decrypt_config()->iv().empty()) {
346 decrypted
= DecoderBuffer::CopyFrom(encrypted
->data(),
347 encrypted
->data_size());
349 const std::string
& key_id
= encrypted
->decrypt_config()->key_id();
350 DecryptionKey
* key
= GetKey(key_id
);
352 DVLOG(1) << "Could not find a matching key for the given key ID.";
353 decrypt_cb
.Run(kNoKey
, NULL
);
357 crypto::SymmetricKey
* decryption_key
= key
->decryption_key();
358 decrypted
= DecryptData(*encrypted
.get(), decryption_key
);
359 if (!decrypted
.get()) {
360 DVLOG(1) << "Decryption failed.";
361 decrypt_cb
.Run(kError
, NULL
);
366 decrypted
->set_timestamp(encrypted
->timestamp());
367 decrypted
->set_duration(encrypted
->duration());
368 decrypt_cb
.Run(kSuccess
, decrypted
);
371 void AesDecryptor::CancelDecrypt(StreamType stream_type
) {
372 // Decrypt() calls the DecryptCB synchronously so there's nothing to cancel.
375 void AesDecryptor::InitializeAudioDecoder(const AudioDecoderConfig
& config
,
376 const DecoderInitCB
& init_cb
) {
377 // AesDecryptor does not support audio decoding.
381 void AesDecryptor::InitializeVideoDecoder(const VideoDecoderConfig
& config
,
382 const DecoderInitCB
& init_cb
) {
383 // AesDecryptor does not support video decoding.
387 void AesDecryptor::DecryptAndDecodeAudio(
388 const scoped_refptr
<DecoderBuffer
>& encrypted
,
389 const AudioDecodeCB
& audio_decode_cb
) {
390 NOTREACHED() << "AesDecryptor does not support audio decoding";
393 void AesDecryptor::DecryptAndDecodeVideo(
394 const scoped_refptr
<DecoderBuffer
>& encrypted
,
395 const VideoDecodeCB
& video_decode_cb
) {
396 NOTREACHED() << "AesDecryptor does not support video decoding";
399 void AesDecryptor::ResetDecoder(StreamType stream_type
) {
400 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
403 void AesDecryptor::DeinitializeDecoder(StreamType stream_type
) {
404 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
407 bool AesDecryptor::AddDecryptionKey(const uint32 session_id
,
408 const std::string
& key_id
,
409 const std::string
& key_string
) {
410 scoped_ptr
<DecryptionKey
> decryption_key(new DecryptionKey(key_string
));
411 if (!decryption_key
) {
412 DVLOG(1) << "Could not create key.";
416 if (!decryption_key
->Init()) {
417 DVLOG(1) << "Could not initialize decryption key.";
421 base::AutoLock
auto_lock(key_map_lock_
);
422 KeyIdToSessionKeysMap::iterator key_id_entry
= key_map_
.find(key_id
);
423 if (key_id_entry
!= key_map_
.end()) {
424 key_id_entry
->second
->Insert(session_id
, decryption_key
.Pass());
428 // |key_id| not found, so need to create new entry.
429 scoped_ptr
<SessionIdDecryptionKeyMap
> inner_map(
430 new SessionIdDecryptionKeyMap());
431 inner_map
->Insert(session_id
, decryption_key
.Pass());
432 key_map_
.add(key_id
, inner_map
.Pass());
436 AesDecryptor::DecryptionKey
* AesDecryptor::GetKey(
437 const std::string
& key_id
) const {
438 base::AutoLock
auto_lock(key_map_lock_
);
439 KeyIdToSessionKeysMap::const_iterator key_id_found
= key_map_
.find(key_id
);
440 if (key_id_found
== key_map_
.end())
443 // Return the key from the "latest" session_id entry.
444 return key_id_found
->second
->LatestDecryptionKey();
447 void AesDecryptor::DeleteKeysForSession(const uint32 session_id
) {
448 base::AutoLock
auto_lock(key_map_lock_
);
450 // Remove all keys associated with |session_id|. Since the data is optimized
451 // for access in GetKey(), we need to look at each entry in |key_map_|.
452 KeyIdToSessionKeysMap::iterator it
= key_map_
.begin();
453 while (it
!= key_map_
.end()) {
454 it
->second
->Erase(session_id
);
455 if (it
->second
->Empty()) {
456 // Need to get rid of the entry for this key_id. This will mess up the
457 // iterator, so we need to increment it first.
458 KeyIdToSessionKeysMap::iterator current
= it
;
460 key_map_
.erase(current
);
467 AesDecryptor::DecryptionKey::DecryptionKey(const std::string
& secret
)
471 AesDecryptor::DecryptionKey::~DecryptionKey() {}
473 bool AesDecryptor::DecryptionKey::Init() {
474 CHECK(!secret_
.empty());
475 decryption_key_
.reset(crypto::SymmetricKey::Import(
476 crypto::SymmetricKey::AES
, secret_
));
477 if (!decryption_key_
)