1 // Copyright (c) 2012 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/crypto/aes_decryptor.h"
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "base/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/decryptor_client.h"
18 #include "media/base/video_decoder_config.h"
19 #include "media/base/video_frame.h"
23 uint32
AesDecryptor::next_session_id_
= 1;
25 enum ClearBytesBufferSel
{
26 kSrcContainsClearBytes
,
27 kDstContainsClearBytes
30 static void CopySubsamples(const std::vector
<SubsampleEntry
>& subsamples
,
31 const ClearBytesBufferSel sel
,
34 for (size_t i
= 0; i
< subsamples
.size(); i
++) {
35 const SubsampleEntry
& subsample
= subsamples
[i
];
36 if (sel
== kSrcContainsClearBytes
) {
37 src
+= subsample
.clear_bytes
;
39 dst
+= subsample
.clear_bytes
;
41 memcpy(dst
, src
, subsample
.cypher_bytes
);
42 src
+= subsample
.cypher_bytes
;
43 dst
+= subsample
.cypher_bytes
;
47 // Decrypts |input| using |key|. Returns a DecoderBuffer with the decrypted
48 // data if decryption succeeded or NULL if decryption failed.
49 static scoped_refptr
<DecoderBuffer
> DecryptData(const DecoderBuffer
& input
,
50 crypto::SymmetricKey
* key
) {
51 CHECK(input
.GetDataSize());
52 CHECK(input
.GetDecryptConfig());
55 crypto::Encryptor encryptor
;
56 if (!encryptor
.Init(key
, crypto::Encryptor::CTR
, "")) {
57 DVLOG(1) << "Could not initialize decryptor.";
61 DCHECK_EQ(input
.GetDecryptConfig()->iv().size(),
62 static_cast<size_t>(DecryptConfig::kDecryptionKeySize
));
63 if (!encryptor
.SetCounter(input
.GetDecryptConfig()->iv())) {
64 DVLOG(1) << "Could not set counter block.";
68 const int data_offset
= input
.GetDecryptConfig()->data_offset();
70 reinterpret_cast<const char*>(input
.GetData() + data_offset
);
71 int sample_size
= input
.GetDataSize() - data_offset
;
73 if (input
.GetDecryptConfig()->subsamples().empty()) {
74 std::string decrypted_text
;
75 base::StringPiece
encrypted_text(sample
, sample_size
);
76 if (!encryptor
.Decrypt(encrypted_text
, &decrypted_text
)) {
77 DVLOG(1) << "Could not decrypt data.";
81 // TODO(xhwang): Find a way to avoid this data copy.
82 return DecoderBuffer::CopyFrom(
83 reinterpret_cast<const uint8
*>(decrypted_text
.data()),
84 decrypted_text
.size());
87 const std::vector
<SubsampleEntry
>& subsamples
=
88 input
.GetDecryptConfig()->subsamples();
90 int total_clear_size
= 0;
91 int total_encrypted_size
= 0;
92 for (size_t i
= 0; i
< subsamples
.size(); i
++) {
93 total_clear_size
+= subsamples
[i
].clear_bytes
;
94 total_encrypted_size
+= subsamples
[i
].cypher_bytes
;
96 if (total_clear_size
+ total_encrypted_size
!= sample_size
) {
97 DVLOG(1) << "Subsample sizes do not equal input size";
101 // The encrypted portions of all subsamples must form a contiguous block,
102 // such that an encrypted subsample that ends away from a block boundary is
103 // immediately followed by the start of the next encrypted subsample. We
104 // copy all encrypted subsamples to a contiguous buffer, decrypt them, then
105 // copy the decrypted bytes over the encrypted bytes in the output.
106 // TODO(strobe): attempt to reduce number of memory copies
107 scoped_array
<uint8
> encrypted_bytes(new uint8
[total_encrypted_size
]);
108 CopySubsamples(subsamples
, kSrcContainsClearBytes
,
109 reinterpret_cast<const uint8
*>(sample
), encrypted_bytes
.get());
111 base::StringPiece
encrypted_text(
112 reinterpret_cast<const char*>(encrypted_bytes
.get()),
113 total_encrypted_size
);
114 std::string decrypted_text
;
115 if (!encryptor
.Decrypt(encrypted_text
, &decrypted_text
)) {
116 DVLOG(1) << "Could not decrypt data.";
120 scoped_refptr
<DecoderBuffer
> output
= DecoderBuffer::CopyFrom(
121 reinterpret_cast<const uint8
*>(sample
), sample_size
);
122 CopySubsamples(subsamples
, kDstContainsClearBytes
,
123 reinterpret_cast<const uint8
*>(decrypted_text
.data()),
124 output
->GetWritableData());
128 AesDecryptor::AesDecryptor(DecryptorClient
* client
)
132 AesDecryptor::~AesDecryptor() {
133 STLDeleteValues(&key_map_
);
136 bool AesDecryptor::GenerateKeyRequest(const std::string
& key_system
,
137 const std::string
& type
,
138 const uint8
* init_data
,
139 int init_data_length
) {
140 std::string
session_id_string(base::UintToString(next_session_id_
++));
142 // For now, the AesDecryptor does not care about |key_system| and |type|;
143 // just fire the event with the |init_data| as the request.
144 int message_length
= init_data_length
;
145 scoped_array
<uint8
> message(new uint8
[message_length
]);
146 memcpy(message
.get(), init_data
, message_length
);
148 client_
->KeyMessage(key_system
, session_id_string
,
149 message
.Pass(), message_length
, "");
153 void AesDecryptor::AddKey(const std::string
& key_system
,
156 const uint8
* init_data
,
157 int init_data_length
,
158 const std::string
& session_id
) {
160 CHECK_GT(key_length
, 0);
162 // TODO(xhwang): Add |session_id| check after we figure out how:
163 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=16550
164 if (key_length
!= DecryptConfig::kDecryptionKeySize
) {
165 DVLOG(1) << "Invalid key length: " << key_length
;
166 client_
->KeyError(key_system
, session_id
, Decryptor::kUnknownError
, 0);
170 // TODO(xhwang): Fix the decryptor to accept no |init_data|. See
171 // http://crbug.com/123265. Until then, ensure a non-empty value is passed.
172 static const uint8 kDummyInitData
[1] = { 0 };
174 init_data
= kDummyInitData
;
175 init_data_length
= arraysize(kDummyInitData
);
178 // TODO(xhwang): For now, use |init_data| for key ID. Make this more spec
179 // compliant later (http://crbug.com/123262, http://crbug.com/123265).
180 std::string
key_id_string(reinterpret_cast<const char*>(init_data
),
182 std::string
key_string(reinterpret_cast<const char*>(key
) , key_length
);
183 scoped_ptr
<DecryptionKey
> decryption_key(new DecryptionKey(key_string
));
184 if (!decryption_key
.get()) {
185 DVLOG(1) << "Could not create key.";
186 client_
->KeyError(key_system
, session_id
, Decryptor::kUnknownError
, 0);
190 if (!decryption_key
->Init()) {
191 DVLOG(1) << "Could not initialize decryption key.";
192 client_
->KeyError(key_system
, session_id
, Decryptor::kUnknownError
, 0);
196 SetKey(key_id_string
, decryption_key
.Pass());
197 client_
->KeyAdded(key_system
, session_id
);
200 void AesDecryptor::CancelKeyRequest(const std::string
& key_system
,
201 const std::string
& session_id
) {
204 void AesDecryptor::Decrypt(StreamType stream_type
,
205 const scoped_refptr
<DecoderBuffer
>& encrypted
,
206 const DecryptCB
& decrypt_cb
) {
207 CHECK(encrypted
->GetDecryptConfig());
208 const std::string
& key_id
= encrypted
->GetDecryptConfig()->key_id();
210 DecryptionKey
* key
= GetKey(key_id
);
212 DVLOG(1) << "Could not find a matching key for the given key ID.";
213 decrypt_cb
.Run(kNoKey
, NULL
);
217 scoped_refptr
<DecoderBuffer
> decrypted
;
218 // An empty iv string signals that the frame is unencrypted.
219 if (encrypted
->GetDecryptConfig()->iv().empty()) {
220 int data_offset
= encrypted
->GetDecryptConfig()->data_offset();
221 decrypted
= DecoderBuffer::CopyFrom(encrypted
->GetData() + data_offset
,
222 encrypted
->GetDataSize() - data_offset
);
224 crypto::SymmetricKey
* decryption_key
= key
->decryption_key();
225 decrypted
= DecryptData(*encrypted
, decryption_key
);
227 DVLOG(1) << "Decryption failed.";
228 decrypt_cb
.Run(kError
, NULL
);
233 decrypted
->SetTimestamp(encrypted
->GetTimestamp());
234 decrypted
->SetDuration(encrypted
->GetDuration());
235 decrypt_cb
.Run(kSuccess
, decrypted
);
238 void AesDecryptor::CancelDecrypt(StreamType stream_type
) {
239 // Decrypt() calls the DecryptCB synchronously so there's nothing to cancel.
242 void AesDecryptor::InitializeAudioDecoder(scoped_ptr
<AudioDecoderConfig
> config
,
243 const DecoderInitCB
& init_cb
,
244 const KeyAddedCB
& key_added_cb
) {
245 // AesDecryptor does not support audio decoding.
249 void AesDecryptor::InitializeVideoDecoder(scoped_ptr
<VideoDecoderConfig
> config
,
250 const DecoderInitCB
& init_cb
,
251 const KeyAddedCB
& key_added_cb
) {
252 // AesDecryptor does not support video decoding.
256 void AesDecryptor::DecryptAndDecodeAudio(
257 const scoped_refptr
<DecoderBuffer
>& encrypted
,
258 const AudioDecodeCB
& audio_decode_cb
) {
259 NOTREACHED() << "AesDecryptor does not support audio decoding";
262 void AesDecryptor::DecryptAndDecodeVideo(
263 const scoped_refptr
<DecoderBuffer
>& encrypted
,
264 const VideoDecodeCB
& video_decode_cb
) {
265 NOTREACHED() << "AesDecryptor does not support video decoding";
268 void AesDecryptor::ResetDecoder(StreamType stream_type
) {
269 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
272 void AesDecryptor::DeinitializeDecoder(StreamType stream_type
) {
273 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
276 void AesDecryptor::SetKey(const std::string
& key_id
,
277 scoped_ptr
<DecryptionKey
> decryption_key
) {
278 base::AutoLock
auto_lock(key_map_lock_
);
279 KeyMap::iterator found
= key_map_
.find(key_id
);
280 if (found
!= key_map_
.end()) {
281 delete found
->second
;
282 key_map_
.erase(found
);
284 key_map_
[key_id
] = decryption_key
.release();
287 AesDecryptor::DecryptionKey
* AesDecryptor::GetKey(
288 const std::string
& key_id
) const {
289 base::AutoLock
auto_lock(key_map_lock_
);
290 KeyMap::const_iterator found
= key_map_
.find(key_id
);
291 if (found
== key_map_
.end())
294 return found
->second
;
297 AesDecryptor::DecryptionKey::DecryptionKey(const std::string
& secret
)
301 AesDecryptor::DecryptionKey::~DecryptionKey() {}
303 bool AesDecryptor::DecryptionKey::Init() {
304 CHECK(!secret_
.empty());
305 decryption_key_
.reset(crypto::SymmetricKey::Import(
306 crypto::SymmetricKey::AES
, secret_
));
307 if (!decryption_key_
.get())