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());