From d5cdd00ba18e3ff568ea89e0fd31fee2a5a4ca1b Mon Sep 17 00:00:00 2001 From: Jacob Trimble Date: Fri, 19 Feb 2016 12:23:37 -0800 Subject: [PATCH] Move fixed key encryption code to new FixedKeySource. KeySource is now an abstract class that is implemented in two types WidevineKeySource and FixedKeySource. This also updates fixed key encryption to use v1 PSSH boxes with the common system ID. This also updates the --pssh argument. Now it accepts full PSSH boxes rather than data. Multiple PSSH boxes can be concatenated together. Issue #88 Change-Id: I4bd0290f6d8b965f7d118f075c96e0f267d7e831 --- packager/app/fixed_key_encryption_flags.cc | 8 +- packager/app/packager_util.cc | 9 +- packager/app/test/packager_test.py | 6 +- .../media/base/decryptor_source_unittest.cc | 3 +- packager/media/base/fixed_key_source.cc | 153 ++++++++++++++++++ packager/media/base/fixed_key_source.h | 68 ++++++++ .../media/base/fixed_key_source_unittest.cc | 99 ++++++++++++ packager/media/base/key_source.cc | 129 +-------------- packager/media/base/key_source.h | 47 ++---- packager/media/base/media_base.gyp | 3 + packager/media/base/widevine_key_source.cc | 4 + packager/media/base/widevine_key_source.h | 9 +- .../mpd_notify_muxer_listener_unittest.cc | 4 +- .../media/event/muxer_listener_test_helper.cc | 5 +- .../media/event/muxer_listener_test_helper.h | 4 +- ...media_info_dump_muxer_listener_unittest.cc | 2 +- .../formats/mp4/mp4_media_parser_unittest.cc | 4 +- .../webm/encrypted_segmenter_unittest.cc | 4 +- .../webm/webm_cluster_parser_unittest.cc | 3 +- .../formats/wvm/wvm_media_parser_unittest.cc | 4 +- packager/media/test/packager_test.cc | 11 +- 21 files changed, 384 insertions(+), 195 deletions(-) create mode 100644 packager/media/base/fixed_key_source.cc create mode 100644 packager/media/base/fixed_key_source.h create mode 100644 packager/media/base/fixed_key_source_unittest.cc diff --git a/packager/app/fixed_key_encryption_flags.cc b/packager/app/fixed_key_encryption_flags.cc index 15b537cb9d..9ba3646307 100644 --- a/packager/app/fixed_key_encryption_flags.cc +++ b/packager/app/fixed_key_encryption_flags.cc @@ -22,7 +22,11 @@ DEFINE_string(iv, "", "Iv in hex string format. If not specified, a random iv will be " "generated. This flag should only be used for testing."); -DEFINE_string(pssh, "", "PSSH in hex string format."); +DEFINE_string(pssh, + "", + "One or more PSSH boxes in hex string format. If not specified, " + "will generate a v1 common PSSH box according to " + "https://goo.gl/507mKp."); namespace edash_packager { @@ -51,7 +55,7 @@ bool ValidateFixedCryptoFlags() { if (!ValidateFlag("pssh", FLAGS_pssh, FLAGS_enable_fixed_key_encryption, - false, + true, "--enable_fixed_key_encryption")) { success = false; } diff --git a/packager/app/packager_util.cc b/packager/app/packager_util.cc index 03373f86a4..3c618354d0 100644 --- a/packager/app/packager_util.cc +++ b/packager/app/packager_util.cc @@ -15,6 +15,7 @@ #include "packager/app/widevine_encryption_flags.h" #include "packager/base/logging.h" #include "packager/base/strings/string_number_conversions.h" +#include "packager/media/base/fixed_key_source.h" #include "packager/media/base/media_stream.h" #include "packager/media/base/muxer.h" #include "packager/media/base/muxer_options.h" @@ -100,7 +101,7 @@ scoped_ptr CreateEncryptionKeySource() { } encryption_key_source = widevine_key_source.Pass(); } else if (FLAGS_enable_fixed_key_encryption) { - encryption_key_source = KeySource::CreateFromHexStrings( + encryption_key_source = FixedKeySource::CreateFromHexStrings( FLAGS_key_id, FLAGS_key, FLAGS_pssh, FLAGS_iv); } return encryption_key_source.Pass(); @@ -120,8 +121,10 @@ scoped_ptr CreateDecryptionKeySource() { decryption_key_source = widevine_key_source.Pass(); } else if (FLAGS_enable_fixed_key_decryption) { - decryption_key_source = - KeySource::CreateFromHexStrings(FLAGS_key_id, FLAGS_key, "", ""); + const char kNoPssh[] = ""; + const char kNoIv[] = ""; + decryption_key_source = FixedKeySource::CreateFromHexStrings( + FLAGS_key_id, FLAGS_key, kNoPssh, kNoIv); } return decryption_key_source.Pass(); } diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py index 3bd90625c5..8a8a1c956f 100755 --- a/packager/app/test/packager_test.py +++ b/packager/app/test/packager_test.py @@ -389,10 +389,14 @@ class PackagerAppTest(unittest.TestCase): '--key_server_url=' + widevine_server_url, '--content_id=3031323334353637', '--signer=widevine_test'] elif encryption: + pssh_box = ('000000307073736800000000' # PSSH header + 'edef8ba979d64acea3c827dcd51d21ed' # Widevine system ID + '00000010' # Data size + '31323334353637383930313233343536') # Data flags += ['--enable_fixed_key_encryption', '--key_id=31323334353637383930313233343536', '--key=32333435363738393021323334353637', - '--pssh=31323334353637383930313233343536', '--clear_lead=1'] + '--pssh=' + pssh_box, '--clear_lead=1'] if not random_iv: flags.append('--iv=3334353637383930') if key_rotation: diff --git a/packager/media/base/decryptor_source_unittest.cc b/packager/media/base/decryptor_source_unittest.cc index a595824bd8..be1f99d959 100644 --- a/packager/media/base/decryptor_source_unittest.cc +++ b/packager/media/base/decryptor_source_unittest.cc @@ -10,6 +10,7 @@ #include #include "packager/base/macros.h" +#include "packager/media/base/fixed_key_source.h" using ::testing::Return; using ::testing::SetArgPointee; @@ -50,7 +51,7 @@ const uint8_t kBuffer2[] = {0x05, 0x02}; // Expected decrypted buffer with the above kMockKey and kIv2. const uint8_t kExpectedDecryptedBuffer2[] = {0x20, 0x62}; -class MockKeySource : public KeySource { +class MockKeySource : public FixedKeySource { public: MOCK_METHOD2(GetKey, Status(const std::vector& key_id, EncryptionKey* key)); diff --git a/packager/media/base/fixed_key_source.cc b/packager/media/base/fixed_key_source.cc new file mode 100644 index 0000000000..1eeeeaffe2 --- /dev/null +++ b/packager/media/base/fixed_key_source.cc @@ -0,0 +1,153 @@ +// Copyright 2016 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "packager/media/base/fixed_key_source.h" + +#include "packager/base/logging.h" +#include "packager/base/strings/string_number_conversions.h" + +namespace edash_packager { +namespace media { + +namespace { +// Common SystemID defined by EME, which requires Key System implementations +// supporting ISO Common Encryption to support this SystemID and format. +// http://goo.gl/PHZDAF +const uint8_t kCommonSystemId[] = {0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, + 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, + 0x52, 0xe2, 0xfb, 0x4b}; +} // namespace + +FixedKeySource::~FixedKeySource() {} + +Status FixedKeySource::FetchKeys(const std::vector& pssh_box) { + // Do nothing for fixed key encryption/decryption. + return Status::OK; +} + +Status FixedKeySource::FetchKeys( + const std::vector>& key_ids) { + // Do nothing for fixed key encryption/decryption. + return Status::OK; +} + +Status FixedKeySource::FetchKeys(uint32_t asset_id) { + // Do nothing for fixed key encryption/decryption. + return Status::OK; +} + +Status FixedKeySource::GetKey(TrackType track_type, EncryptionKey* key) { + DCHECK(key); + DCHECK(encryption_key_); + *key = *encryption_key_; + return Status::OK; +} + +Status FixedKeySource::GetKey(const std::vector& key_id, + EncryptionKey* key) { + DCHECK(key); + DCHECK(encryption_key_); + if (key_id != encryption_key_->key_id) { + return Status(error::NOT_FOUND, + std::string("Key for key ID ") + + base::HexEncode(&key_id[0], key_id.size()) + + " was not found."); + } + *key = *encryption_key_; + return Status::OK; +} + +Status FixedKeySource::GetCryptoPeriodKey(uint32_t crypto_period_index, + TrackType track_type, + EncryptionKey* key) { + // Create a copy of the key. + *key = *encryption_key_; + + // A naive key rotation algorithm is implemented here by left rotating the + // key, key_id and pssh. Note that this implementation is only intended for + // testing purpose. The actual key rotation algorithm can be much more + // complicated. + LOG(WARNING) + << "This naive key rotation algorithm should not be used in production."; + std::rotate(key->key_id.begin(), + key->key_id.begin() + (crypto_period_index % key->key_id.size()), + key->key_id.end()); + std::rotate(key->key.begin(), + key->key.begin() + (crypto_period_index % key->key.size()), + key->key.end()); + + for (size_t i = 0; i < key->key_system_info.size(); i++) { + std::vector pssh_data = key->key_system_info[i].pssh_data(); + std::rotate(pssh_data.begin(), + pssh_data.begin() + (crypto_period_index % pssh_data.size()), + pssh_data.end()); + key->key_system_info[i].set_pssh_data(pssh_data); + } + + return Status::OK; +} + +scoped_ptr FixedKeySource::CreateFromHexStrings( + const std::string& key_id_hex, + const std::string& key_hex, + const std::string& pssh_boxes_hex, + const std::string& iv_hex) { + scoped_ptr encryption_key(new EncryptionKey()); + + if (!base::HexStringToBytes(key_id_hex, &encryption_key->key_id)) { + LOG(ERROR) << "Cannot parse key_id_hex " << key_id_hex; + return scoped_ptr(); + } else if (encryption_key->key_id.size() != 16) { + LOG(ERROR) << "Invalid key ID size '" << encryption_key->key_id.size() + << "', must be 16 bytes."; + return scoped_ptr(); + } + + if (!base::HexStringToBytes(key_hex, &encryption_key->key)) { + LOG(ERROR) << "Cannot parse key_hex " << key_hex; + return scoped_ptr(); + } + + std::vector pssh_boxes; + if (!pssh_boxes_hex.empty() && + !base::HexStringToBytes(pssh_boxes_hex, &pssh_boxes)) { + LOG(ERROR) << "Cannot parse pssh_hex " << pssh_boxes_hex; + return scoped_ptr(); + } + + if (!iv_hex.empty()) { + if (!base::HexStringToBytes(iv_hex, &encryption_key->iv)) { + LOG(ERROR) << "Cannot parse iv_hex " << iv_hex; + return scoped_ptr(); + } + } + + if (!ProtectionSystemSpecificInfo::ParseBoxes( + pssh_boxes.data(), pssh_boxes.size(), + &encryption_key->key_system_info)) { + LOG(ERROR) << "--pssh argument should be full PSSH boxes."; + return scoped_ptr(); + } + + // If there aren't any PSSH boxes given, create one with the common system ID. + if (encryption_key->key_system_info.size() == 0) { + ProtectionSystemSpecificInfo info; + info.add_key_id(encryption_key->key_id); + info.set_system_id(kCommonSystemId, arraysize(kCommonSystemId)); + info.set_pssh_box_version(1); + + encryption_key->key_system_info.push_back(info); + } + + return scoped_ptr(new FixedKeySource(encryption_key.Pass())); +} + +FixedKeySource::FixedKeySource() {} +FixedKeySource::FixedKeySource(scoped_ptr key) + : encryption_key_(key.Pass()) {} + +} // namespace media +} // namespace edash_packager diff --git a/packager/media/base/fixed_key_source.h b/packager/media/base/fixed_key_source.h new file mode 100644 index 0000000000..c1d5499ae6 --- /dev/null +++ b/packager/media/base/fixed_key_source.h @@ -0,0 +1,68 @@ +// Copyright 2016 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef MEDIA_BASE_FIXED_KEY_SOURCE_H_ +#define MEDIA_BASE_FIXED_KEY_SOURCE_H_ + +#include +#include + +#include "packager/base/memory/scoped_ptr.h" +#include "packager/media/base/key_source.h" + +namespace edash_packager { +namespace media { + +/// A key source that uses fixed keys for encryption. +class FixedKeySource : public KeySource { + public: + ~FixedKeySource() override; + + /// @name KeySource implementation overrides. + /// @{ + Status FetchKeys(const std::vector& pssh_box) override; + Status FetchKeys(const std::vector>& key_ids) override; + Status FetchKeys(uint32_t asset_id) override; + + Status GetKey(TrackType track_type, EncryptionKey* key) override; + Status GetKey(const std::vector& key_id, + EncryptionKey* key) override; + Status GetCryptoPeriodKey(uint32_t crypto_period_index, + TrackType track_type, + EncryptionKey* key) override; + /// @} + + /// Creates a new FixedKeySource from the given hex strings. Returns null + /// if the strings are invalid. + /// @param key_id_hex is the key id in hex string. + /// @param key_hex is the key in hex string. + /// @param pssh_boxes_hex is the pssh_boxes in hex string. + /// @param iv_hex is the IV in hex string. If not specified, a randomly + /// generated IV with the default length will be used. + /// Note: GetKey on the created key source will always return the same key + /// for all track types. + static scoped_ptr CreateFromHexStrings( + const std::string& key_id_hex, + const std::string& key_hex, + const std::string& pssh_boxes_hex, + const std::string& iv_hex); + + protected: + // Allow default constructor for mock key sources. + FixedKeySource(); + + private: + explicit FixedKeySource(scoped_ptr key); + + scoped_ptr encryption_key_; + + DISALLOW_COPY_AND_ASSIGN(FixedKeySource); +}; + +} // namespace media +} // namespace edash_packager + +#endif // MEDIA_BASE_FIXED_KEY_SOURCE_H_ diff --git a/packager/media/base/fixed_key_source_unittest.cc b/packager/media/base/fixed_key_source_unittest.cc new file mode 100644 index 0000000000..dfc0fffa6e --- /dev/null +++ b/packager/media/base/fixed_key_source_unittest.cc @@ -0,0 +1,99 @@ +// Copyright 2016 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include +#include + +#include "packager/base/strings/string_number_conversions.h" +#include "packager/media/base/fixed_key_source.h" +#include "packager/media/base/test/status_test_util.h" + +#define EXPECT_HEX_EQ(expected, actual) \ + do { \ + std::vector decoded_; \ + ASSERT_TRUE(base::HexStringToBytes((expected), &decoded_)); \ + EXPECT_EQ(decoded_, (actual)); \ + } while (false) + +namespace edash_packager { +namespace media { + +namespace { +const char kKeyIdHex[] = "0101020305080d1522375990e9000000"; +const char kKeyHex[] = "00100100200300500801302103405500"; +const char kIvHex[] = "000102030405060708090a0b0c0d0e0f"; +const char kPsshBox1Hex[] = + "000000427073736801000000" + "020305070b0d1113171d1f25292b2f35" + "00000001" + "0101020305080d1522375990e9000000" + "0000000e" + "6544617368207061636b61676572"; +const char kPsshBox2Hex[] = + "0000002e7073736800000000" + "bbbbbbbbbaaaaaaaaaaaaddddddddddd" + "0000000e" + "fffffffff000000000000ddddddd"; +const char kDefaultPsshBoxHex[] = + "000000347073736801000000" + "1077efecc0b24d02ace33c1e52e2fb4b" + "00000001" + "0101020305080d1522375990e9000000" + "00000000"; +} + +TEST(FixedKeySourceTest, CreateFromHexStrings_Succes) { + std::string pssh_boxes = std::string(kPsshBox1Hex) + kPsshBox2Hex; + scoped_ptr key_source = FixedKeySource::CreateFromHexStrings( + kKeyIdHex, kKeyHex, pssh_boxes, kIvHex); + ASSERT_NE(nullptr, key_source); + + EncryptionKey key; + ASSERT_OK(key_source->GetKey(KeySource::TRACK_TYPE_SD, &key)); + + EXPECT_HEX_EQ(kKeyIdHex, key.key_id); + EXPECT_HEX_EQ(kKeyHex, key.key); + EXPECT_HEX_EQ(kIvHex, key.iv); + + ASSERT_EQ(2u, key.key_system_info.size()); + EXPECT_HEX_EQ(kPsshBox1Hex, key.key_system_info[0].CreateBox()); + EXPECT_HEX_EQ(kPsshBox2Hex, key.key_system_info[1].CreateBox()); +} + +TEST(FixedKeySourceTest, CreateFromHexStrings_EmptyPssh) { + scoped_ptr key_source = FixedKeySource::CreateFromHexStrings( + kKeyIdHex, kKeyHex, "", kIvHex); + ASSERT_NE(nullptr, key_source); + + EncryptionKey key; + ASSERT_OK(key_source->GetKey(KeySource::TRACK_TYPE_SD, &key)); + + EXPECT_HEX_EQ(kKeyIdHex, key.key_id); + EXPECT_HEX_EQ(kKeyHex, key.key); + EXPECT_HEX_EQ(kIvHex, key.iv); + + ASSERT_EQ(1u, key.key_system_info.size()); + EXPECT_HEX_EQ(kDefaultPsshBoxHex, key.key_system_info[0].CreateBox()); +} + +TEST(FixedKeySourceTest, CreateFromHexStrings_Failure) { + scoped_ptr key_source = FixedKeySource::CreateFromHexStrings( + kKeyIdHex, "invalid_hex_value", kPsshBox1Hex, kIvHex); + EXPECT_EQ(nullptr, key_source); + + // Invalid key id size. + key_source = FixedKeySource::CreateFromHexStrings("000102030405", kKeyHex, + kPsshBox1Hex, kIvHex); + EXPECT_EQ(nullptr, key_source); + + // Invalid pssh box. + key_source = FixedKeySource::CreateFromHexStrings(kKeyIdHex, kKeyHex, + "000102030405", kIvHex); + EXPECT_EQ(nullptr, key_source); +} + +} // namespace media +} // namespace edash_packager diff --git a/packager/media/base/key_source.cc b/packager/media/base/key_source.cc index 1f5e8f73f0..f6dda92fee 100644 --- a/packager/media/base/key_source.cc +++ b/packager/media/base/key_source.cc @@ -6,9 +6,7 @@ #include "packager/media/base/key_source.h" -#include "packager/base/strings/string_number_conversions.h" -#include "packager/media/base/aes_encryptor.h" -#include "packager/media/base/buffer_writer.h" +#include "packager/base/logging.h" namespace edash_packager { namespace media { @@ -18,127 +16,6 @@ EncryptionKey::~EncryptionKey() {} KeySource::~KeySource() {} -Status KeySource::FetchKeys(const std::vector& content_id, - const std::string& policy) { - // Do nothing for fixed key encryption/decryption. - return Status::OK; -} - -Status KeySource::FetchKeys(const std::vector& pssh_box) { - // Do nothing for fixed key encryption/decryption. - return Status::OK; -} - -Status KeySource::FetchKeys(const std::vector>& key_ids) { - // Do nothing for fixed key encryption/decryption. - return Status::OK; -} - -Status KeySource::FetchKeys(uint32_t asset_id) { - // Do nothing for fixed key encryption/decryption. - return Status::OK; -} - -Status KeySource::GetKey(TrackType track_type, EncryptionKey* key) { - DCHECK(key); - DCHECK(encryption_key_); - *key = *encryption_key_; - return Status::OK; -} - -Status KeySource::GetKey(const std::vector& key_id, - EncryptionKey* key) { - DCHECK(key); - DCHECK(encryption_key_); - if (key_id != encryption_key_->key_id) { - return Status(error::NOT_FOUND, std::string("Key for key ID ") + - base::HexEncode(&key_id[0], key_id.size()) + - " was not found."); - } - *key = *encryption_key_; - return Status::OK; -} - -Status KeySource::GetCryptoPeriodKey(uint32_t crypto_period_index, - TrackType track_type, - EncryptionKey* key) { - *key = *encryption_key_; - // A naive key rotation algorithm is implemented here by left rotating the - // key, key_id and pssh. Note that this implementation is only intended for - // testing purpose. The actual key rotation algorithm can be much more - // complicated. - LOG(WARNING) - << "This naive key rotation algorithm should not be used in production."; - std::rotate(key->key_id.begin(), - key->key_id.begin() + (crypto_period_index % key->key_id.size()), - key->key_id.end()); - std::rotate(key->key.begin(), - key->key.begin() + (crypto_period_index % key->key.size()), - key->key.end()); - - std::vector pssh_data( - key->key_system_info[0].pssh_data().begin(), - key->key_system_info[0].pssh_data().end()); - std::rotate(pssh_data.begin(), - pssh_data.begin() + (crypto_period_index % pssh_data.size()), - pssh_data.end()); - - // Since this should only be used for testing, use the Widevine system id. - // TODO(modmaker): Change to FixedKeySource - ProtectionSystemSpecificInfo info; - info.add_key_id(key->key_id); - info.set_system_id(kWidevineSystemId, arraysize(kWidevineSystemId)); - info.set_pssh_box_version(0); - info.set_pssh_data(pssh_data); - - key->key_system_info.clear(); - key->key_system_info.push_back(info); - - return Status::OK; -} - -scoped_ptr KeySource::CreateFromHexStrings( - const std::string& key_id_hex, - const std::string& key_hex, - const std::string& pssh_data_hex, - const std::string& iv_hex) { - scoped_ptr encryption_key(new EncryptionKey()); - - if (!base::HexStringToBytes(key_id_hex, &encryption_key->key_id)) { - LOG(ERROR) << "Cannot parse key_id_hex " << key_id_hex; - return scoped_ptr(); - } - - if (!base::HexStringToBytes(key_hex, &encryption_key->key)) { - LOG(ERROR) << "Cannot parse key_hex " << key_hex; - return scoped_ptr(); - } - - std::vector pssh_data; - if (!pssh_data_hex.empty() && - !base::HexStringToBytes(pssh_data_hex, &pssh_data)) { - LOG(ERROR) << "Cannot parse pssh_hex " << pssh_data_hex; - return scoped_ptr(); - } - - if (!iv_hex.empty()) { - if (!base::HexStringToBytes(iv_hex, &encryption_key->iv)) { - LOG(ERROR) << "Cannot parse iv_hex " << iv_hex; - return scoped_ptr(); - } - } - - // TODO(modmaker): Change to FixedKeySource - ProtectionSystemSpecificInfo info; - info.add_key_id(encryption_key->key_id); - info.set_system_id(kWidevineSystemId, arraysize(kWidevineSystemId)); - info.set_pssh_box_version(0); - info.set_pssh_data(pssh_data); - - encryption_key->key_system_info.push_back(info); - return scoped_ptr(new KeySource(encryption_key.Pass())); -} - KeySource::TrackType KeySource::GetTrackTypeFromString( const std::string& track_type_string) { if (track_type_string == "SD") @@ -168,10 +45,6 @@ std::string KeySource::TrackTypeToString(TrackType track_type) { } KeySource::KeySource() {} -KeySource::KeySource(scoped_ptr encryption_key) - : encryption_key_(encryption_key.Pass()) { - DCHECK(encryption_key_); -} } // namespace media } // namespace edash_packager diff --git a/packager/media/base/key_source.h b/packager/media/base/key_source.h index 727d407c0c..f483dfb634 100644 --- a/packager/media/base/key_source.h +++ b/packager/media/base/key_source.h @@ -17,10 +17,6 @@ namespace edash_packager { namespace media { -const uint8_t kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, - 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc, - 0xd5, 0x1d, 0x21, 0xed}; - struct EncryptionKey { EncryptionKey(); ~EncryptionKey(); @@ -43,44 +39,40 @@ class KeySource { NUM_VALID_TRACK_TYPES = 4 }; + KeySource(); virtual ~KeySource(); - /// Fetch keys for CENC from the key server. - /// @param content_id the unique id identify the content. - /// @param policy specifies the DRM content rights. - /// @return OK on success, an error status otherwise. - virtual Status FetchKeys(const std::vector& content_id, - const std::string& policy); - /// Fetch keys for CENC from the key server. /// @param pssh_box The entire PSSH box for the content to be decrypted /// @return OK on success, an error status otherwise. - virtual Status FetchKeys(const std::vector& pssh_box); + virtual Status FetchKeys(const std::vector& pssh_box) = 0; /// Fetch keys for CENC from the key server. /// @param key_ids the key IDs for the keys to fetch from the server. /// @return OK on success, an error status otherwise. - virtual Status FetchKeys(const std::vector>& key_ids); + virtual Status FetchKeys( + const std::vector>& key_ids) = 0; /// Fetch keys for WVM decryption from the key server. /// @param asset_id is the Widevine Classic asset ID for the content to be /// decrypted. /// @return OK on success, an error status otherwise. - virtual Status FetchKeys(uint32_t asset_id); + virtual Status FetchKeys(uint32_t asset_id) = 0; /// Get encryption key of the specified track type. /// @param track_type is the type of track for which retrieving the key. /// @param key is a pointer to the EncryptionKey which will hold the retrieved /// key. Owner retains ownership, and may not be NULL. /// @return OK on success, an error status otherwise. - virtual Status GetKey(TrackType track_type, EncryptionKey* key); + virtual Status GetKey(TrackType track_type, EncryptionKey* key) = 0; /// Get the encryption key specified by the CENC key ID. /// @param key_id is the unique identifier for the key being retreived. /// @param key is a pointer to the EncryptionKey which will hold the retrieved /// key. Owner retains ownership, and may not be NULL. /// @return OK on success, or an error status otherwise. - virtual Status GetKey(const std::vector& key_id, EncryptionKey* key); + virtual Status GetKey(const std::vector& key_id, + EncryptionKey* key) = 0; /// Get encryption key of the specified track type at the specified index. /// @param crypto_period_index is the sequence number of the key rotation @@ -91,21 +83,7 @@ class KeySource { /// @return OK on success, an error status otherwise. virtual Status GetCryptoPeriodKey(uint32_t crypto_period_index, TrackType track_type, - EncryptionKey* key); - - /// Create KeySource object from hex strings. - /// @param key_id_hex is the key id in hex string. - /// @param key_hex is the key in hex string. - /// @param pssh_data_hex is the pssh_data in hex string. - /// @param iv_hex is the IV in hex string. If not specified, a randomly - /// generated IV with the default length will be used. - /// Note: GetKey on the created key source will always return the same key - /// for all track types. - static scoped_ptr CreateFromHexStrings( - const std::string& key_id_hex, - const std::string& key_hex, - const std::string& pssh_data_hex, - const std::string& iv_hex); + EncryptionKey* key) = 0; /// Convert string representation of track type to enum representation. static TrackType GetTrackTypeFromString(const std::string& track_type_string); @@ -113,14 +91,7 @@ class KeySource { /// Convert TrackType to string. static std::string TrackTypeToString(TrackType track_type); - protected: - KeySource(); - private: - explicit KeySource(scoped_ptr encryption_key); - - scoped_ptr encryption_key_; - DISALLOW_COPY_AND_ASSIGN(KeySource); }; diff --git a/packager/media/base/media_base.gyp b/packager/media/base/media_base.gyp index f1e64be7d5..8f40c0c92f 100644 --- a/packager/media/base/media_base.gyp +++ b/packager/media/base/media_base.gyp @@ -40,6 +40,8 @@ 'decryptor_source.cc', 'decryptor_source.h', 'encryption_modes.h', + 'fixed_key_source.cc', + 'fixed_key_source.h', 'http_key_fetcher.cc', 'http_key_fetcher.h', 'key_fetcher.cc', @@ -118,6 +120,7 @@ 'closure_thread_unittest.cc', 'container_names_unittest.cc', 'decryptor_source_unittest.cc', + 'fixed_key_source_unittest.cc', 'http_key_fetcher_unittest.cc', 'muxer_util_unittest.cc', 'offset_byte_queue_unittest.cc', diff --git a/packager/media/base/widevine_key_source.cc b/packager/media/base/widevine_key_source.cc index ae5b75a09e..b31d9cc335 100644 --- a/packager/media/base/widevine_key_source.cc +++ b/packager/media/base/widevine_key_source.cc @@ -47,6 +47,10 @@ const int kDefaultCryptoPeriodCount = 10; const int kGetKeyTimeoutInSeconds = 5 * 60; // 5 minutes. const int kKeyFetchTimeoutInSeconds = 60; // 1 minute. +const uint8_t kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, + 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc, + 0xd5, 0x1d, 0x21, 0xed}; + bool Base64StringToBytes(const std::string& base64_string, std::vector* bytes) { DCHECK(bytes); diff --git a/packager/media/base/widevine_key_source.h b/packager/media/base/widevine_key_source.h index 8e8b4c4d30..9d3340da31 100644 --- a/packager/media/base/widevine_key_source.h +++ b/packager/media/base/widevine_key_source.h @@ -32,8 +32,6 @@ class WidevineKeySource : public KeySource { /// @name KeySource implementation overrides. /// @{ - Status FetchKeys(const std::vector& content_id, - const std::string& policy) override; Status FetchKeys(const std::vector& pssh_box) override; Status FetchKeys(const std::vector>& key_ids) override; Status FetchKeys(uint32_t asset_id) override; @@ -46,6 +44,13 @@ class WidevineKeySource : public KeySource { EncryptionKey* key) override; /// @} + /// Fetch keys for CENC from the key server. + /// @param content_id the unique id identify the content. + /// @param policy specifies the DRM content rights. + /// @return OK on success, an error status otherwise. + Status FetchKeys(const std::vector& content_id, + const std::string& policy); + /// Set signer for the key source. /// @param signer signs the request message. void set_signer(scoped_ptr signer); diff --git a/packager/media/event/mpd_notify_muxer_listener_unittest.cc b/packager/media/event/mpd_notify_muxer_listener_unittest.cc index f3a46c8e60..1eea88ea12 100644 --- a/packager/media/event/mpd_notify_muxer_listener_unittest.cc +++ b/packager/media/event/mpd_notify_muxer_listener_unittest.cc @@ -154,7 +154,7 @@ TEST_F(MpdNotifyMuxerListenerTest, VodEncryptedContent) { std::string(kExpectedDefaultMediaInfo) + "protected_content {\n" " content_protection_entry {\n" - " uuid: 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'\n" + " uuid: '00010203-0405-0607-0809-0a0b0c0d0e0f'\n" " pssh: '" + std::string(kExpectedDefaultPsshBox) + "'\n" " }\n" " default_key_id: 'defaultkeyid'\n" @@ -286,7 +286,7 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) { "protected_content {\n" " default_key_id: \"defaultkeyid\"\n" " content_protection_entry {\n" - " uuid: 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'\n" + " uuid: '00010203-0405-0607-0809-0a0b0c0d0e0f'\n" " pssh: \"" + std::string(kExpectedDefaultPsshBox) + "\"\n" " }\n" "}\n"; diff --git a/packager/media/event/muxer_listener_test_helper.cc b/packager/media/event/muxer_listener_test_helper.cc index c03075cdf4..5ee9788452 100644 --- a/packager/media/event/muxer_listener_test_helper.cc +++ b/packager/media/event/muxer_listener_test_helper.cc @@ -96,9 +96,12 @@ void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) { std::vector GetDefaultKeySystemInfo() { const uint8_t kPsshData[] = {'p', 's', 's', 'h'}; + const uint8_t kTestSystemId[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f}; ProtectionSystemSpecificInfo info; - info.set_system_id(kWidevineSystemId, arraysize(kWidevineSystemId)); + info.set_system_id(kTestSystemId, arraysize(kTestSystemId)); info.set_pssh_data( std::vector(kPsshData, kPsshData + arraysize(kPsshData))); info.set_pssh_box_version(0); diff --git a/packager/media/event/muxer_listener_test_helper.h b/packager/media/event/muxer_listener_test_helper.h index c2b4cbbf41..e655446a82 100644 --- a/packager/media/event/muxer_listener_test_helper.h +++ b/packager/media/event/muxer_listener_test_helper.h @@ -25,8 +25,8 @@ namespace media { // This is a full v0 PSSH box with the Widevine system ID and the PSSH data // 'pssh' const char kExpectedDefaultPsshBox[] = - "\\000\\000\\000$pssh\\000\\000\\000\\000\\355\\357\\213\\251y\\326J\\316" - "\\243\\310\\'\\334\\325\\035!\\355\\000\\000\\000\\4pssh"; + "\\000\\000\\000$pssh\\000\\000\\000\\000\\000\\001\\002\\003\\004\\005" + "\\006\\007\\010\\t\\n\\013\\014\\r\\016\\017\\000\\000\\000\\004pssh"; const char kExpectedDefaultMediaInfo[] = "bandwidth: 7620\n" "video_info {\n" diff --git a/packager/media/event/vod_media_info_dump_muxer_listener_unittest.cc b/packager/media/event/vod_media_info_dump_muxer_listener_unittest.cc index 950fec1f6b..0a550e8282 100644 --- a/packager/media/event/vod_media_info_dump_muxer_listener_unittest.cc +++ b/packager/media/event/vod_media_info_dump_muxer_listener_unittest.cc @@ -179,7 +179,7 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) { "media_duration_seconds: 10.5\n" "protected_content {\n" " content_protection_entry {\n" - " uuid: 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'\n" + " uuid: '00010203-0405-0607-0809-0a0b0c0d0e0f'\n" " pssh: '" + std::string(kExpectedDefaultPsshBox) + "'\n" " }\n" " default_key_id: '_default_key_id_'\n" diff --git a/packager/media/formats/mp4/mp4_media_parser_unittest.cc b/packager/media/formats/mp4/mp4_media_parser_unittest.cc index 4668fcce44..0244cc9428 100644 --- a/packager/media/formats/mp4/mp4_media_parser_unittest.cc +++ b/packager/media/formats/mp4/mp4_media_parser_unittest.cc @@ -9,7 +9,7 @@ #include "packager/base/bind.h" #include "packager/base/logging.h" -#include "packager/media/base/key_source.h" +#include "packager/media/base/fixed_key_source.h" #include "packager/media/base/media_sample.h" #include "packager/media/base/stream_info.h" #include "packager/media/base/video_stream_info.h" @@ -29,7 +29,7 @@ const char kKey[] = "\xeb\xdd\x62\xf1\x68\x14\xd2\x7b\x68\xef\x12\x2a\xfc\xe4\xae\x3c"; const char kKeyId[] = "0123456789012345"; -class MockKeySource : public KeySource { +class MockKeySource : public FixedKeySource { public: MOCK_METHOD1(FetchKeys, Status(const std::vector& pssh_data)); MOCK_METHOD2(GetKey, diff --git a/packager/media/formats/webm/encrypted_segmenter_unittest.cc b/packager/media/formats/webm/encrypted_segmenter_unittest.cc index df79d9719a..cb9c2f3933 100644 --- a/packager/media/formats/webm/encrypted_segmenter_unittest.cc +++ b/packager/media/formats/webm/encrypted_segmenter_unittest.cc @@ -8,6 +8,7 @@ #include #include "packager/base/memory/scoped_ptr.h" +#include "packager/media/base/fixed_key_source.h" #include "packager/media/formats/webm/segmenter_test_base.h" namespace edash_packager { @@ -189,7 +190,8 @@ class EncrypedSegmenterTest : public SegmentTestBase { protected: void InitializeSegmenter(const MuxerOptions& options) { - key_source_ = KeySource::CreateFromHexStrings(kKeyId, kKey, kPsshData, kIv); + key_source_ = + FixedKeySource::CreateFromHexStrings(kKeyId, kKey, kPsshData, kIv); ASSERT_NO_FATAL_FAILURE( CreateAndInitializeSegmenter( options, info_.get(), key_source_.get(), &segmenter_)); diff --git a/packager/media/formats/webm/webm_cluster_parser_unittest.cc b/packager/media/formats/webm/webm_cluster_parser_unittest.cc index 4013f69528..0eb1a583a8 100644 --- a/packager/media/formats/webm/webm_cluster_parser_unittest.cc +++ b/packager/media/formats/webm/webm_cluster_parser_unittest.cc @@ -16,6 +16,7 @@ #include "packager/base/logging.h" #include "packager/base/strings/string_number_conversions.h" #include "packager/media/base/decrypt_config.h" +#include "packager/media/base/fixed_key_source.h" #include "packager/media/base/timestamp.h" #include "packager/media/formats/webm/cluster_builder.h" #include "packager/media/formats/webm/webm_constants.h" @@ -171,7 +172,7 @@ const uint8_t kVP9Frame[] = { 0xe1, 0xe6, 0xef, 0xff, 0xfd, 0xf7, 0x4f, 0x0f, }; -class MockKeySource : public KeySource { +class MockKeySource : public FixedKeySource { public: MOCK_METHOD2(GetKey, Status(const std::vector& key_id, EncryptionKey* key)); diff --git a/packager/media/formats/wvm/wvm_media_parser_unittest.cc b/packager/media/formats/wvm/wvm_media_parser_unittest.cc index 9bd2196c47..4286e49f69 100644 --- a/packager/media/formats/wvm/wvm_media_parser_unittest.cc +++ b/packager/media/formats/wvm/wvm_media_parser_unittest.cc @@ -13,12 +13,12 @@ #include "packager/base/logging.h" #include "packager/base/memory/ref_counted.h" #include "packager/media/base/audio_stream_info.h" +#include "packager/media/base/fixed_key_source.h" #include "packager/media/base/media_sample.h" #include "packager/media/base/request_signer.h" #include "packager/media/base/stream_info.h" #include "packager/media/base/timestamp.h" #include "packager/media/base/video_stream_info.h" -#include "packager/media/base/key_source.h" #include "packager/media/formats/wvm/wvm_media_parser.h" #include "packager/media/test/test_data_util.h" @@ -49,7 +49,7 @@ using ::testing::SetArgPointee; namespace edash_packager { namespace media { -class MockKeySource : public KeySource { +class MockKeySource : public FixedKeySource { public: MockKeySource() {} ~MockKeySource() override {} diff --git a/packager/media/test/packager_test.cc b/packager/media/test/packager_test.cc index 183ecd0cd6..7b84182660 100644 --- a/packager/media/test/packager_test.cc +++ b/packager/media/test/packager_test.cc @@ -12,7 +12,7 @@ #include "packager/base/time/clock.h" #include "packager/media/base/demuxer.h" #include "packager/media/base/encryption_modes.h" -#include "packager/media/base/key_source.h" +#include "packager/media/base/fixed_key_source.h" #include "packager/media/base/media_stream.h" #include "packager/media/base/muxer.h" #include "packager/media/base/stream_info.h" @@ -54,10 +54,6 @@ const char kNoLanguageOverride[] = ""; // Encryption constants. const char kKeyIdHex[] = "e5007e6e9dcd5ac095202ed3758382cd"; const char kKeyHex[] = "6fc96fe628a265b13aeddec0bc421f4d"; -const char kPsshHex[] = - "08011210e5007e6e9dcd5ac095202ed3" - "758382cd1a0d7769646576696e655f746573742211544553545f" - "434f4e54454e545f49445f312a025344"; const double kClearLeadInSeconds = 1.5; const double kCryptoDurationInSeconds = 0; // Key rotation is disabled. @@ -160,8 +156,7 @@ void PackagerTestBasic::Remux(const std::string& input, ASSERT_OK(demuxer.Initialize()); scoped_ptr encryption_key_source( - KeySource::CreateFromHexStrings( - kKeyIdHex, kKeyHex, kPsshHex, "")); + FixedKeySource::CreateFromHexStrings(kKeyIdHex, kKeyHex, "", "")); DCHECK(encryption_key_source); scoped_ptr muxer_video; @@ -219,7 +214,7 @@ void PackagerTestBasic::Decrypt(const std::string& input, Demuxer demuxer(GetFullPath(input)); scoped_ptr decryption_key_source( - KeySource::CreateFromHexStrings(kKeyIdHex, kKeyHex, "", "")); + FixedKeySource::CreateFromHexStrings(kKeyIdHex, kKeyHex, "", "")); ASSERT_TRUE(decryption_key_source); demuxer.SetKeySource(decryption_key_source.Pass()); ASSERT_OK(demuxer.Initialize());