Index: media/crypto/aes_decryptor.cc |
diff --git a/media/crypto/aes_decryptor.cc b/media/crypto/aes_decryptor.cc |
index 129bc330131585c2a77a66dc7ab8b96fb96c76e6..2f47d9c5641d14f2874644b188d86bbbb7e225da 100644 |
--- a/media/crypto/aes_decryptor.cc |
+++ b/media/crypto/aes_decryptor.cc |
@@ -16,9 +16,6 @@ |
namespace media { |
-// TODO(xhwang): Get real IV from frames. |
-static const char kInitialCounter[] = "0000000000000000"; |
- |
uint32 AesDecryptor::next_session_id_ = 1; |
// Decrypt |input| using |key|. |
@@ -29,27 +26,100 @@ static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input, |
CHECK(input.GetDataSize()); |
CHECK(key); |
+ base::StringPiece iv( |
+ reinterpret_cast<const char*>(input.GetDecryptConfig()->iv()), |
+ input.GetDecryptConfig()->iv_size()); |
xhwang
2012/06/27 19:37:43
Life will be easier here if we use std::string for
strobe_
2012/07/13 00:47:07
Done.
|
+ |
// Initialize encryption data. |
// The IV must be exactly as long as the cipher block size. |
crypto::Encryptor encryptor; |
- if (!encryptor.Init(key, crypto::Encryptor::CBC, kInitialCounter)) { |
- DVLOG(1) << "Could not initialize encryptor."; |
- return NULL; |
+ if (input.GetDecryptConfig()->use_cbc()) { |
+ if (!encryptor.Init(key, crypto::Encryptor::CBC, iv)) { |
+ DVLOG(1) << "Could not initialize encryptor."; |
+ return NULL; |
+ } |
+ } else { |
+ if (!encryptor.Init(key, crypto::Encryptor::CTR, base::StringPiece()) || |
+ !encryptor.SetCounter(iv)) { |
+ DVLOG(1) << "Could not initialize encryptor."; |
+ return NULL; |
+ } |
} |
- std::string decrypted_text; |
- base::StringPiece encrypted_text( |
- reinterpret_cast<const char*>(input.GetData()), |
- input.GetDataSize()); |
- if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { |
- DVLOG(1) << "Could not decrypt data."; |
- return NULL; |
- } |
+ if (!input.GetDecryptConfig()->subsamples().empty()) { |
+ // XXX(strobe): factor out and test before final commit |
ddorwin
2012/07/03 21:03:47
XXX? TODO?
strobe_
2012/07/13 00:47:07
Done.
|
+ const std::vector<SubsampleEntry> subsamples = |
ddorwin
2012/07/03 21:03:47
const ref instead of copying
strobe_
2012/07/13 00:47:07
Done.
|
+ input.GetDecryptConfig()->subsamples(); |
+ |
+ int total_encrypted_subsample_size = 0; |
+ for (size_t i = 0; i < subsamples.size(); i++) |
+ total_encrypted_subsample_size += subsamples[i].cypher_bytes; |
+ |
+ if (total_encrypted_subsample_size > input.GetDataSize()) { |
ddorwin
2012/07/03 21:03:47
Should we also check that enc plus unenc are == da
strobe_
2012/07/13 00:47:07
Done.
|
+ DVLOG(1) << "Subsample encrypted size larger than input size"; |
+ return NULL; |
+ } |
- // TODO(xhwang): Find a way to avoid this data copy. |
- return DecoderBuffer::CopyFrom( |
- reinterpret_cast<const uint8*>(decrypted_text.data()), |
- decrypted_text.size()); |
+ // The encrypted portion of each subsample must form a contiguous block, |
ddorwin
2012/07/03 21:03:47
This line seems to discuss a single subsample rath
strobe_
2012/07/13 00:47:07
Done.
|
+ // such that an encrypted subsample that ends away from a block boundary is |
+ // immediately followed by the start of the next encrypted subsample. We |
+ // copy all encrypted subsamples to a contiguous buffer, decrypt them, then |
+ // copy the decrypted bytes over the encrypted bytes in the output. |
+ // TODO(strobe): attempt to reduce number of memory copies |
+ scoped_array<uint8> encrypted_bytes( |
+ new uint8[total_encrypted_subsample_size]); |
+ int in_pos = 0, out_pos = 0; |
xhwang
2012/06/27 19:37:43
Prefer to declaring variables on separate lines. I
strobe_
2012/07/13 00:47:07
Done.
|
+ for (size_t i = 0; i < subsamples.size(); i++) { |
+ const SubsampleEntry& subsample = subsamples[i]; |
+ in_pos += subsample.clear_bytes; |
+ if (in_pos + subsample.cypher_bytes > input.GetDataSize()) { |
+ DVLOG(1) << "Subsample total size larger than input size"; |
+ return NULL; |
+ } |
+ memcpy(encrypted_bytes.get() + out_pos, input.GetData() + in_pos, |
+ subsample.cypher_bytes); |
+ in_pos += subsample.cypher_bytes; |
+ out_pos += subsample.cypher_bytes; |
+ } |
+ |
+ std::string decrypted_text; |
+ base::StringPiece encrypted_text( |
+ reinterpret_cast<const char*>(encrypted_bytes.get()), |
+ total_encrypted_subsample_size); |
+ if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { |
+ DVLOG(1) << "Could not decrypt data."; |
+ return NULL; |
+ } |
+ |
+ scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom( |
+ input.GetData(), input.GetDataSize()); |
+ in_pos = 0; |
+ out_pos = 0; |
+ for (size_t i = 0; i < subsamples.size(); i++) { |
+ const SubsampleEntry& subsample = subsamples[i]; |
+ out_pos += subsample.clear_bytes; |
+ memcpy(output->GetWritableData() + out_pos, |
+ reinterpret_cast<const uint8*>(decrypted_text.data()) + in_pos, |
+ subsample.cypher_bytes); |
+ in_pos += subsample.cypher_bytes; |
+ out_pos += subsample.cypher_bytes; |
xhwang
2012/06/27 19:37:43
This part is so similar to the block starting from
strobe_
2012/07/13 00:47:07
Done.
|
+ } |
+ return output; |
+ } else { |
xhwang
2012/06/27 19:37:43
nit: we don't need this "else" since "if" will alw
strobe_
2012/07/13 00:47:07
Done.
|
+ std::string decrypted_text; |
+ base::StringPiece encrypted_text( |
+ reinterpret_cast<const char*>(input.GetData()), |
+ input.GetDataSize()); |
+ if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { |
+ DVLOG(1) << "Could not decrypt data."; |
+ return NULL; |
+ } |
+ |
+ // TODO(xhwang): Find a way to avoid this data copy. |
+ return DecoderBuffer::CopyFrom( |
+ reinterpret_cast<const uint8*>(decrypted_text.data()), |
+ decrypted_text.size()); |
+ } |
} |
AesDecryptor::AesDecryptor(DecryptorClient* client) |