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"
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "crypto/encryptor.h"
13 #include "crypto/symmetric_key.h"
14 #include "media/base/audio_decoder_config.h"
15 #include "media/base/decoder_buffer.h"
16 #include "media/base/decrypt_config.h"
17 #include "media/base/video_decoder_config.h"
18 #include "media/base/video_frame.h"
22 uint32
AesDecryptor::next_session_id_
= 1;
24 enum ClearBytesBufferSel
{
25 kSrcContainsClearBytes
,
26 kDstContainsClearBytes
29 static void CopySubsamples(const std::vector
<SubsampleEntry
>& subsamples
,
30 const ClearBytesBufferSel sel
,
33 for (size_t i
= 0; i
< subsamples
.size(); i
++) {
34 const SubsampleEntry
& subsample
= subsamples
[i
];
35 if (sel
== kSrcContainsClearBytes
) {
36 src
+= subsample
.clear_bytes
;
38 dst
+= subsample
.clear_bytes
;
40 memcpy(dst
, src
, subsample
.cypher_bytes
);
41 src
+= subsample
.cypher_bytes
;
42 dst
+= subsample
.cypher_bytes
;
46 // Decrypts |input| using |key|. Returns a DecoderBuffer with the decrypted
47 // data if decryption succeeded or NULL if decryption failed.
48 static scoped_refptr
<DecoderBuffer
> DecryptData(const DecoderBuffer
& input
,
49 crypto::SymmetricKey
* key
) {
50 CHECK(input
.data_size());
51 CHECK(input
.decrypt_config());
54 crypto::Encryptor encryptor
;
55 if (!encryptor
.Init(key
, crypto::Encryptor::CTR
, "")) {
56 DVLOG(1) << "Could not initialize decryptor.";
60 DCHECK_EQ(input
.decrypt_config()->iv().size(),
61 static_cast<size_t>(DecryptConfig::kDecryptionKeySize
));
62 if (!encryptor
.SetCounter(input
.decrypt_config()->iv())) {
63 DVLOG(1) << "Could not set counter block.";
67 const int data_offset
= input
.decrypt_config()->data_offset();
69 reinterpret_cast<const char*>(input
.data() + data_offset
);
70 int sample_size
= input
.data_size() - data_offset
;
72 DCHECK_GT(sample_size
, 0) << "No sample data to be decrypted.";
76 if (input
.decrypt_config()->subsamples().empty()) {
77 std::string decrypted_text
;
78 base::StringPiece
encrypted_text(sample
, sample_size
);
79 if (!encryptor
.Decrypt(encrypted_text
, &decrypted_text
)) {
80 DVLOG(1) << "Could not decrypt data.";
84 // TODO(xhwang): Find a way to avoid this data copy.
85 return DecoderBuffer::CopyFrom(
86 reinterpret_cast<const uint8
*>(decrypted_text
.data()),
87 decrypted_text
.size());
90 const std::vector
<SubsampleEntry
>& subsamples
=
91 input
.decrypt_config()->subsamples();
93 int total_clear_size
= 0;
94 int total_encrypted_size
= 0;
95 for (size_t i
= 0; i
< subsamples
.size(); i
++) {
96 total_clear_size
+= subsamples
[i
].clear_bytes
;
97 total_encrypted_size
+= subsamples
[i
].cypher_bytes
;
99 if (total_clear_size
+ total_encrypted_size
!= sample_size
) {
100 DVLOG(1) << "Subsample sizes do not equal input size";
104 // No need to decrypt if there is no encrypted data.
105 if (total_encrypted_size
<= 0) {
106 return DecoderBuffer::CopyFrom(reinterpret_cast<const uint8
*>(sample
),
110 // The encrypted portions of all subsamples must form a contiguous block,
111 // such that an encrypted subsample that ends away from a block boundary is
112 // immediately followed by the start of the next encrypted subsample. We
113 // copy all encrypted subsamples to a contiguous buffer, decrypt them, then
114 // copy the decrypted bytes over the encrypted bytes in the output.
115 // TODO(strobe): attempt to reduce number of memory copies
116 scoped_ptr
<uint8
[]> encrypted_bytes(new uint8
[total_encrypted_size
]);
117 CopySubsamples(subsamples
, kSrcContainsClearBytes
,
118 reinterpret_cast<const uint8
*>(sample
), encrypted_bytes
.get());
120 base::StringPiece
encrypted_text(
121 reinterpret_cast<const char*>(encrypted_bytes
.get()),
122 total_encrypted_size
);
123 std::string decrypted_text
;
124 if (!encryptor
.Decrypt(encrypted_text
, &decrypted_text
)) {
125 DVLOG(1) << "Could not decrypt data.";
128 DCHECK_EQ(decrypted_text
.size(), encrypted_text
.size());
130 scoped_refptr
<DecoderBuffer
> output
= DecoderBuffer::CopyFrom(
131 reinterpret_cast<const uint8
*>(sample
), sample_size
);
132 CopySubsamples(subsamples
, kDstContainsClearBytes
,
133 reinterpret_cast<const uint8
*>(decrypted_text
.data()),
134 output
->writable_data());
138 AesDecryptor::AesDecryptor(const KeyAddedCB
& key_added_cb
,
139 const KeyErrorCB
& key_error_cb
,
140 const KeyMessageCB
& key_message_cb
)
141 : key_added_cb_(key_added_cb
),
142 key_error_cb_(key_error_cb
),
143 key_message_cb_(key_message_cb
) {
146 AesDecryptor::~AesDecryptor() {
147 STLDeleteValues(&key_map_
);
150 bool AesDecryptor::GenerateKeyRequest(const std::string
& type
,
151 const uint8
* init_data
,
152 int init_data_length
) {
153 std::string
session_id_string(base::UintToString(next_session_id_
++));
155 // For now, the AesDecryptor does not care about |type|;
156 // just fire the event with the |init_data| as the request.
157 std::vector
<uint8
> message
;
158 if (init_data
&& init_data_length
)
159 message
.assign(init_data
, init_data
+ init_data_length
);
161 key_message_cb_
.Run(session_id_string
, message
, std::string());
165 void AesDecryptor::AddKey(const uint8
* key
,
167 const uint8
* init_data
,
168 int init_data_length
,
169 const std::string
& session_id
) {
171 CHECK_GT(key_length
, 0);
173 // TODO(xhwang): Add |session_id| check after we figure out how:
174 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=16550
175 if (key_length
!= DecryptConfig::kDecryptionKeySize
) {
176 DVLOG(1) << "Invalid key length: " << key_length
;
177 key_error_cb_
.Run(session_id
, MediaKeys::kUnknownError
, 0);
181 // TODO(xhwang): Fix the decryptor to accept no |init_data|. See
182 // http://crbug.com/123265. Until then, ensure a non-empty value is passed.
183 static const uint8 kDummyInitData
[1] = { 0 };
185 init_data
= kDummyInitData
;
186 init_data_length
= arraysize(kDummyInitData
);
189 // TODO(xhwang): For now, use |init_data| for key ID. Make this more spec
190 // compliant later (http://crbug.com/123262, http://crbug.com/123265).
191 std::string
key_id_string(reinterpret_cast<const char*>(init_data
),
193 std::string
key_string(reinterpret_cast<const char*>(key
) , key_length
);
194 scoped_ptr
<DecryptionKey
> decryption_key(new DecryptionKey(key_string
));
195 if (!decryption_key
) {
196 DVLOG(1) << "Could not create key.";
197 key_error_cb_
.Run(session_id
, MediaKeys::kUnknownError
, 0);
201 if (!decryption_key
->Init()) {
202 DVLOG(1) << "Could not initialize decryption key.";
203 key_error_cb_
.Run(session_id
, MediaKeys::kUnknownError
, 0);
207 SetKey(key_id_string
, decryption_key
.Pass());
209 if (!new_audio_key_cb_
.is_null())
210 new_audio_key_cb_
.Run();
212 if (!new_video_key_cb_
.is_null())
213 new_video_key_cb_
.Run();
215 key_added_cb_
.Run(session_id
);
218 void AesDecryptor::CancelKeyRequest(const std::string
& session_id
) {
221 Decryptor
* AesDecryptor::GetDecryptor() {
225 void AesDecryptor::RegisterNewKeyCB(StreamType stream_type
,
226 const NewKeyCB
& new_key_cb
) {
227 switch (stream_type
) {
229 new_audio_key_cb_
= new_key_cb
;
232 new_video_key_cb_
= new_key_cb
;
239 void AesDecryptor::Decrypt(StreamType stream_type
,
240 const scoped_refptr
<DecoderBuffer
>& encrypted
,
241 const DecryptCB
& decrypt_cb
) {
242 CHECK(encrypted
->decrypt_config());
244 scoped_refptr
<DecoderBuffer
> decrypted
;
245 // An empty iv string signals that the frame is unencrypted.
246 if (encrypted
->decrypt_config()->iv().empty()) {
247 int data_offset
= encrypted
->decrypt_config()->data_offset();
248 decrypted
= DecoderBuffer::CopyFrom(encrypted
->data() + data_offset
,
249 encrypted
->data_size() - data_offset
);
251 const std::string
& key_id
= encrypted
->decrypt_config()->key_id();
252 DecryptionKey
* key
= GetKey(key_id
);
254 DVLOG(1) << "Could not find a matching key for the given key ID.";
255 decrypt_cb
.Run(kNoKey
, NULL
);
259 crypto::SymmetricKey
* decryption_key
= key
->decryption_key();
260 decrypted
= DecryptData(*encrypted
.get(), decryption_key
);
261 if (!decrypted
.get()) {
262 DVLOG(1) << "Decryption failed.";
263 decrypt_cb
.Run(kError
, NULL
);
268 decrypted
->set_timestamp(encrypted
->timestamp());
269 decrypted
->set_duration(encrypted
->duration());
270 decrypt_cb
.Run(kSuccess
, decrypted
);
273 void AesDecryptor::CancelDecrypt(StreamType stream_type
) {
274 // Decrypt() calls the DecryptCB synchronously so there's nothing to cancel.
277 void AesDecryptor::InitializeAudioDecoder(const AudioDecoderConfig
& config
,
278 const DecoderInitCB
& init_cb
) {
279 // AesDecryptor does not support audio decoding.
283 void AesDecryptor::InitializeVideoDecoder(const VideoDecoderConfig
& config
,
284 const DecoderInitCB
& init_cb
) {
285 // AesDecryptor does not support video decoding.
289 void AesDecryptor::DecryptAndDecodeAudio(
290 const scoped_refptr
<DecoderBuffer
>& encrypted
,
291 const AudioDecodeCB
& audio_decode_cb
) {
292 NOTREACHED() << "AesDecryptor does not support audio decoding";
295 void AesDecryptor::DecryptAndDecodeVideo(
296 const scoped_refptr
<DecoderBuffer
>& encrypted
,
297 const VideoDecodeCB
& video_decode_cb
) {
298 NOTREACHED() << "AesDecryptor does not support video decoding";
301 void AesDecryptor::ResetDecoder(StreamType stream_type
) {
302 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
305 void AesDecryptor::DeinitializeDecoder(StreamType stream_type
) {
306 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
309 void AesDecryptor::SetKey(const std::string
& key_id
,
310 scoped_ptr
<DecryptionKey
> decryption_key
) {
311 base::AutoLock
auto_lock(key_map_lock_
);
312 KeyMap::iterator found
= key_map_
.find(key_id
);
313 if (found
!= key_map_
.end()) {
314 delete found
->second
;
315 key_map_
.erase(found
);
317 key_map_
[key_id
] = decryption_key
.release();
320 AesDecryptor::DecryptionKey
* AesDecryptor::GetKey(
321 const std::string
& key_id
) const {
322 base::AutoLock
auto_lock(key_map_lock_
);
323 KeyMap::const_iterator found
= key_map_
.find(key_id
);
324 if (found
== key_map_
.end())
327 return found
->second
;
330 AesDecryptor::DecryptionKey::DecryptionKey(const std::string
& secret
)
334 AesDecryptor::DecryptionKey::~DecryptionKey() {}
336 bool AesDecryptor::DecryptionKey::Init() {
337 CHECK(!secret_
.empty());
338 decryption_key_
.reset(crypto::SymmetricKey::Import(
339 crypto::SymmetricKey::AES
, secret_
));
340 if (!decryption_key_
)