Index: media/crypto/aes_decryptor.cc |
diff --git a/media/crypto/aes_decryptor.cc b/media/crypto/aes_decryptor.cc |
index f677f0d4206f186683b7c30d36fa4eb1f7b117c7..a5c8694db16b1ad96d013ae8a664cd1f83aae02c 100644 |
--- a/media/crypto/aes_decryptor.cc |
+++ b/media/crypto/aes_decryptor.cc |
@@ -16,11 +16,30 @@ |
namespace media { |
-// TODO(xhwang): Get real IV from frames. |
-static const char kInitialCounter[] = "0000000000000000"; |
- |
uint32 AesDecryptor::next_session_id_ = 1; |
+enum ClearBytesBufferSel { |
+ kSrcContainsClearBytes, |
+ kDstContainsClearBytes, |
+}; |
+ |
+static void CopySubsamples(const std::vector<SubsampleEntry>& subsamples, |
+ const ClearBytesBufferSel sel, |
+ const uint8* src, |
+ uint8* dst) { |
+ for (size_t i = 0; i < subsamples.size(); i++) { |
+ const SubsampleEntry& subsample = subsamples[i]; |
+ if (sel == kSrcContainsClearBytes) { |
+ src += subsample.clear_bytes; |
+ } else { |
+ dst += subsample.clear_bytes; |
+ } |
+ memcpy(dst, src, subsample.cypher_bytes); |
+ src += subsample.cypher_bytes; |
+ dst += subsample.cypher_bytes; |
+ } |
+} |
+ |
// Decrypt |input| using |key|. |
// Return a DecoderBuffer with the decrypted data if decryption succeeded. |
// Return NULL if decryption failed. |
@@ -31,25 +50,77 @@ static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input, |
// Initialize encryption data. |
// The IV must be exactly as long as the cipher block size. |
+ const std::string& iv = input.GetDecryptConfig()->iv(); |
crypto::Encryptor encryptor; |
- if (!encryptor.Init(key, crypto::Encryptor::CBC, kInitialCounter)) { |
- DVLOG(1) << "Could not initialize encryptor."; |
+ 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; |
+ } |
+ } |
+ |
+ if (input.GetDecryptConfig()->subsamples().empty()) { |
+ 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()); |
+ } |
+ |
+ const std::vector<SubsampleEntry>& subsamples = |
+ input.GetDecryptConfig()->subsamples(); |
+ |
+ int total_clear_size = 0; |
+ int total_encrypted_size = 0; |
+ for (size_t i = 0; i < subsamples.size(); i++) { |
+ total_clear_size += subsamples[i].clear_bytes; |
+ total_encrypted_size += subsamples[i].cypher_bytes; |
+ } |
+ if (total_clear_size + total_encrypted_size != input.GetDataSize()) { |
+ DVLOG(1) << "Subsample sizes do not equal input size"; |
return NULL; |
} |
+ // The encrypted portions of all subsamples must form a contiguous block, |
+ // 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_size]); |
+ CopySubsamples(subsamples, kSrcContainsClearBytes, |
+ input.GetData(), encrypted_bytes.get()); |
+ |
std::string decrypted_text; |
base::StringPiece encrypted_text( |
- reinterpret_cast<const char*>(input.GetData()), |
- input.GetDataSize()); |
+ reinterpret_cast<const char*>(encrypted_bytes.get()), |
+ total_encrypted_size); |
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()); |
+ scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom( |
+ input.GetData(), input.GetDataSize()); |
+ CopySubsamples(subsamples, kDstContainsClearBytes, |
+ reinterpret_cast<const uint8*>(decrypted_text.data()), |
+ output->GetWritableData()); |
+ return output; |
} |
AesDecryptor::AesDecryptor(DecryptorClient* client) |