summaryrefslogtreecommitdiffstats
path: root/media/crypto
diff options
context:
space:
mode:
authorxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-08 05:09:27 +0000
committerxhwang@chromium.org <xhwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-08 05:09:27 +0000
commit08819ae89715143453b592abe0115ac1d3076003 (patch)
tree2f271a0ad88893d89a49703a5f6873ede8b5c073 /media/crypto
parenta8076b782e9d36f69651c84d5aee2a5ae321dca7 (diff)
downloadchromium_src-08819ae89715143453b592abe0115ac1d3076003.zip
chromium_src-08819ae89715143453b592abe0115ac1d3076003.tar.gz
chromium_src-08819ae89715143453b592abe0115ac1d3076003.tar.bz2
Add AES decryptor and tests.
For now we support decryption in video only. The first encryption key ID in ContentEncodings element will be used as the decryption key ID. Also we assume decryption key is the same as key ID. BUG=117060 TEST=test page with encrypted content plays; added media_unittest Review URL: http://codereview.chromium.org/9298021 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125560 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/crypto')
-rw-r--r--media/crypto/DEPS3
-rw-r--r--media/crypto/aes_decryptor.cc78
-rw-r--r--media/crypto/aes_decryptor.h32
-rw-r--r--media/crypto/aes_decryptor_unittest.cc56
4 files changed, 169 insertions, 0 deletions
diff --git a/media/crypto/DEPS b/media/crypto/DEPS
new file mode 100644
index 0000000..4ef4138
--- /dev/null
+++ b/media/crypto/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+crypto",
+]
diff --git a/media/crypto/aes_decryptor.cc b/media/crypto/aes_decryptor.cc
new file mode 100644
index 0000000..8e83daf
--- /dev/null
+++ b/media/crypto/aes_decryptor.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/crypto/aes_decryptor.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "crypto/encryptor.h"
+#include "crypto/symmetric_key.h"
+#include "media/base/buffers.h"
+#include "media/base/data_buffer.h"
+#include "media/base/decrypt_config.h"
+
+namespace media {
+
+static const char* kInitialCounter = "0000000000000000";
+
+// Decrypts |input| using |raw_key|, which is the binary data for the decryption
+// key.
+// Return a scoped_refptr to a Buffer object with the decrypted data on success.
+// Return a scoped_refptr to NULL if the data could not be decrypted.
+// TODO(xhwang): Both the input and output are copied! Any performance concern?
+static scoped_refptr<Buffer> DecryptData(const Buffer& input,
+ const uint8* raw_key,
+ int raw_key_size) {
+ CHECK(raw_key && raw_key_size > 0);
+ CHECK(input.GetDataSize());
+
+ scoped_ptr<crypto::SymmetricKey> key(crypto::SymmetricKey::Import(
+ crypto::SymmetricKey::AES,
+ std::string(reinterpret_cast<const char*>(raw_key), raw_key_size)));
+ if (!key.get()) {
+ DVLOG(1) << "Could not import key.";
+ return NULL;
+ }
+
+ // Initialize encryption data.
+ // The IV must be exactly as long as the cipher block size.
+ crypto::Encryptor encryptor;
+ if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, kInitialCounter)) {
+ DVLOG(1) << "Could not initialize encryptor.";
+ return NULL;
+ }
+
+ std::string decrypt_text;
+ std::string encrypted_text(reinterpret_cast<const char*>(input.GetData()),
+ input.GetDataSize());
+ if (!encryptor.Decrypt(encrypted_text, &decrypt_text)) {
+ DVLOG(1) << "Could not decrypt data.";
+ return NULL;
+ }
+
+ return DataBuffer::CopyFrom(
+ reinterpret_cast<const uint8*>(decrypt_text.data()),
+ decrypt_text.size());
+}
+
+AesDecryptor::AesDecryptor() {}
+
+scoped_refptr<Buffer> AesDecryptor::Decrypt(
+ const scoped_refptr<Buffer>& encrypted) {
+ CHECK(encrypted->GetDecryptConfig());
+
+ // For now, the key is the key ID.
+ const uint8* key = encrypted->GetDecryptConfig()->key_id();
+ int key_size = encrypted->GetDecryptConfig()->key_id_size();
+ scoped_refptr<Buffer> decrypted = DecryptData(*encrypted, key, key_size);
+ if (decrypted) {
+ decrypted->SetTimestamp(encrypted->GetTimestamp());
+ decrypted->SetDuration(encrypted->GetDuration());
+ }
+
+ return decrypted;
+}
+
+} // namespace media
diff --git a/media/crypto/aes_decryptor.h b/media/crypto/aes_decryptor.h
new file mode 100644
index 0000000..32d6802
--- /dev/null
+++ b/media/crypto/aes_decryptor.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CRYPTO_AES_DECRYPTOR_H_
+#define MEDIA_CRYPTO_AES_DECRYPTOR_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+class Buffer;
+
+// Decrypts AES encrypted buffer into unencrypted buffer.
+class MEDIA_EXPORT AesDecryptor {
+ public:
+ AesDecryptor();
+
+ // Decrypt |input| buffer. The |input| should not be NULL.
+ // Return a Buffer that contains decrypted data if decryption succeeded.
+ // Return NULL if decryption failed.
+ scoped_refptr<Buffer> Decrypt(const scoped_refptr<Buffer>& input);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AesDecryptor);
+};
+
+} // namespace media
+
+#endif // MEDIA_CRYPTO_AES_DECRYPTOR_H_
diff --git a/media/crypto/aes_decryptor_unittest.cc b/media/crypto/aes_decryptor_unittest.cc
new file mode 100644
index 0000000..0143bd0
--- /dev/null
+++ b/media/crypto/aes_decryptor_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "media/base/data_buffer.h"
+#include "media/base/decrypt_config.h"
+#include "media/crypto/aes_decryptor.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+// |kEncryptedDataHex| is encrypted from |kOriginalData| using |kRawKey|, whose
+// length is |kKeySize|. Modifying any of these independently would fail the
+// test.
+static const char kOriginalData[] = "Original data.";
+static const int kEncryptedDataSize = 16;
+static const unsigned char kEncryptedData[] =
+ "\x82\x3A\x76\x92\xEC\x7F\xF8\x85\xEC\x23\x52\xFB\x19\xB1\xB9\x09";
+static const int kKeySize = 16;
+static const unsigned char kRawKey[] = "A wonderful key!";
+static const unsigned char kWrongKey[] = "I'm a wrong key.";
+
+class AesDecryptorTest : public testing::Test {
+ public:
+ AesDecryptorTest() {
+ encrypted_data_ = DataBuffer::CopyFrom(kEncryptedData, kEncryptedDataSize);
+ }
+
+ protected:
+ void SetKey(const uint8* key, int key_size) {
+ encrypted_data_->SetDecryptConfig(
+ scoped_ptr<DecryptConfig>(new DecryptConfig(key, key_size)));
+ }
+
+ scoped_refptr<DataBuffer> encrypted_data_;
+ AesDecryptor decryptor_;
+};
+
+TEST_F(AesDecryptorTest, NormalDecryption) {
+ SetKey(kRawKey, kKeySize);
+ scoped_refptr<Buffer> decrypted_data = decryptor_.Decrypt(encrypted_data_);
+ ASSERT_TRUE(decrypted_data.get());
+ size_t data_length = sizeof(kOriginalData) - 1;
+ ASSERT_EQ(data_length, decrypted_data->GetDataSize());
+ ASSERT_EQ(0, memcmp(kOriginalData, decrypted_data->GetData(), data_length));
+}
+
+TEST_F(AesDecryptorTest, WrongKey) {
+ SetKey(kWrongKey, kKeySize);
+ scoped_refptr<Buffer> decrypted_data = decryptor_.Decrypt(encrypted_data_);
+ EXPECT_FALSE(decrypted_data.get());
+}
+
+} // media