Move hex string out of packager.h

Also added validation failure tests in packager_test.py.

Change-Id: I6697a3138d57889110250404205536dd5cd53cd0
This commit is contained in:
KongQun Yang 2017-06-14 16:18:16 -07:00
parent abbd495ad4
commit 03889e6465
25 changed files with 520 additions and 304 deletions

View File

@ -16,13 +16,15 @@ DEFINE_bool(enable_fixed_key_encryption,
DEFINE_bool(enable_fixed_key_decryption,
false,
"Enable decryption with fixed key.");
DEFINE_string(key_id, "", "Key id in hex string format.");
DEFINE_string(key, "", "Key in hex string format.");
DEFINE_string(iv,
DEFINE_hex_bytes(key_id, "", "Key id in hex string format.");
DEFINE_hex_bytes(key, "", "Key in hex string format.");
DEFINE_hex_bytes(
iv,
"",
"Iv in hex string format. If not specified, a random iv will be "
"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,
DEFINE_hex_bytes(
pssh,
"",
"One or more PSSH boxes in hex string format. If not specified, "
"will generate a v1 common PSSH box as specified in "
@ -38,20 +40,20 @@ bool ValidateFixedCryptoFlags() {
const char fixed_crypto_label[] = "--enable_fixed_key_encryption/decryption";
// --key_id and --key are associated with --enable_fixed_key_encryption and
// --enable_fixed_key_decryption.
if (!ValidateFlag(
"key_id", FLAGS_key_id, fixed_crypto, false, fixed_crypto_label)) {
if (!ValidateFlag("key_id", FLAGS_key_id_bytes, fixed_crypto, false,
fixed_crypto_label)) {
success = false;
}
if (!ValidateFlag(
"key", FLAGS_key, fixed_crypto, false, fixed_crypto_label)) {
if (!ValidateFlag("key", FLAGS_key_bytes, fixed_crypto, false,
fixed_crypto_label)) {
success = false;
}
if (!ValidateFlag("iv", FLAGS_iv, FLAGS_enable_fixed_key_encryption, true,
"--enable_fixed_key_encryption")) {
if (!ValidateFlag("iv", FLAGS_iv_bytes, FLAGS_enable_fixed_key_encryption,
true, "--enable_fixed_key_encryption")) {
success = false;
}
if (!FLAGS_iv.empty()) {
if (FLAGS_iv.size() != 8 * 2 && FLAGS_iv.size() != 16 * 2) {
if (!FLAGS_iv_bytes.empty()) {
if (FLAGS_iv_bytes.size() != 8 && FLAGS_iv_bytes.size() != 16) {
PrintError(
"--iv should be either 8 bytes (16 hex digits) or 16 bytes (32 hex "
"digits).");
@ -60,11 +62,8 @@ bool ValidateFixedCryptoFlags() {
}
// --pssh is associated with --enable_fix_key_encryption.
if (!ValidateFlag("pssh",
FLAGS_pssh,
FLAGS_enable_fixed_key_encryption,
true,
"--enable_fixed_key_encryption")) {
if (!ValidateFlag("pssh", FLAGS_pssh_bytes, FLAGS_enable_fixed_key_encryption,
true, "--enable_fixed_key_encryption")) {
success = false;
}
return success;

View File

@ -11,13 +11,15 @@
#include <gflags/gflags.h>
#include "packager/app/gflags_hex_bytes.h"
// TODO(kqyang): s/fixed/raw/.
DECLARE_bool(enable_fixed_key_encryption);
DECLARE_bool(enable_fixed_key_decryption);
DECLARE_string(key_id);
DECLARE_string(key);
DECLARE_string(iv);
DECLARE_string(pssh);
DECLARE_hex_bytes(key_id);
DECLARE_hex_bytes(key);
DECLARE_hex_bytes(iv);
DECLARE_hex_bytes(pssh);
namespace shaka {

View File

@ -0,0 +1,25 @@
// Copyright 2017 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/app/gflags_hex_bytes.h"
#include "packager/base/strings/string_number_conversions.h"
namespace shaka {
bool ValidateHexString(const char* flagname,
const std::string& value,
std::vector<uint8_t>* value_bytes) {
std::vector<uint8_t> temp_value_bytes;
if (!value.empty() && !base::HexStringToBytes(value, &temp_value_bytes)) {
printf("Invalid hex string for --%s: %s\n", flagname, value.c_str());
return false;
}
value_bytes->swap(temp_value_bytes);
return true;
}
} // namespace shaka

View File

@ -0,0 +1,50 @@
// Copyright 2017 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
//
// Extends gflags to support hex formatted bytes.
#ifndef PACKAGER_APP_GFLAGS_HEX_BYTES_H_
#define PACKAGER_APP_GFLAGS_HEX_BYTES_H_
#include <gflags/gflags.h>
#include <string>
#include <vector>
namespace shaka {
bool ValidateHexString(const char* flagname,
const std::string& value,
std::vector<uint8_t>* value_bytes);
} // namespace shaka
// The raw bytes will be available in FLAGS_##name##_bytes.
// The original gflag variable FLAGS_##name is defined in shaka_gflags_extension
// and not exposed directly.
#define DECLARE_hex_bytes(name) \
namespace shaka_gflags_extension { \
DECLARE_string(name); \
} \
namespace shaka_gflags_extension { \
extern std::vector<uint8_t> FLAGS_##name##_bytes; \
} \
using shaka_gflags_extension::FLAGS_##name##_bytes
#define DEFINE_hex_bytes(name, val, txt) \
namespace shaka_gflags_extension { \
DEFINE_string(name, val, txt); \
} \
namespace shaka_gflags_extension { \
std::vector<uint8_t> FLAGS_##name##_bytes; \
static bool hex_validator_##name = gflags::RegisterFlagValidator( \
&FLAGS_##name, \
[](const char* flagname, const std::string& value) { \
return shaka::ValidateHexString(flagname, value, \
&FLAGS_##name##_bytes); \
}); \
} \
using shaka_gflags_extension::FLAGS_##name##_bytes
#endif // PACKAGER_APP_GFLAGS_HEX_BYTES_H_

View File

@ -97,6 +97,24 @@ enum ExitStatus {
kInternalError,
};
bool GetWidevineSigner(WidevineSigner* signer) {
signer->signer_name = FLAGS_signer;
if (!FLAGS_aes_signing_key_bytes.empty()) {
signer->signing_key_type = WidevineSigner::SigningKeyType::kAes;
signer->aes.key = FLAGS_aes_signing_key_bytes;
signer->aes.iv = FLAGS_aes_signing_iv_bytes;
} else if (!FLAGS_rsa_signing_key_path.empty()) {
signer->signing_key_type = WidevineSigner::SigningKeyType::kRsa;
if (!media::File::ReadFileToString(FLAGS_rsa_signing_key_path.c_str(),
&signer->rsa.key)) {
LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path
<< "'.";
return false;
}
}
return true;
}
base::Optional<PackagingParams> GetPackagingParams() {
PackagingParams packaging_params;
@ -143,33 +161,10 @@ base::Optional<PackagingParams> GetPackagingParams() {
widevine.key_server_url = FLAGS_key_server_url;
widevine.include_common_pssh = FLAGS_include_common_pssh;
if (!base::HexStringToBytes(FLAGS_content_id, &widevine.content_id)) {
LOG(ERROR) << "Invalid content_id hex string specified.";
return base::nullopt;
}
widevine.content_id = FLAGS_content_id_bytes;
widevine.policy = FLAGS_policy;
widevine.signer.signer_name = FLAGS_signer;
if (!FLAGS_aes_signing_key.empty() && !FLAGS_rsa_signing_key_path.empty()) {
LOG(ERROR) << "Only one of --aes_signing_key and "
"--rsa_signing_key_path is needed.";
if (!GetWidevineSigner(&widevine.signer))
return base::nullopt;
}
WidevineSigner& signer = widevine.signer;
if (!FLAGS_aes_signing_key.empty()) {
// TODO(kqyang): Take care of hex conversion and file read here.
signer.signing_key_type = WidevineSigner::SigningKeyType::kAes;
signer.aes.key = FLAGS_aes_signing_key;
signer.aes.iv = FLAGS_aes_signing_iv;
}
if (!FLAGS_rsa_signing_key_path.empty()) {
signer.signing_key_type = WidevineSigner::SigningKeyType::kRsa;
if (!media::File::ReadFileToString(FLAGS_rsa_signing_key_path.c_str(),
&signer.rsa.key)) {
LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path
<< "'.";
return base::nullopt;
}
}
break;
}
case KeyProvider::kPlayready: {
@ -182,19 +177,18 @@ base::Optional<PackagingParams> GetPackagingParams() {
FLAGS_client_cert_private_key_file;
playready.client_cert_private_key_password =
FLAGS_client_cert_private_key_password;
playready.key_id = FLAGS_playready_key_id;
playready.key = FLAGS_playready_key;
playready.key_id = FLAGS_playready_key_id_bytes;
playready.key = FLAGS_playready_key_bytes;
break;
}
case KeyProvider::kRawKey: {
RawKeyEncryptionParams& raw_key = encryption_params.raw_key;
raw_key.iv = FLAGS_iv;
raw_key.pssh = FLAGS_pssh;
// An empty TrackType specifies the default KeyPair.
raw_key.iv = FLAGS_iv_bytes;
raw_key.pssh = FLAGS_pssh_bytes;
// An empty StreamLabel specifies the default KeyPair.
RawKeyEncryptionParams::KeyPair& key_pair = raw_key.key_map[""];
// TODO(kqyang): Take care of hex conversion here.
key_pair.key_id = FLAGS_key_id;
key_pair.key = FLAGS_key;
key_pair.key_id = FLAGS_key_id_bytes;
key_pair.key = FLAGS_key_bytes;
break;
}
case KeyProvider::kNone:
@ -220,42 +214,20 @@ base::Optional<PackagingParams> GetPackagingParams() {
case KeyProvider::kWidevine: {
WidevineDecryptionParams& widevine = decryption_params.widevine;
widevine.key_server_url = FLAGS_key_server_url;
widevine.signer.signer_name = FLAGS_signer;
if (!FLAGS_aes_signing_key.empty() && !FLAGS_rsa_signing_key_path.empty()) {
LOG(ERROR) << "Only one of --aes_signing_key and "
"--rsa_signing_key_path is needed.";
if (!GetWidevineSigner(&widevine.signer))
return base::nullopt;
}
WidevineSigner& signer = widevine.signer;
if (!FLAGS_aes_signing_key.empty()) {
// TODO(kqyang): Take care of hex conversion and file read here.
signer.signing_key_type = WidevineSigner::SigningKeyType::kAes;
signer.aes.key = FLAGS_aes_signing_key;
signer.aes.iv = FLAGS_aes_signing_iv;
}
if (!FLAGS_rsa_signing_key_path.empty()) {
signer.signing_key_type = WidevineSigner::SigningKeyType::kRsa;
if (!media::File::ReadFileToString(FLAGS_rsa_signing_key_path.c_str(),
&signer.rsa.key)) {
LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path
<< "'.";
return base::nullopt;
}
}
break;
}
case KeyProvider::kRawKey: {
RawKeyDecryptionParams& raw_key = decryption_params.raw_key;
// An empty TrackType specifies the default KeyPair.
// An empty StreamLabel specifies the default KeyPair.
RawKeyDecryptionParams::KeyPair& key_pair = raw_key.key_map[""];
// TODO(kqyang): Take care of hex conversion here.
key_pair.key_id = FLAGS_key_id;
key_pair.key = FLAGS_key;
key_pair.key_id = FLAGS_key_id_bytes;
key_pair.key = FLAGS_key_bytes;
break;
}
case KeyProvider::kNone:
case KeyProvider::kPlayready:
case KeyProvider::kNone:
break;
}

View File

@ -103,7 +103,7 @@ std::unique_ptr<KeySource> CreateEncryptionKeySource(
const RawKeyEncryptionParams& raw_key = encryption_params.raw_key;
const std::string kDefaultTrackType;
// TODO(kqyang): Refactor FixedKeySource.
encryption_key_source = FixedKeySource::CreateFromHexStrings(
encryption_key_source = FixedKeySource::Create(
raw_key.key_map.find("")->second.key_id,
raw_key.key_map.find("")->second.key, raw_key.pssh, raw_key.iv);
break;
@ -171,9 +171,9 @@ std::unique_ptr<KeySource> CreateDecryptionKeySource(
}
case KeyProvider::kRawKey: {
const RawKeyDecryptionParams& raw_key = decryption_params.raw_key;
const char kNoPssh[] = "";
const char kNoIv[] = "";
decryption_key_source = FixedKeySource::CreateFromHexStrings(
const std::vector<uint8_t> kNoPssh;
const std::vector<uint8_t> kNoIv;
decryption_key_source = FixedKeySource::Create(
raw_key.key_map.find("")->second.key_id,
raw_key.key_map.find("")->second.key, kNoPssh, kNoIv);
break;

View File

@ -16,8 +16,8 @@ DEFINE_bool(enable_playready_encryption,
DEFINE_string(playready_server_url, "", "PlayReady packaging server url.");
DEFINE_string(program_identifier, "",
"Program identifier for packaging request.");
DEFINE_string(playready_key_id, "", "PlayReady key id in hex.");
DEFINE_string(playready_key, "", "PlayReady key in hex.");
DEFINE_hex_bytes(playready_key_id, "", "PlayReady key id in hex.");
DEFINE_hex_bytes(playready_key, "", "PlayReady key in hex.");
DEFINE_string(ca_file, "",
"Absolute path to the Certificate Authority file for the "
"server cert. PEM format");
@ -45,16 +45,16 @@ bool ValidatePRCryptoFlags() {
}
bool use_packaging = !FLAGS_playready_server_url.empty() &&
!FLAGS_program_identifier.empty();
if (!ValidateFlag("playready_key_id", FLAGS_playready_key_id,
if (!ValidateFlag("playready_key_id", FLAGS_playready_key_id_bytes,
playready_enabled, true, playready_label)) {
success = false;
}
if (!ValidateFlag("playready_key", FLAGS_playready_key,
if (!ValidateFlag("playready_key", FLAGS_playready_key_bytes,
playready_enabled, true, playready_label)) {
success = false;
}
bool use_fixed_key = !FLAGS_playready_key_id.empty() &&
!FLAGS_playready_key.empty();
bool use_fixed_key = !FLAGS_playready_key_id_bytes.empty() &&
!FLAGS_playready_key_bytes.empty();
if (playready_enabled && !use_packaging && !use_fixed_key) {
PrintError("combination of --playready_server_url and "

View File

@ -11,11 +11,13 @@
#include <gflags/gflags.h>
#include "packager/app/gflags_hex_bytes.h"
DECLARE_bool(enable_playready_encryption);
DECLARE_string(playready_server_url);
DECLARE_string(program_identifier);
DECLARE_string(playready_key_id);
DECLARE_string(playready_key);
DECLARE_hex_bytes(playready_key_id);
DECLARE_hex_bytes(playready_key);
DECLARE_string(ca_file);
DECLARE_string(client_cert_file);
DECLARE_string(client_cert_private_key_file);

View File

@ -52,8 +52,9 @@ class PackagerApp(object):
# Put single-quotes around each entry so that things like '$' signs in
# segment templates won't be interpreted as shell variables.
self.packaging_command_line = ' '.join(["'%s'" % entry for entry in cmd])
assert 0 == subprocess.call(cmd), ('%s returned non-0 status' %
self.packaging_command_line)
self.packaging_result = subprocess.call(cmd)
if self.packaging_result != 0:
print '%s returned non-0 status' % self.packaging_command_line
def GetCommandLine(self):
return self.packaging_command_line

View File

@ -42,6 +42,18 @@ class PackagerAppTest(unittest.TestCase):
self.hls_master_playlist_output = self.output_prefix + '.m3u8'
self.output = None
# Test variables.
self.encryption_key_id = '31323334353637383930313233343536'
if test_env.options.encryption_key:
self.encryption_key = test_env.options.encryption_key
else:
self.encryption_key = '32333435363738393021323334353637'
if test_env.options.encryption_iv:
self.encryption_iv = test_env.options.encryption_iv
else:
self.encryption_iv = '3334353637383930'
self.widevine_content_id = '3031323334353637'
def tearDown(self):
if test_env.options.remove_temp_files_after_test:
shutil.rmtree(self.tmp_dir)
@ -83,6 +95,7 @@ class PackagerAppTest(unittest.TestCase):
def testPackageFirstStream(self):
self.packager.Package(self._GetStreams(['0']), self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-v-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-v-golden.mpd')
@ -90,6 +103,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['text'], test_files=['subtitle-english.vtt']),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'subtitle-english-golden.vtt')
self._DiffGold(self.mpd_output, 'subtitle-english-vtt-golden.mpd')
@ -97,6 +111,7 @@ class PackagerAppTest(unittest.TestCase):
def testPackageAudioVideo(self):
self.packager.Package(
self._GetStreams(['audio', 'video']), self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-av-golden.mpd')
@ -105,6 +120,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1']),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-golden.mp4')
@ -115,6 +131,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1',
'video,trick_play_factor=2']),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-golden.mp4')
@ -127,6 +144,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetStreams(['audio', 'video', 'video,trick_play_factor=2',
'video,trick_play_factor=1']),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
self._DiffGold(self.output[2], 'bear-640x360-v-trick-2-golden.mp4')
@ -140,6 +158,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video'], language_override='por-BR'),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-por-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-av-por-golden.mpd')
@ -148,6 +167,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video'], language_override='por-BR'),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-por-BR-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-av-por-BR-golden.mpd')
@ -157,6 +177,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetStreams(
['audio'], test_files=['bear-640x360-aac_he-silent_right.mp4']),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0],
'bear-640x360-aac_he-silent_right-golden.mp4')
self._DiffGold(self.mpd_output,
@ -168,6 +189,7 @@ class PackagerAppTest(unittest.TestCase):
text_stream = self._GetStreams(['text'],
test_files=['subtitle-english.vtt'])
self.packager.Package(audio_video_streams + text_stream, self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
self._DiffGold(self.output[2], 'subtitle-english-golden.vtt')
@ -181,6 +203,7 @@ class PackagerAppTest(unittest.TestCase):
live=True,
test_files=['bear-640x360.ts']),
self._GetFlags(output_hls=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0],
'bear-640x360-a-golden',
output_format='ts')
@ -200,6 +223,7 @@ class PackagerAppTest(unittest.TestCase):
output_format='webm',
test_files=['bear-640x360.webm']),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-vp8-golden.webm')
self._DiffGold(self.mpd_output, 'bear-640x360-vp8-webm-golden.mpd')
@ -209,6 +233,7 @@ class PackagerAppTest(unittest.TestCase):
output_format='webm',
test_files=['bear-320x240-vp9-opus.webm']),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-320x240-opus-golden.webm')
self._DiffGold(self.output[1], 'bear-320x240-vp9-golden.webm')
self._DiffGold(self.mpd_output, 'bear-320x240-vp9-opus-webm-golden.mpd')
@ -219,6 +244,7 @@ class PackagerAppTest(unittest.TestCase):
output_format='webm',
test_files=['bear-vp9-blockgroup.webm']),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-vp9-blockgroup-golden.webm')
def testPackageVorbisWebm(self):
@ -227,6 +253,7 @@ class PackagerAppTest(unittest.TestCase):
output_format='webm',
test_files=['bear-320x240-audio-only.webm']),
self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-320x240-vorbis-golden.webm')
self._DiffGold(self.mpd_output, 'bear-320x240-vorbis-webm-golden.mpd')
@ -234,16 +261,84 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-av-cenc-golden.mpd')
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
def testPackageWithEncryptionWithIncorrectKeyIdLength1(self):
self.encryption_key_id = self.encryption_key_id[0:-2]
self.packager.Package(
self._GetStreams(['video']), self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithIncorrectKeyIdLength2(self):
self.encryption_key_id += '12'
self.packager.Package(
self._GetStreams(['video']), self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithInvalidKeyIdValue(self):
self.encryption_key_id = self.encryption_key_id[0:-1] + 'g'
self.packager.Package(
self._GetStreams(['video']), self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithIncorrectKeyLength1(self):
self.encryption_key = self.encryption_key[0:-2]
self.packager.Package(
self._GetStreams(['video']), self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithIncorrectKeyLength2(self):
self.encryption_key += '12'
self.packager.Package(
self._GetStreams(['video']), self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithInvalidKeyValue(self):
self.encryption_key = self.encryption_key[0:-1] + 'g'
self.packager.Package(
self._GetStreams(['video']), self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithIncorrectIvLength1(self):
self.encryption_iv = self.encryption_iv[0:-2]
self.packager.Package(
self._GetStreams(['video']), self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithIncorrectIvLength2(self):
self.encryption_iv += '12'
self.packager.Package(
self._GetStreams(['video']), self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithInvalidIvValue(self):
self.encryption_iv = self.encryption_iv[0:-1] + 'g'
self.packager.Package(
self._GetStreams(['video']), self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithInvalidPsshValue1(self):
self.packager.Package(
self._GetStreams(['video']),
self._GetFlags(encryption=True) + ['--pssh=ag'])
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionWithInvalidPsshValue2(self):
self.packager.Package(
self._GetStreams(['video']),
self._GetFlags(encryption=True) + ['--pssh=1122'])
self.assertEqual(self.packager.packaging_result, 1)
def testPackageWithEncryptionOfOnlyVideoStream(self):
self.packager.Package(
self._GetStreams(['audio,skip_encryption=1', 'video']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-a-clear-v-cenc-golden.mpd')
@ -253,6 +348,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-cenc-golden.mp4')
@ -268,6 +364,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1',
'video,trick_play_factor=2']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-cenc-golden.mp4')
@ -283,6 +380,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True, clear_lead=0))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0],
'bear-640x360-a-cenc-no-clear-lead-golden.mp4')
self._DiffGold(self.output[1],
@ -296,6 +394,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True, include_pssh_in_stream=False))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-no-pssh-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-no-pssh-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-av-cenc-no-pssh-golden.mpd')
@ -307,6 +406,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True,
protection_scheme='cbc1'))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-cbc1-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cbc1-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-av-cbc1-golden.mpd')
@ -318,6 +418,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True,
protection_scheme='cens'))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-cens-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cens-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-av-cens-golden.mpd')
@ -329,6 +430,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True,
protection_scheme='cbcs'))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-cbcs-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cbcs-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-av-cbcs-golden.mpd')
@ -341,6 +443,7 @@ class PackagerAppTest(unittest.TestCase):
output_format='webm',
test_files=['bear-320x180-vp9-altref.webm']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-320x180-vp9-altref-enc-golden.webm')
self._VerifyDecryption(self.output[0],
'bear-320x180-vp9-altref-dec-golden.webm')
@ -351,6 +454,7 @@ class PackagerAppTest(unittest.TestCase):
output_format='webm',
test_files=['bear-320x180-vp9-altref.webm']),
self._GetFlags(encryption=True, vp9_subsample_encryption=False))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0],
'bear-320x180-vp9-fullsample-enc-golden.webm')
self._VerifyDecryption(self.output[0],
@ -364,6 +468,7 @@ class PackagerAppTest(unittest.TestCase):
live=True,
test_files=['bear-640x360.ts']),
self._GetFlags(encryption=True, output_hls=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0],
'bear-640x360-a-enc-golden',
output_format='ts')
@ -380,6 +485,7 @@ class PackagerAppTest(unittest.TestCase):
'bear-640x360-v-enc-golden.m3u8')
def testPackageAvcTsWithEncryptionExerciseEmulationPrevention(self):
self.encryption_key = 'ad7e9786def9159db6724be06dfcde7a'
# Currently we only support live packaging for ts.
self.packager.Package(
self._GetStreams(
@ -389,8 +495,8 @@ class PackagerAppTest(unittest.TestCase):
test_files=['sintel-1024x436.mp4']),
self._GetFlags(
encryption=True,
encryption_key='ad7e9786def9159db6724be06dfcde7a',
output_hls=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0],
'sintel-1024x436-v-enc-golden',
output_format='ts')
@ -406,6 +512,7 @@ class PackagerAppTest(unittest.TestCase):
output_format='webm',
test_files=['bear-640x360.webm']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-vp8-cenc-golden.webm')
self._DiffGold(self.mpd_output, 'bear-640x360-vp8-cenc-webm-golden.mpd')
self._VerifyDecryption(self.output[0], 'bear-640x360-vp8-golden.webm')
@ -415,6 +522,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetStreams(['video'],
test_files=['bear-640x360-hevc.mp4']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-hevc-cenc-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-hevc-cenc-golden.mpd')
self._VerifyDecryption(self.output[0], 'bear-640x360-hevc-golden.mp4')
@ -425,6 +533,7 @@ class PackagerAppTest(unittest.TestCase):
output_format='mp4',
test_files=['bear-640x360.webm']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-vp8-cenc-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-vp8-cenc-golden.mpd')
self._VerifyDecryption(self.output[0], 'bear-640x360-vp8-golden.mp4')
@ -435,6 +544,7 @@ class PackagerAppTest(unittest.TestCase):
output_format='mp4',
test_files=['bear-320x240-vp9-opus.webm']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-320x240-opus-cenc-golden.mp4')
self._DiffGold(self.output[1], 'bear-320x240-vp9-cenc-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-320x240-opus-vp9-cenc-golden.mpd')
@ -442,11 +552,12 @@ class PackagerAppTest(unittest.TestCase):
self._VerifyDecryption(self.output[1], 'bear-320x240-vp9-golden.mp4')
def testPackageWvmInput(self):
self.encryption_key = '9248d245390e0a49d483ba9b43fc69c3'
self.packager.Package(
self._GetStreams(
['0', '1', '2', '3'], test_files=['bear-multi-configs.wvm']),
self._GetFlags(
decryption=True, encryption_key='9248d245390e0a49d483ba9b43fc69c3'))
self._GetFlags(decryption=True))
self.assertEqual(self.packager.packaging_result, 0)
# Output timescale is 90000.
self._DiffGold(self.output[0], 'bear-320x180-v-wvm-golden.mp4')
self._DiffGold(self.output[1], 'bear-320x180-a-wvm-golden.mp4')
@ -462,13 +573,12 @@ class PackagerAppTest(unittest.TestCase):
'--strip_parameter_set_nalus flag.'
)
def testPackageWvmInputWithoutStrippingParameterSetNalus(self):
self.encryption_key = '9248d245390e0a49d483ba9b43fc69c3'
self.packager.Package(
self._GetStreams(
['0', '1', '2', '3'], test_files=['bear-multi-configs.wvm']),
self._GetFlags(
strip_parameter_set_nalus=False,
decryption=True,
encryption_key='9248d245390e0a49d483ba9b43fc69c3'))
self._GetFlags(strip_parameter_set_nalus=False, decryption=True))
self.assertEqual(self.packager.packaging_result, 0)
# Output timescale is 90000.
self._DiffGold(self.output[0], 'bear-320x180-avc3-wvm-golden.mp4')
self._DiffGold(self.output[1], 'bear-320x180-a-wvm-golden.mp4')
@ -480,6 +590,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True, random_iv=True))
self.assertEqual(self.packager.packaging_result, 0)
self._AssertStreamInfo(self.output[0], 'is_encrypted: true')
self._AssertStreamInfo(self.output[1], 'is_encrypted: true')
# The outputs are encrypted with random iv, so they are not the same as
@ -496,6 +607,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True, use_fake_clock=False))
self.assertEqual(self.packager.packaging_result, 0)
self._AssertStreamInfo(self.output[0], 'is_encrypted: true')
self._AssertStreamInfo(self.output[1], 'is_encrypted: true')
# The outputs are generated with real clock, so they are not the same as
@ -512,6 +624,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True, dash_if_iop=False))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
self._DiffGold(self.mpd_output, 'bear-640x360-av-cenc-non-iop-golden.mpd')
@ -520,6 +633,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video']),
self._GetFlags(encryption=True, output_media_info=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
self._DiffMediaInfoGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
@ -528,6 +642,7 @@ class PackagerAppTest(unittest.TestCase):
def testPackageWithLiveProfile(self):
self.packager.Package(
self._GetStreams(['audio', 'video'], live=True), self._GetFlags())
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-golden')
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-golden')
self._DiffLiveMpdGold(self.mpd_output, 'bear-640x360-av-live-golden.mpd')
@ -536,6 +651,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video'], live=True),
self._GetFlags(generate_static_mpd=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-golden')
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-golden')
self._DiffGold(self.mpd_output, 'bear-640x360-av-live-static-golden.mpd')
@ -544,6 +660,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video'], live=True),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-cenc-golden')
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-cenc-golden')
self._DiffLiveMpdGold(self.mpd_output,
@ -553,6 +670,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video'], live=True),
self._GetFlags(encryption=True, dash_if_iop=False))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-cenc-golden')
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-cenc-golden')
self._DiffLiveMpdGold(self.mpd_output,
@ -565,6 +683,7 @@ class PackagerAppTest(unittest.TestCase):
test_files=['bear-1280x720.mp4', 'bear-640x360.mp4',
'bear-320x180.mp4']),
self._GetFlags(encryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[2], 'bear-640x360-a-live-cenc-golden')
self._DiffLiveGold(self.output[3], 'bear-640x360-v-live-cenc-golden')
# Mpd cannot be validated right now since we don't generate determinstic
@ -575,6 +694,7 @@ class PackagerAppTest(unittest.TestCase):
self.packager.Package(
self._GetStreams(['audio', 'video'], live=True),
self._GetFlags(encryption=True, key_rotation=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0],
'bear-640x360-a-live-cenc-rotation-golden')
self._DiffLiveGold(self.output[1],
@ -587,6 +707,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetStreams(['audio', 'video'], live=True),
self._GetFlags(
encryption=True, key_rotation=True, include_pssh_in_stream=False))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0],
'bear-640x360-a-live-cenc-rotation-no-pssh-golden')
self._DiffLiveGold(self.output[1],
@ -601,6 +722,7 @@ class PackagerAppTest(unittest.TestCase):
self._GetFlags(encryption=True,
key_rotation=True,
dash_if_iop=False))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffLiveGold(self.output[0],
'bear-640x360-a-live-cenc-rotation-golden')
self._DiffLiveGold(self.output[1],
@ -612,21 +734,98 @@ class PackagerAppTest(unittest.TestCase):
@unittest.skipUnless(test_env.has_aes_flags, 'Requires AES credentials.')
def testWidevineEncryptionWithAes(self):
flags = self._GetFlags(widevine_encryption=True)
flags += ['--aes_signing_key=' + test_env.options.aes_signing_key,
'--aes_signing_iv=' + test_env.options.aes_signing_iv]
flags += [
'--signer=widevine_test',
'--aes_signing_key=' + test_env.options.aes_signing_key,
'--aes_signing_iv=' + test_env.options.aes_signing_iv
]
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 0)
self._AssertStreamInfo(self.output[0], 'is_encrypted: true')
self._AssertStreamInfo(self.output[1], 'is_encrypted: true')
def testWidevineEncryptionInvalidContentId(self):
self.widevine_content_id += 'ag'
flags = self._GetFlags(widevine_encryption=True)
flags += [
'--signer=widevine_test', '--aes_signing_key=1122',
'--aes_signing_iv=3344'
]
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 1)
def testWidevineEncryptionInvalidAesSigningKey(self):
flags = self._GetFlags(widevine_encryption=True)
flags += [
'--signer=widevine_test', '--aes_signing_key=11ag',
'--aes_signing_iv=3344'
]
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 1)
def testWidevineEncryptionInvalidAesSigningIv(self):
flags = self._GetFlags(widevine_encryption=True)
flags += [
'--signer=widevine_test', '--aes_signing_key=1122',
'--aes_signing_iv=33ag'
]
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 1)
def testWidevineEncryptionMissingAesSigningKey(self):
flags = self._GetFlags(widevine_encryption=True)
flags += ['--signer=widevine_test', '--aes_signing_iv=3344']
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 1)
def testWidevineEncryptionMissingAesSigningIv(self):
flags = self._GetFlags(widevine_encryption=True)
flags += ['--signer=widevine_test', '--aes_signing_key=1122']
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 1)
def testWidevineEncryptionMissingSigner1(self):
flags = self._GetFlags(widevine_encryption=True)
flags += ['--aes_signing_key=1122', '--aes_signing_iv=3344']
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 1)
def testWidevineEncryptionMissingSigner2(self):
flags = self._GetFlags(widevine_encryption=True)
flags += ['--rsa_signing_key_path=/tmp/test']
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 1)
def testWidevineEncryptionSignerOnly(self):
flags = self._GetFlags(widevine_encryption=True)
flags += ['--signer=widevine_test']
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 1)
def testWidevineEncryptionAesSigningAndRsaSigning(self):
flags = self._GetFlags(widevine_encryption=True)
flags += [
'--signer=widevine_test',
'--aes_signing_key=1122',
'--aes_signing_iv=3344',
'--rsa_signing_key_path=/tmp/test',
]
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 1)
@unittest.skipUnless(test_env.has_aes_flags, 'Requires AES credentials.')
def testWidevineEncryptionWithAesAndMultFiles(self):
flags = self._GetFlags(widevine_encryption=True)
flags += ['--aes_signing_key=' + test_env.options.aes_signing_key,
'--aes_signing_iv=' + test_env.options.aes_signing_iv]
flags += [
'--signer=widevine_test',
'--aes_signing_key=' + test_env.options.aes_signing_key,
'--aes_signing_iv=' + test_env.options.aes_signing_iv
]
self.packager.Package(
self._GetStreams(['audio', 'video'],
test_files=['bear-1280x720.mp4', 'bear-640x360.mp4',
'bear-320x180.mp4']), flags)
self.assertEqual(self.packager.packaging_result, 0)
with open(self.mpd_output, 'rb') as f:
print f.read()
# TODO(kqyang): Add some validations.
@ -634,17 +833,25 @@ class PackagerAppTest(unittest.TestCase):
@unittest.skipUnless(test_env.has_aes_flags, 'Requires AES credentials.')
def testKeyRotationWithAes(self):
flags = self._GetFlags(widevine_encryption=True, key_rotation=True)
flags += ['--aes_signing_key=' + test_env.options.aes_signing_key,
'--aes_signing_iv=' + test_env.options.aes_signing_iv]
flags += [
'--signer=widevine_test',
'--aes_signing_key=' + test_env.options.aes_signing_key,
'--aes_signing_iv=' + test_env.options.aes_signing_iv
]
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 0)
self._AssertStreamInfo(self.output[0], 'is_encrypted: true')
self._AssertStreamInfo(self.output[1], 'is_encrypted: true')
@unittest.skipUnless(test_env.has_rsa_flags, 'Requires RSA credentials.')
def testWidevineEncryptionWithRsa(self):
flags = self._GetFlags(widevine_encryption=True)
flags += ['--rsa_signing_key_path=' + test_env.options.rsa_signing_key_path]
flags += [
'--signer=widevine_test',
'--rsa_signing_key_path=' + test_env.options.rsa_signing_key_path
]
self.packager.Package(self._GetStreams(['audio', 'video']), flags)
self.assertEqual(self.packager.packaging_result, 0)
self._AssertStreamInfo(self.output[0], 'is_encrypted: true')
self._AssertStreamInfo(self.output[1], 'is_encrypted: true')
@ -715,8 +922,6 @@ class PackagerAppTest(unittest.TestCase):
protection_scheme=None,
vp9_subsample_encryption=True,
decryption=False,
encryption_key='32333435363738393021323334353637',
encryption_iv='3334353637383930',
random_iv=False,
widevine_encryption=False,
key_rotation=False,
@ -734,21 +939,19 @@ class PackagerAppTest(unittest.TestCase):
if widevine_encryption:
widevine_server_url = ('https://license.uat.widevine.com/cenc'
'/getcontentkey/widevine_test')
flags += ['--enable_widevine_encryption',
flags += [
'--enable_widevine_encryption',
'--key_server_url=' + widevine_server_url,
'--content_id=3031323334353637', '--signer=widevine_test']
'--content_id=' + self.widevine_content_id,
]
elif encryption:
flags += ['--enable_fixed_key_encryption',
'--key_id=31323334353637383930313233343536',
'--key_id=' + self.encryption_key_id,
'--key=' + self.encryption_key,
'--clear_lead={0}'.format(clear_lead)]
if test_env.options.encryption_key:
encryption_key = test_env.options.encryption_key
flags.append('--key=' + encryption_key)
if not random_iv:
if test_env.options.encryption_iv:
encryption_iv = test_env.options.encryption_iv
flags.append('--iv=' + encryption_iv)
flags.append('--iv=' + self.encryption_iv)
if protection_scheme:
flags += ['--protection_scheme', protection_scheme]
if not vp9_subsample_encryption:
@ -756,8 +959,8 @@ class PackagerAppTest(unittest.TestCase):
if decryption:
flags += ['--enable_fixed_key_decryption',
'--key_id=31323334353637383930313233343536',
'--key=' + encryption_key]
'--key_id=' + self.encryption_key_id,
'--key=' + self.encryption_key]
if key_rotation:
flags.append('--crypto_period_duration=1')
@ -878,6 +1081,7 @@ class PackagerAppTest(unittest.TestCase):
output_format=output_extension,
test_files=[test_encrypted_file]),
self._GetFlags(decryption=True))
self.assertEqual(self.packager.packaging_result, 0)
self._DiffGold(self.output[-1], golden_clear_file)

View File

@ -10,29 +10,8 @@
#include <stdio.h>
#include "packager/base/strings/stringprintf.h"
namespace shaka {
bool ValidateFlag(const char* flag_name,
const std::string& flag_value,
bool condition,
bool optional,
const char* label) {
if (flag_value.empty()) {
if (!optional && condition) {
PrintError(
base::StringPrintf("--%s is required if %s.", flag_name, label));
return false;
}
} else if (!condition) {
PrintError(base::StringPrintf(
"--%s should be specified only if %s.", flag_name, label));
return false;
}
return true;
}
void PrintError(const std::string& error_message) {
fprintf(stderr, "ERROR: %s\n", error_message.c_str());
}

View File

@ -11,8 +11,14 @@
#include <string>
#include "packager/base/strings/stringprintf.h"
namespace shaka {
/// Format and print error message.
/// @param error_message specifies the error message.
void PrintError(const std::string& error_message);
/// Validate a flag against the given condition.
/// @param flag_name is the name of the flag.
/// @param flag_value is the value of the flag.
@ -23,15 +29,25 @@ namespace shaka {
/// @param label specifies the label associated with the condition. It is used
/// to generate the error message on validation failure.
/// @return true on success, false otherwise.
template <class FlagType>
bool ValidateFlag(const char* flag_name,
const std::string& flag_value,
const FlagType& flag_value,
bool condition,
bool optional,
const char* label);
/// Format and print error message.
/// @param error_message specifies the error message.
void PrintError(const std::string& error_message);
const char* label) {
if (flag_value.empty()) {
if (!optional && condition) {
PrintError(
base::StringPrintf("--%s is required if %s.", flag_name, label));
return false;
}
} else if (!condition) {
PrintError(base::StringPrintf(
"--%s should be specified only if %s.", flag_name, label));
return false;
}
return true;
}
} // namespace shaka

View File

@ -30,7 +30,7 @@ DEFINE_bool(include_common_pssh,
"https://goo.gl/s8RIhr");
DEFINE_string(key_server_url, "", "Key server url. Required for encryption and "
"decryption");
DEFINE_string(content_id, "", "Content Id (hex).");
DEFINE_hex_bytes(content_id, "", "Content Id (hex).");
DEFINE_string(policy,
"",
"The name of a stored policy, which specifies DRM content "
@ -50,13 +50,11 @@ DEFINE_int32(max_uhd1_pixels,
"is higher than max_hd_pixels, but no higher than max_uhd1_pixels."
" Otherwise it is UHD2. Default: 8847360 (4096 x 2160).");
DEFINE_string(signer, "", "The name of the signer.");
DEFINE_string(aes_signing_key,
DEFINE_hex_bytes(aes_signing_key,
"",
"AES signing key in hex string. --aes_signing_iv is required. "
"Exclusive with --rsa_signing_key_path.");
DEFINE_string(aes_signing_iv,
"",
"AES signing iv in hex string.");
DEFINE_hex_bytes(aes_signing_iv, "", "AES signing iv in hex string.");
DEFINE_string(rsa_signing_key_path,
"",
"Stores PKCS#1 RSA private key for request signing. Exclusive "
@ -67,6 +65,9 @@ DEFINE_int32(crypto_period_duration,
"rotation is enabled.");
namespace shaka {
namespace {
const bool kOptional = true;
} // namespace
bool ValidateWidevineCryptoFlags() {
bool success = true;
@ -80,14 +81,14 @@ bool ValidateWidevineCryptoFlags() {
if (!ValidateFlag("key_server_url",
FLAGS_key_server_url,
widevine_crypto,
false,
!kOptional,
widevine_crypto_label)) {
success = false;
}
if (!ValidateFlag("signer",
FLAGS_signer,
widevine_crypto,
true,
kOptional,
widevine_crypto_label)) {
success = false;
}
@ -102,16 +103,16 @@ bool ValidateWidevineCryptoFlags() {
// content_id and policy (optional) are associated with
// enable_widevine_encryption.
if (!ValidateFlag("content_id",
FLAGS_content_id,
FLAGS_content_id_bytes,
FLAGS_enable_widevine_encryption,
false,
!kOptional,
widevine_encryption_label)) {
success = false;
}
if (!ValidateFlag("policy",
FLAGS_policy,
FLAGS_enable_widevine_encryption,
true,
kOptional,
widevine_encryption_label)) {
success = false;
}
@ -142,40 +143,32 @@ bool ValidateWidevineCryptoFlags() {
success = false;
}
const bool aes = !FLAGS_signer.empty() && FLAGS_rsa_signing_key_path.empty();
const char aes_label[] =
"--signer is specified and exclusive with --rsa_signing_key_path";
// aes_signer_key and aes_signing_iv are associated with aes signing.
if (!ValidateFlag(
"aes_signing_key", FLAGS_aes_signing_key, aes, true, aes_label)) {
success = false;
}
if (!ValidateFlag(
"aes_signing_iv", FLAGS_aes_signing_iv, aes, true, aes_label)) {
const bool aes = !FLAGS_aes_signing_key_bytes.empty() ||
!FLAGS_aes_signing_iv_bytes.empty();
if (aes && (FLAGS_aes_signing_key_bytes.empty() ||
FLAGS_aes_signing_iv_bytes.empty())) {
PrintError("--aes_signing_key/iv is required if using aes signing.");
success = false;
}
const bool rsa = !FLAGS_signer.empty() && FLAGS_aes_signing_key.empty() &&
FLAGS_aes_signing_iv.empty();
const char rsa_label[] =
"--signer is specified and exclusive with --aes_signing_key/iv";
// rsa_signing_key_path is associated with rsa_signing.
if (!ValidateFlag("rsa_signing_key_path",
FLAGS_rsa_signing_key_path,
rsa,
true,
rsa_label)) {
const bool rsa = !FLAGS_rsa_signing_key_path.empty();
if (FLAGS_signer.empty() && (aes || rsa)) {
PrintError("--signer is required if using aes/rsa signing.");
success = false;
}
if (!FLAGS_signer.empty() &&
(FLAGS_aes_signing_key.empty() || FLAGS_aes_signing_iv.empty()) &&
FLAGS_rsa_signing_key_path.empty()) {
if (!FLAGS_signer.empty() && !aes && !rsa) {
PrintError(
"--aes_signing_key/iv or --rsa_signing_key_path is required with "
"--signer.");
success = false;
}
if (aes && rsa) {
PrintError(
"Only one of --aes_signing_key/iv and --rsa_signing_key_path should be "
"specified.");
success = false;
}
if (FLAGS_crypto_period_duration < 0) {
PrintError("--crypto_period_duration should not be negative.");

View File

@ -11,18 +11,20 @@
#include <gflags/gflags.h>
#include "packager/app/gflags_hex_bytes.h"
DECLARE_bool(enable_widevine_encryption);
DECLARE_bool(enable_widevine_decryption);
DECLARE_bool(include_common_pssh);
DECLARE_string(key_server_url);
DECLARE_string(content_id);
DECLARE_hex_bytes(content_id);
DECLARE_string(policy);
DECLARE_int32(max_sd_pixels);
DECLARE_int32(max_hd_pixels);
DECLARE_int32(max_uhd1_pixels);
DECLARE_string(signer);
DECLARE_string(aes_signing_key);
DECLARE_string(aes_signing_iv);
DECLARE_hex_bytes(aes_signing_key);
DECLARE_hex_bytes(aes_signing_iv);
DECLARE_string(rsa_signing_key_path);
DECLARE_int32(crypto_period_duration);

View File

@ -75,45 +75,27 @@ Status FixedKeySource::GetCryptoPeriodKey(uint32_t crypto_period_index,
return Status::OK;
}
std::unique_ptr<FixedKeySource> FixedKeySource::CreateFromHexStrings(
const std::string& key_id_hex,
const std::string& key_hex,
const std::string& pssh_boxes_hex,
const std::string& iv_hex) {
std::unique_ptr<FixedKeySource> FixedKeySource::Create(
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& pssh_boxes,
const std::vector<uint8_t>& iv) {
std::unique_ptr<EncryptionKey> 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 std::unique_ptr<FixedKeySource>();
} else if (encryption_key->key_id.size() != 16) {
LOG(ERROR) << "Invalid key ID size '" << encryption_key->key_id.size()
if (key_id.size() != 16) {
LOG(ERROR) << "Invalid key ID size '" << key_id.size()
<< "', must be 16 bytes.";
return std::unique_ptr<FixedKeySource>();
}
if (!base::HexStringToBytes(key_hex, &encryption_key->key)) {
LOG(ERROR) << "Cannot parse key_hex " << key_hex;
return std::unique_ptr<FixedKeySource>();
} else if (encryption_key->key.size() != 16) {
if (key.size() != 16) {
// CENC only supports AES-128, i.e. 16 bytes.
LOG(ERROR) << "Invalid key size '" << encryption_key->key.size()
<< "', must be 16 bytes.";
LOG(ERROR) << "Invalid key size '" << key.size() << "', must be 16 bytes.";
return std::unique_ptr<FixedKeySource>();
}
std::vector<uint8_t> pssh_boxes;
if (!pssh_boxes_hex.empty() &&
!base::HexStringToBytes(pssh_boxes_hex, &pssh_boxes)) {
LOG(ERROR) << "Cannot parse pssh_hex " << pssh_boxes_hex;
return std::unique_ptr<FixedKeySource>();
}
if (!iv_hex.empty()) {
if (!base::HexStringToBytes(iv_hex, &encryption_key->iv)) {
LOG(ERROR) << "Cannot parse iv_hex " << iv_hex;
return std::unique_ptr<FixedKeySource>();
}
}
encryption_key->key_id = key_id;
encryption_key->key = key;
encryption_key->iv = iv;
if (!ProtectionSystemSpecificInfo::ParseBoxes(
pssh_boxes.data(), pssh_boxes.size(),

View File

@ -40,20 +40,20 @@ class FixedKeySource : public KeySource {
EncryptionKey* key) override;
/// @}
/// Creates a new FixedKeySource from the given hex strings. Returns null
/// Creates a new FixedKeySource from the given data. 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
/// @param key_id is the key identifier. Must be 16 bytes.
/// @param key is the encryption / decryption key. Must be 16 bytes.
/// @param pssh_boxes is the concatenated pssh boxes.
/// @param iv is the initialization vector. 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 std::unique_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);
/// Note: GetKey on the created key source will always return the same key for
/// all track types.
static std::unique_ptr<FixedKeySource> Create(
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& pssh_boxes,
const std::vector<uint8_t>& iv);
protected:
// Allow default constructor for mock key sources.

View File

@ -43,13 +43,19 @@ const char kDefaultPsshBoxHex[] =
"00000001"
"0101020305080d1522375990e9000000"
"00000000";
std::vector<uint8_t> HexStringToVector(const std::string& str) {
std::vector<uint8_t> vec;
CHECK(base::HexStringToBytes(str, &vec));
return vec;
}
}
TEST(FixedKeySourceTest, CreateFromHexStrings_Succes) {
TEST(FixedKeySourceTest, Success) {
std::string pssh_boxes = std::string(kPsshBox1Hex) + kPsshBox2Hex;
std::unique_ptr<FixedKeySource> key_source =
FixedKeySource::CreateFromHexStrings(kKeyIdHex, kKeyHex, pssh_boxes,
kIvHex);
std::unique_ptr<FixedKeySource> key_source = FixedKeySource::Create(
HexStringToVector(kKeyIdHex), HexStringToVector(kKeyHex),
HexStringToVector(pssh_boxes), HexStringToVector(kIvHex));
ASSERT_NE(nullptr, key_source);
EncryptionKey key;
@ -64,9 +70,10 @@ TEST(FixedKeySourceTest, CreateFromHexStrings_Succes) {
EXPECT_HEX_EQ(kPsshBox2Hex, key.key_system_info[1].CreateBox());
}
TEST(FixedKeySourceTest, CreateFromHexStrings_EmptyPssh) {
std::unique_ptr<FixedKeySource> key_source =
FixedKeySource::CreateFromHexStrings(kKeyIdHex, kKeyHex, "", kIvHex);
TEST(FixedKeySourceTest, EmptyPssh) {
std::unique_ptr<FixedKeySource> key_source = FixedKeySource::Create(
HexStringToVector(kKeyIdHex), HexStringToVector(kKeyHex),
std::vector<uint8_t>(), HexStringToVector(kIvHex));
ASSERT_NE(nullptr, key_source);
EncryptionKey key;
@ -80,20 +87,17 @@ TEST(FixedKeySourceTest, CreateFromHexStrings_EmptyPssh) {
EXPECT_HEX_EQ(kDefaultPsshBoxHex, key.key_system_info[0].CreateBox());
}
TEST(FixedKeySourceTest, CreateFromHexStrings_Failure) {
std::unique_ptr<FixedKeySource> key_source =
FixedKeySource::CreateFromHexStrings(kKeyIdHex, "invalid_hex_value",
kPsshBox1Hex, kIvHex);
EXPECT_EQ(nullptr, key_source);
TEST(FixedKeySourceTest, Failure) {
// Invalid key id size.
key_source = FixedKeySource::CreateFromHexStrings("000102030405", kKeyHex,
kPsshBox1Hex, kIvHex);
std::unique_ptr<FixedKeySource> key_source = FixedKeySource::Create(
HexStringToVector("000102030405"), HexStringToVector(kKeyHex),
HexStringToVector(kPsshBox1Hex), HexStringToVector(kIvHex));
EXPECT_EQ(nullptr, key_source);
// Invalid pssh box.
key_source = FixedKeySource::CreateFromHexStrings(kKeyIdHex, kKeyHex,
"000102030405", kIvHex);
key_source = FixedKeySource::Create(
HexStringToVector(kKeyIdHex), HexStringToVector(kKeyHex),
HexStringToVector("000102030405"), HexStringToVector(kIvHex));
EXPECT_EQ(nullptr, key_source);
}

View File

@ -182,17 +182,11 @@ PlayReadyKeySource::PlayReadyKeySource(
PlayReadyKeySource::~PlayReadyKeySource() {}
std::unique_ptr<PlayReadyKeySource> PlayReadyKeySource::CreateFromKeyAndKeyId(
const std::string& key_id_hex, const std::string& key_hex) {
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& key) {
std::unique_ptr<EncryptionKey> 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 std::unique_ptr<PlayReadyKeySource>();
}
std::vector<uint8_t> key;
if (!base::HexStringToBytes(key_hex, &encryption_key->key)) {
LOG(ERROR) << "Cannot parse key_hex " << key_hex;
return std::unique_ptr<PlayReadyKeySource>();
}
encryption_key->key_id = key_id;
encryption_key->key = key;
std::vector<uint8_t> pssh_data;
Status status = GeneratePlayReadyPsshData(
encryption_key->key_id, encryption_key->key, &pssh_data);

View File

@ -51,14 +51,13 @@ class PlayReadyKeySource : public KeySource {
/// @}
virtual Status FetchKeysWithProgramIdentifier(const std::string& program_identifier);
/// Creates a new PlayReadyKeySource from the hex string information.
/// Creates a new PlayReadyKeySource from the given data.
/// 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.
/// Note: GetKey on the created key source will always return the same key
/// for all track types.
static std::unique_ptr<PlayReadyKeySource> CreateFromKeyAndKeyId(
const std::string& key_id_hex, const std::string& key_hex);
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& key);
/// Sets the Certificate Authority file for validating self-signed certificates.
void SetCaFile(const std::string& ca_file) {
ca_file_ = ca_file;

View File

@ -8,7 +8,6 @@
#include "packager/base/logging.h"
#include "packager/base/sha1.h"
#include "packager/base/strings/string_number_conversions.h"
#include "packager/media/base/aes_encryptor.h"
#include "packager/media/base/rsa_key.h"
@ -26,20 +25,10 @@ AesRequestSigner::AesRequestSigner(const std::string& signer_name,
}
AesRequestSigner::~AesRequestSigner() {}
AesRequestSigner* AesRequestSigner::CreateSigner(const std::string& signer_name,
const std::string& aes_key_hex,
const std::string& iv_hex) {
std::vector<uint8_t> aes_key;
if (!base::HexStringToBytes(aes_key_hex, &aes_key)) {
LOG(ERROR) << "Failed to convert hex string to bytes: " << aes_key_hex;
return NULL;
}
std::vector<uint8_t> iv;
if (!base::HexStringToBytes(iv_hex, &iv)) {
LOG(ERROR) << "Failed to convert hex string to bytes: " << iv_hex;
return NULL;
}
AesRequestSigner* AesRequestSigner::CreateSigner(
const std::string& signer_name,
const std::vector<uint8_t>& aes_key,
const std::vector<uint8_t>& iv) {
std::unique_ptr<AesCbcEncryptor> encryptor(
new AesCbcEncryptor(kPkcs5Padding, AesCryptor::kUseConstantIv));
if (!encryptor->InitializeWithIv(aes_key, iv))

View File

@ -9,6 +9,7 @@
#include <memory>
#include <string>
#include <vector>
#include "packager/base/macros.h"
@ -45,11 +46,11 @@ class AesRequestSigner : public RequestSigner {
public:
~AesRequestSigner() override;
/// Create an AesSigner object from key and iv in hex.
/// Create an AesSigner object from key and iv.
/// @return The created AesRequestSigner object on success, NULL otherwise.
static AesRequestSigner* CreateSigner(const std::string& signer_name,
const std::string& aes_key_hex,
const std::string& iv_hex);
const std::vector<uint8_t>& aes_key,
const std::vector<uint8_t>& iv);
/// RequestSigner implementation override.
bool GenerateSignature(const std::string& message,

View File

@ -8,13 +8,9 @@
#include <memory>
#include "packager/media/base/aes_encryptor.h"
#include "packager/media/base/key_source.h"
#include "packager/media/base/muxer_util.h"
#include "packager/media/base/status.h"
#include "packager/media/base/video_stream_info.h"
#include "packager/media/event/muxer_listener.h"
#include "packager/media/event/progress_listener.h"
namespace shaka {
namespace media {

View File

@ -56,6 +56,8 @@
'app/crypto_flags.h',
'app/fixed_key_encryption_flags.cc',
'app/fixed_key_encryption_flags.h',
'app/gflags_hex_bytes.cc',
'app/gflags_hex_bytes.h',
'app/hls_flags.cc',
'app/hls_flags.h',
'app/mpd_flags.cc',

View File

@ -150,9 +150,9 @@ struct WidevineSigner {
SigningKeyType signing_key_type = SigningKeyType::kNone;
struct {
/// AES signing key.
std::string key;
std::vector<uint8_t> key;
/// AES signing IV.
std::string iv;
std::vector<uint8_t> iv;
} aes;
struct {
/// RSA signing private key.
@ -201,24 +201,24 @@ struct PlayreadyEncryptionParams {
// TODO(kqyang): move raw playready key generation to RawKey.
/// Provides a raw Playready KeyId.
std::string key_id;
std::vector<uint8_t> key_id;
/// Provides a raw Playready Key.
std::string key;
std::vector<uint8_t> key;
};
/// Raw key encryption parameters, i.e. with key parameters provided.
struct RawKeyEncryptionParams {
/// An optional initialization vector. If not provided, a random `iv` will be
/// generated. Note that this parameter should only be used during testing.
std::string iv;
std::vector<uint8_t> iv;
/// Inject a custom `pssh` or multiple concatenated `psshs`. If not provided,
/// a common system pssh will be generated.
std::string pssh;
std::vector<uint8_t> pssh;
using StreamLabel = std::string;
struct KeyPair {
std::string key_id;
std::string key;
std::vector<uint8_t> key_id;
std::vector<uint8_t> key;
};
/// Defines the KeyPair for the streams. An empty `StreamLabel` indicates the
/// default `KeyPair`, which applies to all the `StreamLabels` not present in
@ -324,8 +324,8 @@ struct WidevineDecryptionParams {
struct RawKeyDecryptionParams {
using StreamLabel = std::string;
struct KeyPair {
std::string key_id;
std::string key;
std::vector<uint8_t> key_id;
std::vector<uint8_t> key;
};
/// Defines the KeyPair for the streams. An empty `StreamLabel` indicates the
/// default `KeyPair`, which applies to all the `StreamLabels` not present in

View File

@ -9,6 +9,7 @@
#include "packager/base/files/file_util.h"
#include "packager/base/logging.h"
#include "packager/base/path_service.h"
#include "packager/base/strings/string_number_conversions.h"
#include "packager/packager.h"
namespace shaka {
@ -67,8 +68,11 @@ class PackagerTest : public ::testing::Test {
packaging_params.encryption_params.clear_lead_in_seconds =
kClearLeadInSeconds;
packaging_params.encryption_params.key_provider = KeyProvider::kRawKey;
packaging_params.encryption_params.raw_key.key_map[""].key_id = kKeyIdHex;
packaging_params.encryption_params.raw_key.key_map[""].key = kKeyHex;
CHECK(base::HexStringToBytes(
kKeyIdHex,
&packaging_params.encryption_params.raw_key.key_map[""].key_id));
CHECK(base::HexStringToBytes(
kKeyHex, &packaging_params.encryption_params.raw_key.key_map[""].key));
return packaging_params;
}