Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(370)

Side by Side Diff: media/crypto/aes_decryptor.cc

Issue 22362007: Relocate last remnants of webkit/renderer/media code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Make chromeos crypto dep explicit. Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/crypto/aes_decryptor.h ('k') | media/crypto/aes_decryptor_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "media/crypto/aes_decryptor.h"
6
7 #include <vector>
8
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"
19
20 namespace media {
21
22 uint32 AesDecryptor::next_session_id_ = 1;
23
24 enum ClearBytesBufferSel {
25 kSrcContainsClearBytes,
26 kDstContainsClearBytes
27 };
28
29 static void CopySubsamples(const std::vector<SubsampleEntry>& subsamples,
30 const ClearBytesBufferSel sel,
31 const uint8* src,
32 uint8* dst) {
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;
37 } else {
38 dst += subsample.clear_bytes;
39 }
40 memcpy(dst, src, subsample.cypher_bytes);
41 src += subsample.cypher_bytes;
42 dst += subsample.cypher_bytes;
43 }
44 }
45
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());
52 CHECK(key);
53
54 crypto::Encryptor encryptor;
55 if (!encryptor.Init(key, crypto::Encryptor::CTR, "")) {
56 DVLOG(1) << "Could not initialize decryptor.";
57 return NULL;
58 }
59
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.";
64 return NULL;
65 }
66
67 const int data_offset = input.decrypt_config()->data_offset();
68 const char* sample =
69 reinterpret_cast<const char*>(input.data() + data_offset);
70 int sample_size = input.data_size() - data_offset;
71
72 DCHECK_GT(sample_size, 0) << "No sample data to be decrypted.";
73 if (sample_size <= 0)
74 return NULL;
75
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.";
81 return NULL;
82 }
83
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());
88 }
89
90 const std::vector<SubsampleEntry>& subsamples =
91 input.decrypt_config()->subsamples();
92
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;
98 }
99 if (total_clear_size + total_encrypted_size != sample_size) {
100 DVLOG(1) << "Subsample sizes do not equal input size";
101 return NULL;
102 }
103
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),
107 sample_size);
108 }
109
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());
119
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.";
126 return NULL;
127 }
128 DCHECK_EQ(decrypted_text.size(), encrypted_text.size());
129
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());
135 return output;
136 }
137
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) {
144 }
145
146 AesDecryptor::~AesDecryptor() {
147 STLDeleteValues(&key_map_);
148 }
149
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_++));
154
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);
160
161 key_message_cb_.Run(session_id_string, message, std::string());
162 return true;
163 }
164
165 void AesDecryptor::AddKey(const uint8* key,
166 int key_length,
167 const uint8* init_data,
168 int init_data_length,
169 const std::string& session_id) {
170 CHECK(key);
171 CHECK_GT(key_length, 0);
172
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);
178 return;
179 }
180
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 };
184 if (!init_data) {
185 init_data = kDummyInitData;
186 init_data_length = arraysize(kDummyInitData);
187 }
188
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),
192 init_data_length);
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);
198 return;
199 }
200
201 if (!decryption_key->Init()) {
202 DVLOG(1) << "Could not initialize decryption key.";
203 key_error_cb_.Run(session_id, MediaKeys::kUnknownError, 0);
204 return;
205 }
206
207 SetKey(key_id_string, decryption_key.Pass());
208
209 if (!new_audio_key_cb_.is_null())
210 new_audio_key_cb_.Run();
211
212 if (!new_video_key_cb_.is_null())
213 new_video_key_cb_.Run();
214
215 key_added_cb_.Run(session_id);
216 }
217
218 void AesDecryptor::CancelKeyRequest(const std::string& session_id) {
219 }
220
221 Decryptor* AesDecryptor::GetDecryptor() {
222 return this;
223 }
224
225 void AesDecryptor::RegisterNewKeyCB(StreamType stream_type,
226 const NewKeyCB& new_key_cb) {
227 switch (stream_type) {
228 case kAudio:
229 new_audio_key_cb_ = new_key_cb;
230 break;
231 case kVideo:
232 new_video_key_cb_ = new_key_cb;
233 break;
234 default:
235 NOTREACHED();
236 }
237 }
238
239 void AesDecryptor::Decrypt(StreamType stream_type,
240 const scoped_refptr<DecoderBuffer>& encrypted,
241 const DecryptCB& decrypt_cb) {
242 CHECK(encrypted->decrypt_config());
243
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);
250 } else {
251 const std::string& key_id = encrypted->decrypt_config()->key_id();
252 DecryptionKey* key = GetKey(key_id);
253 if (!key) {
254 DVLOG(1) << "Could not find a matching key for the given key ID.";
255 decrypt_cb.Run(kNoKey, NULL);
256 return;
257 }
258
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);
264 return;
265 }
266 }
267
268 decrypted->set_timestamp(encrypted->timestamp());
269 decrypted->set_duration(encrypted->duration());
270 decrypt_cb.Run(kSuccess, decrypted);
271 }
272
273 void AesDecryptor::CancelDecrypt(StreamType stream_type) {
274 // Decrypt() calls the DecryptCB synchronously so there's nothing to cancel.
275 }
276
277 void AesDecryptor::InitializeAudioDecoder(const AudioDecoderConfig& config,
278 const DecoderInitCB& init_cb) {
279 // AesDecryptor does not support audio decoding.
280 init_cb.Run(false);
281 }
282
283 void AesDecryptor::InitializeVideoDecoder(const VideoDecoderConfig& config,
284 const DecoderInitCB& init_cb) {
285 // AesDecryptor does not support video decoding.
286 init_cb.Run(false);
287 }
288
289 void AesDecryptor::DecryptAndDecodeAudio(
290 const scoped_refptr<DecoderBuffer>& encrypted,
291 const AudioDecodeCB& audio_decode_cb) {
292 NOTREACHED() << "AesDecryptor does not support audio decoding";
293 }
294
295 void AesDecryptor::DecryptAndDecodeVideo(
296 const scoped_refptr<DecoderBuffer>& encrypted,
297 const VideoDecodeCB& video_decode_cb) {
298 NOTREACHED() << "AesDecryptor does not support video decoding";
299 }
300
301 void AesDecryptor::ResetDecoder(StreamType stream_type) {
302 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
303 }
304
305 void AesDecryptor::DeinitializeDecoder(StreamType stream_type) {
306 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
307 }
308
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);
316 }
317 key_map_[key_id] = decryption_key.release();
318 }
319
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())
325 return NULL;
326
327 return found->second;
328 }
329
330 AesDecryptor::DecryptionKey::DecryptionKey(const std::string& secret)
331 : secret_(secret) {
332 }
333
334 AesDecryptor::DecryptionKey::~DecryptionKey() {}
335
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_)
341 return false;
342 return true;
343 }
344
345 } // namespace media
OLDNEW
« no previous file with comments | « media/crypto/aes_decryptor.h ('k') | media/crypto/aes_decryptor_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698