OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/crypto/aes_decryptor.h" | 5 #include "media/crypto/aes_decryptor.h" |
6 | 6 |
7 #include <vector> | |
8 | |
7 #include "base/logging.h" | 9 #include "base/logging.h" |
8 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
9 #include "base/string_number_conversions.h" | 11 #include "base/string_number_conversions.h" |
10 #include "crypto/encryptor.h" | 12 #include "crypto/encryptor.h" |
11 #include "crypto/hmac.h" | 13 #include "crypto/hmac.h" |
12 #include "crypto/symmetric_key.h" | 14 #include "crypto/symmetric_key.h" |
13 #include "media/base/decoder_buffer.h" | 15 #include "media/base/decoder_buffer.h" |
14 #include "media/base/decrypt_config.h" | 16 #include "media/base/decrypt_config.h" |
15 #include "media/base/decryptor_client.h" | 17 #include "media/base/decryptor_client.h" |
16 | 18 |
19 using crypto::SymmetricKey; | |
20 | |
Ryan Sleevi
2012/07/30 06:52:50
FWIW, please see https://groups.google.com/a/chrom
xhwang
2012/07/30 16:22:30
Thanks for the info. Personally I think either way
| |
17 namespace media { | 21 namespace media { |
18 | 22 |
19 // The size is from the WebM encrypted specification. Current encrypted WebM | 23 // The size is from the WebM encrypted specification. Current encrypted WebM |
20 // request for comments specification is here | 24 // request for comments specification is here |
21 // http://wiki.webmproject.org/encryption/webm-encryption-rfc | 25 // http://wiki.webmproject.org/encryption/webm-encryption-rfc |
22 static const int kWebmSha1DigestSize = 20; | 26 static const int kWebmSha1DigestSize = 20; |
23 static const char kWebmHmacSeed[] = "hmac-key"; | 27 static const char kWebmHmacSeed[] = "hmac-key"; |
24 static const char kWebmEncryptionSeed[] = "encryption-key"; | 28 static const char kWebmEncryptionSeed[] = "encryption-key"; |
25 | 29 |
26 uint32 AesDecryptor::next_session_id_ = 1; | 30 uint32 AesDecryptor::next_session_id_ = 1; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
77 | 81 |
78 base::StringPiece data_to_check( | 82 base::StringPiece data_to_check( |
79 reinterpret_cast<const char*>(input.GetData()), input.GetDataSize()); | 83 reinterpret_cast<const char*>(input.GetData()), input.GetDataSize()); |
80 | 84 |
81 return hmac.VerifyTruncated(data_to_check, | 85 return hmac.VerifyTruncated(data_to_check, |
82 input.GetDecryptConfig()->checksum()); | 86 input.GetDecryptConfig()->checksum()); |
83 } | 87 } |
84 | 88 |
85 enum ClearBytesBufferSel { | 89 enum ClearBytesBufferSel { |
86 kSrcContainsClearBytes, | 90 kSrcContainsClearBytes, |
87 kDstContainsClearBytes, | 91 kDstContainsClearBytes |
88 }; | 92 }; |
89 | 93 |
90 static void CopySubsamples(const std::vector<SubsampleEntry>& subsamples, | 94 static void CopySubsamples(const std::vector<SubsampleEntry>& subsamples, |
91 const ClearBytesBufferSel sel, | 95 const ClearBytesBufferSel sel, |
92 const uint8* src, | 96 const uint8* src, |
93 uint8* dst) { | 97 uint8* dst) { |
94 for (size_t i = 0; i < subsamples.size(); i++) { | 98 for (size_t i = 0; i < subsamples.size(); i++) { |
95 const SubsampleEntry& subsample = subsamples[i]; | 99 const SubsampleEntry& subsample = subsamples[i]; |
96 if (sel == kSrcContainsClearBytes) { | 100 if (sel == kSrcContainsClearBytes) { |
97 src += subsample.clear_bytes; | 101 src += subsample.clear_bytes; |
98 } else { | 102 } else { |
99 dst += subsample.clear_bytes; | 103 dst += subsample.clear_bytes; |
100 } | 104 } |
101 memcpy(dst, src, subsample.cypher_bytes); | 105 memcpy(dst, src, subsample.cypher_bytes); |
102 src += subsample.cypher_bytes; | 106 src += subsample.cypher_bytes; |
103 dst += subsample.cypher_bytes; | 107 dst += subsample.cypher_bytes; |
104 } | 108 } |
105 } | 109 } |
106 | 110 |
107 // Decrypts |input| using |key|. Returns a DecoderBuffer with the decrypted | 111 // Decrypts |input| using |key|. Returns a DecoderBuffer with the decrypted |
108 // data if decryption succeeded or NULL if decryption failed. | 112 // data if decryption succeeded or NULL if decryption failed. |
109 static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input, | 113 static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input, |
110 crypto::SymmetricKey* key) { | 114 SymmetricKey* key) { |
111 CHECK(input.GetDataSize()); | 115 CHECK(input.GetDataSize()); |
112 CHECK(input.GetDecryptConfig()); | 116 CHECK(input.GetDecryptConfig()); |
113 CHECK(key); | 117 CHECK(key); |
114 | 118 |
115 crypto::Encryptor encryptor; | 119 crypto::Encryptor encryptor; |
116 if (!encryptor.Init(key, crypto::Encryptor::CTR, "")) { | 120 if (!encryptor.Init(key, crypto::Encryptor::CTR, "")) { |
117 DVLOG(1) << "Could not initialize decryptor."; | 121 DVLOG(1) << "Could not initialize decryptor."; |
118 return NULL; | 122 return NULL; |
119 } | 123 } |
120 | 124 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 client_->KeyError(key_system, session_id, Decryptor::kUnknownError, 0); | 247 client_->KeyError(key_system, session_id, Decryptor::kUnknownError, 0); |
244 return; | 248 return; |
245 } | 249 } |
246 | 250 |
247 if (!decryption_key->Init()) { | 251 if (!decryption_key->Init()) { |
248 DVLOG(1) << "Could not initialize decryption key."; | 252 DVLOG(1) << "Could not initialize decryption key."; |
249 client_->KeyError(key_system, session_id, Decryptor::kUnknownError, 0); | 253 client_->KeyError(key_system, session_id, Decryptor::kUnknownError, 0); |
250 return; | 254 return; |
251 } | 255 } |
252 | 256 |
253 { | 257 SetKey(key_id_string, decryption_key.Pass()); |
254 base::AutoLock auto_lock(key_map_lock_); | |
255 KeyMap::iterator found = key_map_.find(key_id_string); | |
256 if (found != key_map_.end()) { | |
257 delete found->second; | |
258 key_map_.erase(found); | |
259 } | |
260 key_map_[key_id_string] = decryption_key.release(); | |
261 } | |
262 | |
263 client_->KeyAdded(key_system, session_id); | 258 client_->KeyAdded(key_system, session_id); |
264 } | 259 } |
265 | 260 |
266 void AesDecryptor::CancelKeyRequest(const std::string& key_system, | 261 void AesDecryptor::CancelKeyRequest(const std::string& key_system, |
267 const std::string& session_id) { | 262 const std::string& session_id) { |
268 } | 263 } |
269 | 264 |
270 void AesDecryptor::Decrypt(const scoped_refptr<DecoderBuffer>& encrypted, | 265 void AesDecryptor::Decrypt(const scoped_refptr<DecoderBuffer>& encrypted, |
271 const DecryptCB& decrypt_cb) { | 266 const DecryptCB& decrypt_cb) { |
272 CHECK(encrypted->GetDecryptConfig()); | 267 CHECK(encrypted->GetDecryptConfig()); |
273 const std::string& key_id = encrypted->GetDecryptConfig()->key_id(); | 268 const std::string& key_id = encrypted->GetDecryptConfig()->key_id(); |
274 | 269 |
275 DecryptionKey* key = NULL; | 270 DecryptionKey* key = GetKey(key_id); |
276 { | |
277 base::AutoLock auto_lock(key_map_lock_); | |
278 KeyMap::const_iterator found = key_map_.find(key_id); | |
279 if (found != key_map_.end()) | |
280 key = found->second; | |
281 } | |
282 | |
283 if (!key) { | 271 if (!key) { |
284 // TODO(fgalligan): Fire a need_key event here and add a test. | 272 // TODO(xhwang): Fire a need_key event here and add a test. |
285 DVLOG(1) << "Could not find a matching key for given key ID."; | 273 DVLOG(1) << "Could not find a matching key for the given key ID."; |
286 decrypt_cb.Run(kError, NULL); | 274 decrypt_cb.Run(kError, NULL); |
287 return; | 275 return; |
288 } | 276 } |
289 | 277 |
290 int checksum_size = encrypted->GetDecryptConfig()->checksum().size(); | 278 int checksum_size = encrypted->GetDecryptConfig()->checksum().size(); |
291 // According to the WebM encrypted specification, it is an open question | 279 // According to the WebM encrypted specification, it is an open question |
292 // what should happen when a frame fails the integrity check. | 280 // what should happen when a frame fails the integrity check. |
293 // http://wiki.webmproject.org/encryption/webm-encryption-rfc | 281 // http://wiki.webmproject.org/encryption/webm-encryption-rfc |
294 if (checksum_size > 0 && | 282 if (checksum_size > 0 && |
295 !key->hmac_key().empty() && | 283 !key->hmac_key().empty() && |
296 !CheckData(*encrypted, key->hmac_key())) { | 284 !CheckData(*encrypted, key->hmac_key())) { |
297 DVLOG(1) << "Integrity check failed."; | 285 DVLOG(1) << "Integrity check failed."; |
298 decrypt_cb.Run(kError, NULL); | 286 decrypt_cb.Run(kError, NULL); |
299 return; | 287 return; |
300 } | 288 } |
301 | 289 |
302 // TODO(strobe): Currently, presence of checksum is used to indicate the use | 290 // TODO(strobe): Currently, presence of checksum is used to indicate the use |
303 // of normal or WebM decryption keys. Consider a more explicit signaling | 291 // of normal or WebM decryption keys. Consider a more explicit signaling |
304 // mechanism and the removal of the webm_decryption_key member. | 292 // mechanism and the removal of the webm_decryption_key member. |
305 crypto::SymmetricKey* decryption_key = (checksum_size > 0) ? | 293 SymmetricKey* decryption_key = (checksum_size > 0) ? |
306 key->webm_decryption_key() : key->decryption_key(); | 294 key->webm_decryption_key() : key->decryption_key(); |
307 scoped_refptr<DecoderBuffer> decrypted = | 295 scoped_refptr<DecoderBuffer> decrypted = |
308 DecryptData(*encrypted, decryption_key); | 296 DecryptData(*encrypted, decryption_key); |
309 if (!decrypted) { | 297 if (!decrypted) { |
310 DVLOG(1) << "Decryption failed."; | 298 DVLOG(1) << "Decryption failed."; |
311 decrypt_cb.Run(kError, NULL); | 299 decrypt_cb.Run(kError, NULL); |
312 return; | 300 return; |
313 } | 301 } |
314 | 302 |
315 decrypted->SetTimestamp(encrypted->GetTimestamp()); | 303 decrypted->SetTimestamp(encrypted->GetTimestamp()); |
316 decrypted->SetDuration(encrypted->GetDuration()); | 304 decrypted->SetDuration(encrypted->GetDuration()); |
317 decrypt_cb.Run(kSuccess, decrypted); | 305 decrypt_cb.Run(kSuccess, decrypted); |
318 } | 306 } |
319 | 307 |
320 AesDecryptor::DecryptionKey::DecryptionKey( | 308 void AesDecryptor::SetKey(const std::string& key_id, |
321 const std::string& secret) | 309 scoped_ptr<DecryptionKey> decryption_key) { |
310 base::AutoLock auto_lock(key_map_lock_); | |
311 KeyMap::iterator found = key_map_.find(key_id); | |
312 if (found != key_map_.end()) { | |
313 delete found->second; | |
314 key_map_.erase(found); | |
315 } | |
316 key_map_[key_id] = decryption_key.release(); | |
317 } | |
318 | |
319 AesDecryptor::DecryptionKey* AesDecryptor::GetKey( | |
320 const std::string& key_id) const { | |
321 base::AutoLock auto_lock(key_map_lock_); | |
322 KeyMap::const_iterator found = key_map_.find(key_id); | |
323 if (found == key_map_.end()) | |
324 return NULL; | |
325 | |
326 return found->second; | |
327 } | |
328 | |
329 AesDecryptor::DecryptionKey::DecryptionKey(const std::string& secret) | |
322 : secret_(secret) { | 330 : secret_(secret) { |
323 } | 331 } |
324 | 332 |
325 AesDecryptor::DecryptionKey::~DecryptionKey() {} | 333 AesDecryptor::DecryptionKey::~DecryptionKey() {} |
326 | 334 |
327 bool AesDecryptor::DecryptionKey::Init() { | 335 bool AesDecryptor::DecryptionKey::Init() { |
328 CHECK(!secret_.empty()); | 336 CHECK(!secret_.empty()); |
329 decryption_key_.reset( | 337 decryption_key_.reset(SymmetricKey::Import(SymmetricKey::AES, secret_)); |
330 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, secret_)); | 338 if (!decryption_key_.get()) |
331 if (!decryption_key_.get()) { | |
332 return false; | 339 return false; |
333 } | |
334 | 340 |
335 std::string raw_key = DeriveKey(secret_, | 341 std::string raw_key = DeriveKey(secret_, |
336 kWebmEncryptionSeed, | 342 kWebmEncryptionSeed, |
337 secret_.length()); | 343 secret_.length()); |
338 if (raw_key.empty()) { | 344 if (raw_key.empty()) |
339 return false; | 345 return false; |
340 } | 346 |
341 webm_decryption_key_.reset( | 347 webm_decryption_key_.reset(SymmetricKey::Import(SymmetricKey::AES, raw_key)); |
342 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key)); | 348 if (!webm_decryption_key_.get()) |
343 if (!webm_decryption_key_.get()) { | |
344 return false; | 349 return false; |
345 } | |
346 | 350 |
347 hmac_key_ = DeriveKey(secret_, kWebmHmacSeed, kWebmSha1DigestSize); | 351 hmac_key_ = DeriveKey(secret_, kWebmHmacSeed, kWebmSha1DigestSize); |
348 if (hmac_key_.empty()) { | 352 if (hmac_key_.empty()) |
349 return false; | 353 return false; |
350 } | |
351 | 354 |
352 return true; | 355 return true; |
353 } | 356 } |
354 | 357 |
355 } // namespace media | 358 } // namespace media |
OLD | NEW |