summaryrefslogtreecommitdiffstats
path: root/media/crypto
diff options
context:
space:
mode:
authorstrobe@google.com <strobe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-26 00:49:59 +0000
committerstrobe@google.com <strobe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-26 00:49:59 +0000
commit9746f9132e55a91d2ec3d866711277b874574743 (patch)
treeb0f6d236afc3515855403363b6e9fe455a6c801d /media/crypto
parent7db8893ab741949612cebfed89e11d267daacbf9 (diff)
downloadchromium_src-9746f9132e55a91d2ec3d866711277b874574743.zip
chromium_src-9746f9132e55a91d2ec3d866711277b874574743.tar.gz
chromium_src-9746f9132e55a91d2ec3d866711277b874574743.tar.bz2
Add Common Encryption support to BMFF, including subsample decryption.
BUG=132351 TEST=AesDecryptorTest, plus manual playback in browser Review URL: https://chromiumcodereview.appspot.com/10651006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148453 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/crypto')
-rw-r--r--media/crypto/aes_decryptor.cc180
-rw-r--r--media/crypto/aes_decryptor.h11
-rw-r--r--media/crypto/aes_decryptor_unittest.cc270
3 files changed, 313 insertions, 148 deletions
diff --git a/media/crypto/aes_decryptor.cc b/media/crypto/aes_decryptor.cc
index 730a9b8..552197b 100644
--- a/media/crypto/aes_decryptor.cc
+++ b/media/crypto/aes_decryptor.cc
@@ -59,7 +59,7 @@ static bool CheckData(const DecoderBuffer& input,
const base::StringPiece& hmac_key) {
CHECK(input.GetDataSize());
CHECK(input.GetDecryptConfig());
- CHECK_GT(input.GetDecryptConfig()->checksum_size(), 0);
+ CHECK_GT(input.GetDecryptConfig()->checksum().size(), 0u);
CHECK(!hmac_key.empty());
crypto::HMAC hmac(crypto::HMAC::SHA1);
@@ -72,65 +72,117 @@ static bool CheckData(const DecoderBuffer& input,
// Here, check that checksum size is not greater than the hash
// algorithm's digest length.
- DCHECK_LE(input.GetDecryptConfig()->checksum_size(),
- static_cast<int>(hmac.DigestLength()));
+ DCHECK_LE(input.GetDecryptConfig()->checksum().size(),
+ hmac.DigestLength());
base::StringPiece data_to_check(
reinterpret_cast<const char*>(input.GetData()), input.GetDataSize());
- base::StringPiece digest(
- reinterpret_cast<const char*>(input.GetDecryptConfig()->checksum()),
- input.GetDecryptConfig()->checksum_size());
- return hmac.VerifyTruncated(data_to_check, digest);
+ return hmac.VerifyTruncated(data_to_check,
+ input.GetDecryptConfig()->checksum());
}
-// Decrypts |input| using |key|. |encrypted_data_offset| is the number of bytes
-// into |input| that the encrypted data starts.
-// Returns a DecoderBuffer with the decrypted data if decryption succeeded or
-// NULL if decryption failed.
+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;
+ }
+}
+
+// Decrypts |input| using |key|. Returns a DecoderBuffer with the decrypted
+// data if decryption succeeded or NULL if decryption failed.
static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input,
- crypto::SymmetricKey* key,
- int encrypted_data_offset) {
+ crypto::SymmetricKey* key) {
CHECK(input.GetDataSize());
CHECK(input.GetDecryptConfig());
CHECK(key);
- // Initialize decryptor.
crypto::Encryptor encryptor;
if (!encryptor.Init(key, crypto::Encryptor::CTR, "")) {
DVLOG(1) << "Could not initialize decryptor.";
return NULL;
}
- DCHECK_EQ(input.GetDecryptConfig()->iv_size(),
- DecryptConfig::kDecryptionKeySize);
- // Set the counter block.
- base::StringPiece counter_block(
- reinterpret_cast<const char*>(input.GetDecryptConfig()->iv()),
- input.GetDecryptConfig()->iv_size());
- if (counter_block.empty()) {
- DVLOG(1) << "Could not generate counter block.";
+ DCHECK_EQ(input.GetDecryptConfig()->iv().size(),
+ static_cast<size_t>(DecryptConfig::kDecryptionKeySize));
+ if (!encryptor.SetCounter(input.GetDecryptConfig()->iv())) {
+ DVLOG(1) << "Could not set counter block.";
return NULL;
}
- if (!encryptor.SetCounter(counter_block)) {
- DVLOG(1) << "Could not set counter block.";
+
+ const int data_offset = input.GetDecryptConfig()->data_offset();
+ const char* sample =
+ reinterpret_cast<const char*>(input.GetData() + data_offset);
+ int sample_size = input.GetDataSize() - data_offset;
+
+ if (input.GetDecryptConfig()->subsamples().empty()) {
+ std::string decrypted_text;
+ base::StringPiece encrypted_text(sample, sample_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());
+ }
+
+ 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 != sample_size) {
+ 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,
+ reinterpret_cast<const uint8*>(sample), encrypted_bytes.get());
+
+ base::StringPiece encrypted_text(
+ reinterpret_cast<const char*>(encrypted_bytes.get()),
+ total_encrypted_size);
std::string decrypted_text;
- const char* frame =
- reinterpret_cast<const char*>(input.GetData() + encrypted_data_offset);
- int frame_size = input.GetDataSize() - encrypted_data_offset;
- base::StringPiece encrypted_text(frame, frame_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(
+ reinterpret_cast<const uint8*>(sample), sample_size);
+ CopySubsamples(subsamples, kDstContainsClearBytes,
+ reinterpret_cast<const uint8*>(decrypted_text.data()),
+ output->GetWritableData());
+ return output;
}
AesDecryptor::AesDecryptor(DecryptorClient* client)
@@ -192,9 +244,7 @@ void AesDecryptor::AddKey(const std::string& key_system,
return;
}
- // TODO(fgalligan): When ISO is added we will need to figure out how to
- // detect if the encrypted data will contain an HMAC.
- if (!decryption_key->Init(true)) {
+ if (!decryption_key->Init()) {
DVLOG(1) << "Could not initialize decryption key.";
client_->KeyError(key_system, session_id, Decryptor::kUnknownError, 0);
return;
@@ -220,16 +270,12 @@ void AesDecryptor::CancelKeyRequest(const std::string& key_system,
void AesDecryptor::Decrypt(const scoped_refptr<DecoderBuffer>& encrypted,
const DecryptCB& decrypt_cb) {
CHECK(encrypted->GetDecryptConfig());
- const uint8* key_id = encrypted->GetDecryptConfig()->key_id();
- const int key_id_size = encrypted->GetDecryptConfig()->key_id_size();
-
- // TODO(xhwang): Avoid always constructing a string with StringPiece?
- std::string key_id_string(reinterpret_cast<const char*>(key_id), key_id_size);
+ const std::string& key_id = encrypted->GetDecryptConfig()->key_id();
DecryptionKey* key = NULL;
{
base::AutoLock auto_lock(key_map_lock_);
- KeyMap::const_iterator found = key_map_.find(key_id_string);
+ KeyMap::const_iterator found = key_map_.find(key_id);
if (found != key_map_.end())
key = found->second;
}
@@ -241,7 +287,7 @@ void AesDecryptor::Decrypt(const scoped_refptr<DecoderBuffer>& encrypted,
return;
}
- int checksum_size = encrypted->GetDecryptConfig()->checksum_size();
+ int checksum_size = encrypted->GetDecryptConfig()->checksum().size();
// According to the WebM encrypted specification, it is an open question
// what should happen when a frame fails the integrity check.
// http://wiki.webmproject.org/encryption/webm-encryption-rfc
@@ -253,10 +299,13 @@ void AesDecryptor::Decrypt(const scoped_refptr<DecoderBuffer>& encrypted,
return;
}
+ // TODO(strobe): Currently, presence of checksum is used to indicate the use
+ // of normal or WebM decryption keys. Consider a more explicit signaling
+ // mechanism and the removal of the webm_decryption_key member.
+ crypto::SymmetricKey* decryption_key = (checksum_size > 0) ?
+ key->webm_decryption_key() : key->decryption_key();
scoped_refptr<DecoderBuffer> decrypted =
- DecryptData(*encrypted,
- key->decryption_key(),
- encrypted->GetDecryptConfig()->encrypted_frame_offset());
+ DecryptData(*encrypted, decryption_key);
if (!decrypted) {
DVLOG(1) << "Decryption failed.";
decrypt_cb.Run(kError, NULL);
@@ -275,34 +324,31 @@ AesDecryptor::DecryptionKey::DecryptionKey(
AesDecryptor::DecryptionKey::~DecryptionKey() {}
-bool AesDecryptor::DecryptionKey::Init(bool derive_webm_keys) {
+bool AesDecryptor::DecryptionKey::Init() {
CHECK(!secret_.empty());
-
- if (derive_webm_keys) {
- std::string raw_key = DeriveKey(secret_,
- kWebmEncryptionSeed,
- secret_.length());
- if (raw_key.empty()) {
- return false;
- }
- decryption_key_.reset(
- crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key));
- if (!decryption_key_.get()) {
- return false;
- }
-
- hmac_key_ = DeriveKey(secret_, kWebmHmacSeed, kWebmSha1DigestSize);
- if (hmac_key_.empty()) {
- return false;
- }
- return true;
- }
-
decryption_key_.reset(
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, secret_));
if (!decryption_key_.get()) {
return false;
}
+
+ std::string raw_key = DeriveKey(secret_,
+ kWebmEncryptionSeed,
+ secret_.length());
+ if (raw_key.empty()) {
+ return false;
+ }
+ webm_decryption_key_.reset(
+ crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key));
+ if (!webm_decryption_key_.get()) {
+ return false;
+ }
+
+ hmac_key_ = DeriveKey(secret_, kWebmHmacSeed, kWebmSha1DigestSize);
+ if (hmac_key_.empty()) {
+ return false;
+ }
+
return true;
}
diff --git a/media/crypto/aes_decryptor.h b/media/crypto/aes_decryptor.h
index 224035c..86b258d 100644
--- a/media/crypto/aes_decryptor.h
+++ b/media/crypto/aes_decryptor.h
@@ -61,12 +61,12 @@ class MEDIA_EXPORT AesDecryptor : public Decryptor {
explicit DecryptionKey(const std::string& secret);
~DecryptionKey();
- // Creates the encryption key and HMAC. If |derive_webm_keys| is true then
- // the object will derive the decryption key and the HMAC key from
- // |secret_|.
- bool Init(bool derive_webm_keys);
+ // Creates the encryption key, and derives the WebM decryption key and HMAC.
+ bool Init();
crypto::SymmetricKey* decryption_key() { return decryption_key_.get(); }
+ crypto::SymmetricKey* webm_decryption_key()
+ { return webm_decryption_key_.get(); }
base::StringPiece hmac_key() { return base::StringPiece(hmac_key_); }
private:
@@ -77,6 +77,9 @@ class MEDIA_EXPORT AesDecryptor : public Decryptor {
// The key used to decrypt the data.
scoped_ptr<crypto::SymmetricKey> decryption_key_;
+ // The key used for decryption of WebM media, derived from the secret.
+ scoped_ptr<crypto::SymmetricKey> webm_decryption_key_;
+
// The key used to perform the integrity check. Currently the HMAC key is
// defined by the WebM encrypted specification. Current encrypted WebM
// request for comments specification is here
diff --git a/media/crypto/aes_decryptor_unittest.cc b/media/crypto/aes_decryptor_unittest.cc
index 34354a4..7877f6e 100644
--- a/media/crypto/aes_decryptor_unittest.cc
+++ b/media/crypto/aes_decryptor_unittest.cc
@@ -143,6 +143,47 @@ static const unsigned char kWebmFrame0FrameDataChanged[] = {
0x64, 0xf8
};
+static const uint8 kSubsampleOriginalData[] = "Original subsample data.";
+static const int kSubsampleOriginalDataSize = 24;
+
+static const uint8 kSubsampleKeyId[] = { 0x00, 0x01, 0x02, 0x03 };
+
+static const uint8 kSubsampleKey[] = {
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13
+};
+
+static const uint8 kSubsampleIv[] = {
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8 kSubsampleData[] = {
+ 0x4f, 0x72, 0x09, 0x16, 0x09, 0xe6, 0x79, 0xad,
+ 0x70, 0x73, 0x75, 0x62, 0x09, 0xbb, 0x83, 0x1d,
+ 0x4d, 0x08, 0xd7, 0x78, 0xa4, 0xa7, 0xf1, 0x2e
+};
+
+static const uint8 kPaddedSubsampleData[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x4f, 0x72, 0x09, 0x16, 0x09, 0xe6, 0x79, 0xad,
+ 0x70, 0x73, 0x75, 0x62, 0x09, 0xbb, 0x83, 0x1d,
+ 0x4d, 0x08, 0xd7, 0x78, 0xa4, 0xa7, 0xf1, 0x2e
+};
+
+// Encrypted with kSubsampleKey and kSubsampleIv but without subsamples.
+static const uint8 kNoSubsampleData[] = {
+ 0x2f, 0x03, 0x09, 0xef, 0x71, 0xaf, 0x31, 0x16,
+ 0xfa, 0x9d, 0x18, 0x43, 0x1e, 0x96, 0x71, 0xb5,
+ 0xbf, 0xf5, 0x30, 0x53, 0x9a, 0x20, 0xdf, 0x95
+};
+
+static const SubsampleEntry kSubsampleEntries[] = {
+ { 2, 7 },
+ { 3, 11 },
+ { 1, 0 },
+};
+
class AesDecryptorTest : public testing::Test {
public:
AesDecryptorTest()
@@ -176,10 +217,9 @@ class AesDecryptorTest : public testing::Test {
// an HMAC and IV prepended to an encrypted frame. Current encrypted WebM
// request for comments specification is here
// http://wiki.webmproject.org/encryption/webm-encryption-rfc
- scoped_refptr<DecoderBuffer> CreateWebMEncryptedBuffer(const uint8* data,
- int data_size,
- const uint8* key_id,
- int key_id_size) {
+ scoped_refptr<DecoderBuffer> CreateWebMEncryptedBuffer(
+ const uint8* data, int data_size,
+ const uint8* key_id, int key_id_size) {
scoped_refptr<DecoderBuffer> encrypted_buffer = DecoderBuffer::CopyFrom(
data + kWebMHmacSize, data_size - kWebMHmacSize);
CHECK(encrypted_buffer);
@@ -191,10 +231,30 @@ class AesDecryptorTest : public testing::Test {
GenerateCounterBlock(reinterpret_cast<const uint8*>(&iv), sizeof(iv));
encrypted_buffer->SetDecryptConfig(
scoped_ptr<DecryptConfig>(new DecryptConfig(
- key_id, key_id_size,
- reinterpret_cast<const uint8*>(webm_iv.data()), webm_iv.size(),
- data, kWebMHmacSize,
- sizeof(iv))));
+ std::string(reinterpret_cast<const char*>(key_id), key_id_size),
+ webm_iv,
+ std::string(reinterpret_cast<const char*>(data), kWebMHmacSize),
+ sizeof(iv),
+ std::vector<SubsampleEntry>())));
+ return encrypted_buffer;
+ }
+
+ scoped_refptr<DecoderBuffer> CreateSubsampleEncryptedBuffer(
+ const uint8* data, int data_size,
+ const uint8* key_id, int key_id_size,
+ const uint8* iv, int iv_size,
+ int data_offset,
+ const std::vector<SubsampleEntry>& subsample_entries) {
+ scoped_refptr<DecoderBuffer> encrypted_buffer =
+ DecoderBuffer::CopyFrom(data, data_size);
+ CHECK(encrypted_buffer);
+ encrypted_buffer->SetDecryptConfig(
+ scoped_ptr<DecryptConfig>(new DecryptConfig(
+ std::string(reinterpret_cast<const char*>(key_id), key_id_size),
+ std::string(reinterpret_cast<const char*>(iv), iv_size),
+ std::string(),
+ data_offset,
+ subsample_entries)));
return encrypted_buffer;
}
@@ -223,29 +283,21 @@ class AesDecryptorTest : public testing::Test {
MOCK_METHOD2(BufferDecrypted, void(Decryptor::DecryptStatus,
const scoped_refptr<DecoderBuffer>&));
- void DecryptAndExpectToSucceed(const uint8* data, int data_size,
- const uint8* plain_text,
- int plain_text_size,
- const uint8* key_id, int key_id_size) {
- scoped_refptr<DecoderBuffer> encrypted_data =
- CreateWebMEncryptedBuffer(data, data_size, key_id, key_id_size);
+ void DecryptAndExpectToSucceed(const scoped_refptr<DecoderBuffer>& encrypted,
+ const uint8* plain_text, int plain_text_size) {
scoped_refptr<DecoderBuffer> decrypted;
EXPECT_CALL(*this, BufferDecrypted(AesDecryptor::kSuccess, NotNull()))
.WillOnce(SaveArg<1>(&decrypted));
- decryptor_.Decrypt(encrypted_data, decrypt_cb_);
+ decryptor_.Decrypt(encrypted, decrypt_cb_);
ASSERT_TRUE(decrypted);
ASSERT_EQ(plain_text_size, decrypted->GetDataSize());
EXPECT_EQ(0, memcmp(plain_text, decrypted->GetData(), plain_text_size));
}
- void DecryptAndExpectToFail(const uint8* data, int data_size,
- const uint8* plain_text, int plain_text_size,
- const uint8* key_id, int key_id_size) {
- scoped_refptr<DecoderBuffer> encrypted_data =
- CreateWebMEncryptedBuffer(data, data_size, key_id, key_id_size);
+ void DecryptAndExpectToFail(const scoped_refptr<DecoderBuffer>& encrypted) {
EXPECT_CALL(*this, BufferDecrypted(AesDecryptor::kError, IsNull()));
- decryptor_.Decrypt(encrypted_data, decrypt_cb_);
+ decryptor_.Decrypt(encrypted, decrypt_cb_);
}
scoped_refptr<DecoderBuffer> encrypted_data_;
@@ -255,17 +307,18 @@ class AesDecryptorTest : public testing::Test {
AesDecryptor::DecryptCB decrypt_cb_;
};
-TEST_F(AesDecryptorTest, NormalDecryption) {
+TEST_F(AesDecryptorTest, NormalWebMDecryption) {
const WebmEncryptedData& frame = kWebmEncryptedFrames[0];
GenerateKeyRequest(frame.key_id, frame.key_id_size);
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
frame.key, frame.key_size);
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(frame.encrypted_data,
- frame.encrypted_data_size,
+ scoped_refptr<DecoderBuffer> encrypted_data =
+ CreateWebMEncryptedBuffer(frame.encrypted_data,
+ frame.encrypted_data_size,
+ frame.key_id, frame.key_id_size);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(encrypted_data,
frame.plain_text,
- frame.plain_text_size,
- frame.key_id,
- frame.key_id_size));
+ frame.plain_text_size));
}
TEST_F(AesDecryptorTest, WrongKey) {
@@ -273,12 +326,11 @@ TEST_F(AesDecryptorTest, WrongKey) {
GenerateKeyRequest(frame.key_id, frame.key_id_size);
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
kWebmWrongKey, arraysize(kWebmWrongKey));
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(frame.encrypted_data,
- frame.encrypted_data_size,
- frame.plain_text,
- frame.plain_text_size,
- frame.key_id,
- frame.key_id_size));
+ scoped_refptr<DecoderBuffer> encrypted_data =
+ CreateWebMEncryptedBuffer(frame.encrypted_data,
+ frame.encrypted_data_size,
+ frame.key_id, frame.key_id_size);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(encrypted_data));
}
TEST_F(AesDecryptorTest, KeyReplacement) {
@@ -286,20 +338,16 @@ TEST_F(AesDecryptorTest, KeyReplacement) {
GenerateKeyRequest(frame.key_id, frame.key_id_size);
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
kWebmWrongKey, arraysize(kWebmWrongKey));
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(frame.encrypted_data,
- frame.encrypted_data_size,
- frame.plain_text,
- frame.plain_text_size,
- frame.key_id,
- frame.key_id_size));
+ scoped_refptr<DecoderBuffer> encrypted_data =
+ CreateWebMEncryptedBuffer(frame.encrypted_data,
+ frame.encrypted_data_size,
+ frame.key_id, frame.key_id_size);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(encrypted_data));
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
frame.key, frame.key_size);
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(frame.encrypted_data,
- frame.encrypted_data_size,
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(encrypted_data,
frame.plain_text,
- frame.plain_text_size,
- frame.key_id,
- frame.key_id_size));
+ frame.plain_text_size));
}
TEST_F(AesDecryptorTest, WrongSizedKey) {
@@ -314,12 +362,13 @@ TEST_F(AesDecryptorTest, MultipleKeysAndFrames) {
GenerateKeyRequest(frame.key_id, frame.key_id_size);
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
frame.key, frame.key_size);
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(frame.encrypted_data,
- frame.encrypted_data_size,
+ scoped_refptr<DecoderBuffer> encrypted_data =
+ CreateWebMEncryptedBuffer(frame.encrypted_data,
+ frame.encrypted_data_size,
+ frame.key_id, frame.key_id_size);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(encrypted_data,
frame.plain_text,
- frame.plain_text_size,
- frame.key_id,
- frame.key_id_size));
+ frame.plain_text_size));
const WebmEncryptedData& frame2 = kWebmEncryptedFrames[2];
GenerateKeyRequest(frame2.key_id, frame2.key_id_size);
@@ -327,19 +376,21 @@ TEST_F(AesDecryptorTest, MultipleKeysAndFrames) {
frame2.key, frame2.key_size);
const WebmEncryptedData& frame1 = kWebmEncryptedFrames[1];
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(frame1.encrypted_data,
- frame1.encrypted_data_size,
+ scoped_refptr<DecoderBuffer> encrypted_data1 =
+ CreateWebMEncryptedBuffer(frame1.encrypted_data,
+ frame1.encrypted_data_size,
+ frame1.key_id, frame1.key_id_size);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(encrypted_data1,
frame1.plain_text,
- frame1.plain_text_size,
- frame1.key_id,
- frame1.key_id_size));
+ frame1.plain_text_size));
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(frame2.encrypted_data,
- frame2.encrypted_data_size,
+ scoped_refptr<DecoderBuffer> encrypted_data2 =
+ CreateWebMEncryptedBuffer(frame2.encrypted_data,
+ frame2.encrypted_data_size,
+ frame2.key_id, frame2.key_id_size);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(encrypted_data2,
frame2.plain_text,
- frame2.plain_text_size,
- frame2.key_id,
- frame2.key_id_size));
+ frame2.plain_text_size));
}
TEST_F(AesDecryptorTest, HmacCheckFailure) {
@@ -347,12 +398,11 @@ TEST_F(AesDecryptorTest, HmacCheckFailure) {
GenerateKeyRequest(frame.key_id, frame.key_id_size);
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
frame.key, frame.key_size);
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(kWebmFrame0HmacDataChanged,
- frame.encrypted_data_size,
- frame.plain_text,
- frame.plain_text_size,
- frame.key_id,
- frame.key_id_size));
+ scoped_refptr<DecoderBuffer> encrypted_data =
+ CreateWebMEncryptedBuffer(kWebmFrame0HmacDataChanged,
+ frame.encrypted_data_size,
+ frame.key_id, frame.key_id_size);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(encrypted_data));
}
TEST_F(AesDecryptorTest, IvCheckFailure) {
@@ -360,12 +410,11 @@ TEST_F(AesDecryptorTest, IvCheckFailure) {
GenerateKeyRequest(frame.key_id, frame.key_id_size);
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
frame.key, frame.key_size);
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(kWebmFrame0IvDataChanged,
- frame.encrypted_data_size,
- frame.plain_text,
- frame.plain_text_size,
- frame.key_id,
- frame.key_id_size));
+ scoped_refptr<DecoderBuffer> encrypted_data =
+ CreateWebMEncryptedBuffer(kWebmFrame0IvDataChanged,
+ frame.encrypted_data_size,
+ frame.key_id, frame.key_id_size);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(encrypted_data));
}
TEST_F(AesDecryptorTest, DataCheckFailure) {
@@ -373,12 +422,79 @@ TEST_F(AesDecryptorTest, DataCheckFailure) {
GenerateKeyRequest(frame.key_id, frame.key_id_size);
AddKeyAndExpectToSucceed(frame.key_id, frame.key_id_size,
frame.key, frame.key_size);
- ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(kWebmFrame0FrameDataChanged,
- frame.encrypted_data_size,
- frame.plain_text,
- frame.plain_text_size,
- frame.key_id,
- frame.key_id_size));
+ scoped_refptr<DecoderBuffer> encrypted_data =
+ CreateWebMEncryptedBuffer(kWebmFrame0FrameDataChanged,
+ frame.encrypted_data_size,
+ frame.key_id, frame.key_id_size);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(encrypted_data));
+}
+
+TEST_F(AesDecryptorTest, SubsampleDecryption) {
+ GenerateKeyRequest(kSubsampleKeyId, arraysize(kSubsampleKeyId));
+ AddKeyAndExpectToSucceed(kSubsampleKeyId, arraysize(kSubsampleKeyId),
+ kSubsampleKey, arraysize(kSubsampleKey));
+ scoped_refptr<DecoderBuffer> encrypted_data = CreateSubsampleEncryptedBuffer(
+ kSubsampleData, arraysize(kSubsampleData),
+ kSubsampleKeyId, arraysize(kSubsampleKeyId),
+ kSubsampleIv, arraysize(kSubsampleIv),
+ 0,
+ std::vector<SubsampleEntry>(
+ kSubsampleEntries,
+ kSubsampleEntries + arraysize(kSubsampleEntries)));
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(
+ encrypted_data, kSubsampleOriginalData, kSubsampleOriginalDataSize));
+}
+
+// Ensures noninterference of data offset and subsample mechanisms. We never
+// expect to encounter this in the wild, but since the DecryptConfig doesn't
+// disallow such a configuration, it should be covered.
+TEST_F(AesDecryptorTest, SubsampleDecryptionWithOffset) {
+ GenerateKeyRequest(kSubsampleKeyId, arraysize(kSubsampleKeyId));
+ AddKeyAndExpectToSucceed(kSubsampleKeyId, arraysize(kSubsampleKeyId),
+ kSubsampleKey, arraysize(kSubsampleKey));
+ scoped_refptr<DecoderBuffer> encrypted_data = CreateSubsampleEncryptedBuffer(
+ kPaddedSubsampleData, arraysize(kPaddedSubsampleData),
+ kSubsampleKeyId, arraysize(kSubsampleKeyId),
+ kSubsampleIv, arraysize(kSubsampleIv),
+ arraysize(kPaddedSubsampleData) - arraysize(kSubsampleData),
+ std::vector<SubsampleEntry>(
+ kSubsampleEntries,
+ kSubsampleEntries + arraysize(kSubsampleEntries)));
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(
+ encrypted_data, kSubsampleOriginalData, kSubsampleOriginalDataSize));
+}
+
+// No subsample or offset.
+TEST_F(AesDecryptorTest, NormalDecryption) {
+ GenerateKeyRequest(kSubsampleKeyId, arraysize(kSubsampleKeyId));
+ AddKeyAndExpectToSucceed(kSubsampleKeyId, arraysize(kSubsampleKeyId),
+ kSubsampleKey, arraysize(kSubsampleKey));
+ scoped_refptr<DecoderBuffer> encrypted_data = CreateSubsampleEncryptedBuffer(
+ kNoSubsampleData, arraysize(kNoSubsampleData),
+ kSubsampleKeyId, arraysize(kSubsampleKeyId),
+ kSubsampleIv, arraysize(kSubsampleIv),
+ 0,
+ std::vector<SubsampleEntry>());
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed(
+ encrypted_data, kSubsampleOriginalData, kSubsampleOriginalDataSize));
+}
+
+TEST_F(AesDecryptorTest, IncorrectSubsampleSize) {
+ GenerateKeyRequest(kSubsampleKeyId, arraysize(kSubsampleKeyId));
+ AddKeyAndExpectToSucceed(kSubsampleKeyId, arraysize(kSubsampleKeyId),
+ kSubsampleKey, arraysize(kSubsampleKey));
+ std::vector<SubsampleEntry> entries(
+ kSubsampleEntries,
+ kSubsampleEntries + arraysize(kSubsampleEntries));
+ entries[2].cypher_bytes += 1;
+
+ scoped_refptr<DecoderBuffer> encrypted_data = CreateSubsampleEncryptedBuffer(
+ kSubsampleData, arraysize(kSubsampleData),
+ kSubsampleKeyId, arraysize(kSubsampleKeyId),
+ kSubsampleIv, arraysize(kSubsampleIv),
+ 0,
+ entries);
+ ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail(encrypted_data));
}
} // namespace media