Replace hardcoded parameters

This commit is contained in:
Lu Chen
2020-01-27 16:05:15 -08:00
parent cdd4d97e0f
commit 5c42bf9b7f
134 changed files with 9510 additions and 1938 deletions

View File

@@ -46,10 +46,9 @@ cc_library(
"@abseil_repo//absl/base:core_headers",
"//common:status",
"//media_cas_packager_sdk/internal:ecm",
"//media_cas_packager_sdk/internal:ecm_generator",
"//media_cas_packager_sdk/internal:key_fetcher",
"//protos/public:media_cas_encryption_proto",
"//protos/public:media_cas_proto",
"//protos/public:media_cas_cc_proto",
"//protos/public:media_cas_encryption_cc_proto",
],
)
@@ -65,8 +64,11 @@ cc_library(
"@abseil_repo//absl/strings",
"//common:status",
"//common:string_util",
"//protos/public:media_cas_proto",
"//protos/public:media_cas_cc_proto",
],
# Make sure libmedia_cas_packager_sdk links in symbols defined in this
# target.
alwayslink = 1,
)
cc_test(
@@ -77,7 +79,7 @@ cc_test(
":wv_cas_ca_descriptor",
":wv_cas_types",
"//testing:gunit_main",
"//protos/public:media_cas_proto",
"//protos/public:media_cas_cc_proto",
],
)
@@ -96,11 +98,13 @@ cc_library(
"//common:status",
"//example:constants",
"//media_cas_packager_sdk/internal:ecm",
"//media_cas_packager_sdk/internal:ecm_generator",
"//media_cas_packager_sdk/internal:fixed_key_fetcher",
"//media_cas_packager_sdk/internal:mpeg2ts",
"//media_cas_packager_sdk/internal:util",
],
# Make sure libmedia_cas_packager_sdk links in symbols defined in this
# target.
alwayslink = 1,
)
cc_test(
@@ -126,6 +130,7 @@ cc_library(
],
deps = [
"//base",
"//external:protobuf",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"@curl_repo//:curl",
@@ -133,7 +138,7 @@ cc_library(
"//common:signature_util",
"//common:status",
"//media_cas_packager_sdk/internal:key_fetcher",
"//protos/public:media_cas_encryption_proto",
"//protos/public:media_cas_encryption_cc_proto",
],
)
@@ -149,7 +154,7 @@ cc_test(
"//external:protobuf",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
"//protos/public:media_cas_encryption_proto",
"//protos/public:media_cas_encryption_cc_proto",
],
)
@@ -160,8 +165,12 @@ cc_library(
copts = PUBLIC_COPTS,
deps = [
"//base",
"//protos/public:media_cas_encryption_proto",
"//external:protobuf",
"//protos/public:media_cas_encryption_cc_proto",
],
# Make sure libmedia_cas_packager_sdk links in symbols defined in this
# target.
alwayslink = 1,
)
cc_test(
@@ -178,6 +187,7 @@ cc_binary(
name = "wv_ecmg",
srcs = ["wv_ecmg.cc"],
deps = [
":wv_cas_types",
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",

View File

@@ -45,8 +45,8 @@ static constexpr uint32_t kCaDescriptorTag = 9;
// https://en.wikipedia.org/wiki/Conditional_access
static constexpr uint32_t kWidevineCaSystemId = 0x4AD4;
// Value for CA descriptor reserved field.
static constexpr uint32_t kUnusedZero = 0;
// Value for CA descriptor reserved field should be set to 1.
static constexpr uint32_t kReservedBit = 0x0007;
// The range of valid PIDs, from section 2.4.3.3, and table 2-3.
static constexpr uint32_t kMinValidPID = 0x0010;
@@ -83,7 +83,7 @@ WvCasStatus WvCasCaDescriptor::GenerateCaDescriptor(
// including private bytes.
std::bitset<kNumBitsCaDescriptorLengthField> length(descriptor_length);
std::bitset<kNumBitsCaSystemIdField> ca_system_id(kWidevineCaSystemId);
std::bitset<kNumBitsCaDescriptorReservedField> reserved(kUnusedZero);
std::bitset<kNumBitsCaDescriptorReservedField> reserved(kReservedBit);
std::bitset<kNumBitsCaDescriptorPidField> pid(ca_pid);
// Converts bitset to a std::string where each char represents a bit.
@@ -110,8 +110,8 @@ size_t WvCasCaDescriptor::CaDescriptorBaseSize() const {
return kCaDescriptorBaseSize;
}
std::string WvCasCaDescriptor::GeneratePrivateData(const std::string& provider,
const std::string& content_id) const {
std::string WvCasCaDescriptor::GeneratePrivateData(
const std::string& provider, const std::string& content_id) const {
CaDescriptorPrivateData private_data;
private_data.set_provider(provider);
private_data.set_content_id(content_id);

View File

@@ -53,10 +53,9 @@ class WvCasCaDescriptor {
// section (for an EMM stream) or into a TS Program Map Table section (for an
// ECM stream). The descriptor will be 6 bytes plus any bytes added as
// (user-defined) private data.
virtual WvCasStatus GenerateCaDescriptor(uint16_t ca_pid,
const std::string& provider,
const std::string& content_id,
std::string* serialized_ca_desc) const;
virtual WvCasStatus GenerateCaDescriptor(
uint16_t ca_pid, const std::string& provider, const std::string& content_id,
std::string* serialized_ca_desc) const;
// Return the base size (before private data is added) of the CA
// descriptor. The user can call this to plan the layout of the Table section
@@ -65,7 +64,7 @@ class WvCasCaDescriptor {
// Return private data in the CA descriptor.
virtual std::string GeneratePrivateData(const std::string& provider,
const std::string& content_id) const;
const std::string& content_id) const;
};
} // namespace cas

View File

@@ -42,7 +42,7 @@ TEST_F(WvCasCaDescriptorTest, BaseSize) {
TEST_F(WvCasCaDescriptorTest, BasicGoodGen) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(kTestPid, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\x32", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xE0\x32", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
@@ -61,7 +61,7 @@ TEST_F(WvCasCaDescriptorTest, PidMinOK) {
const uint32_t min_pid = 0x10;
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(min_pid, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\x10", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xE0\x10", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
@@ -69,7 +69,7 @@ TEST_F(WvCasCaDescriptorTest, PidMaxOK) {
const uint32_t max_pid = 0x1FFE;
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(max_pid, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x1f\xfe");
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xff\xfe");
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
@@ -82,77 +82,77 @@ TEST_F(WvCasCaDescriptorTest, PidTooHighFail) {
TEST_F(WvCasCaDescriptorTest, PidOneByte) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(255, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\xff", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xe0\xff", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidSecondByte) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x1F00, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x1f\x00", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xff\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidTwelveBits) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0xFFF, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x0f\xff");
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xef\xff");
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidThirteenthBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x1000, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x10\x00", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xf0\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidTwelthBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x800, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x08\x00", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xe8\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidElevenththBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x400, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x04\x00", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xe4\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidTenthBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x200, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x02\x00", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xe2\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PidNinthBit) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(0x100, "", "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x01\x00", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xe1\x00", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PrivateDataOnlyProviderIgnored) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(kTestPid, kProvider, "",
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\x32", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xe0\x32", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PrivateDataOnlyContentIdIgnored) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(kTestPid, "", kContentId,
&actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\x00\x32", 6);
const std::string expected_ca_descriptor("\x09\x04\x4a\xd4\xe0\x32", 6);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
TEST_F(WvCasCaDescriptorTest, PrivateData) {
EXPECT_EQ(OK, ca_descriptor_.GenerateCaDescriptor(
kTestPid, kProvider, kContentId, &actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x19\x4a\xd4\x00\x32", 6);
const std::string expected_ca_descriptor("\x09\x19\x4a\xd4\xe0\x32", 6);
CaDescriptorPrivateData private_data;
private_data.set_provider(kProvider);
private_data.set_content_id(kContentId);
@@ -162,10 +162,13 @@ TEST_F(WvCasCaDescriptorTest, PrivateData) {
class FakePrivateDataCaDescriptor : public WvCasCaDescriptor {
public:
void set_private_data(std::string private_data) { private_data_ = private_data; }
void set_private_data(std::string private_data) {
private_data_ = private_data;
}
std::string GeneratePrivateData(const std::string& provider,
const std::string& content_id) const override {
std::string GeneratePrivateData(
const std::string& provider,
const std::string& content_id) const override {
return private_data_;
}
@@ -178,7 +181,7 @@ TEST_F(WvCasCaDescriptorTest, PrivateDataOneByte) {
fake_descriptor.set_private_data("X");
EXPECT_EQ(OK, fake_descriptor.GenerateCaDescriptor(
kTestPid, kProvider, kContentId, &actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x05\x4a\xd4\x00\x32X", 7);
const std::string expected_ca_descriptor("\x09\x05\x4a\xd4\xe0\x32X", 7);
EXPECT_EQ(expected_ca_descriptor, actual_ca_descriptor_);
}
@@ -188,7 +191,7 @@ TEST_F(WvCasCaDescriptorTest, PrivateDataMultipleBytes) {
fake_descriptor.set_private_data(private_data_bytes);
EXPECT_EQ(OK, fake_descriptor.GenerateCaDescriptor(
kTestPid, kProvider, kContentId, &actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\x0e\x4a\xd4\x00\x32", 6);
const std::string expected_ca_descriptor("\x09\x0e\x4a\xd4\xe0\x32", 6);
EXPECT_EQ(expected_ca_descriptor + private_data_bytes, actual_ca_descriptor_);
}
@@ -198,7 +201,7 @@ TEST_F(WvCasCaDescriptorTest, PrivateDataMaxNumberBytes) {
fake_descriptor.set_private_data(private_data_bytes);
EXPECT_EQ(OK, fake_descriptor.GenerateCaDescriptor(
kTestPid, kProvider, kContentId, &actual_ca_descriptor_));
const std::string expected_ca_descriptor("\x09\xff\x4a\xd4\x00\x32", 6);
const std::string expected_ca_descriptor("\x09\xff\x4a\xd4\xe0\x32", 6);
EXPECT_EQ(expected_ca_descriptor + private_data_bytes, actual_ca_descriptor_);
}

View File

@@ -19,7 +19,6 @@
#include "common/status.h"
#include "example/constants.h"
#include "media_cas_packager_sdk/internal/ecm.h"
#include "media_cas_packager_sdk/internal/ecm_generator.h"
#include "media_cas_packager_sdk/internal/fixed_key_fetcher.h"
#include "media_cas_packager_sdk/internal/mpeg2ts.h"
#include "media_cas_packager_sdk/internal/util.h"
@@ -115,9 +114,9 @@ WvCasStatus WvCasEcm::GenerateEcm(
}
std::string even_content_iv_str(even_content_iv, content_iv_size_);
std::string even_entitlement_key_id_str(even_entitlement_key_id,
kEntitlementKeyIdSizeBytes);
kEntitlementKeyIdSizeBytes);
std::string even_entitlement_key_str(even_entitlement_key,
kEntitlementKeySizeBytes);
kEntitlementKeySizeBytes);
std::string odd_key_str;
if (crypto_mode_ == CryptoMode::kDvbCsa2) {
odd_key_str = std::string(odd_key, kCsaContentKeySizeBytes);
@@ -127,8 +126,9 @@ WvCasStatus WvCasEcm::GenerateEcm(
}
std::string odd_content_iv_str(odd_content_iv, content_iv_size_);
std::string odd_entitlement_key_id_str(odd_entitlement_key_id,
kEntitlementKeyIdSizeBytes);
std::string odd_entitlement_key_str(odd_entitlement_key, kEntitlementKeySizeBytes);
kEntitlementKeyIdSizeBytes);
std::string odd_entitlement_key_str(odd_entitlement_key,
kEntitlementKeySizeBytes);
// Double check some input sizes.
if (even_key_str.size() != kContentKeySizeBytes ||
@@ -143,7 +143,7 @@ WvCasStatus WvCasEcm::GenerateEcm(
}
// Create an instance of Ecm in order to set the entitlement keys.
std::unique_ptr<Ecm> cas_ecm = absl::make_unique<Ecm>();
auto cas_ecm = absl::make_unique<Ecm>();
std::string entitlement_request;
std::string entitlement_response;
EcmInitParameters ecm_init_params = CreateEcmInitParameters(
@@ -179,23 +179,21 @@ WvCasStatus WvCasEcm::GenerateEcm(
}
// Generate ECM.
EcmGenerator ecm_generator;
ecm_generator.set_ecm(std::move(cas_ecm));
EcmParameters ecm_param;
ecm_param.rotation_enabled = key_rotation_enabled_;
std::vector<EntitledKeyInfo> keys;
keys.reserve(2);
// Add even entitlement key.
ecm_param.key_params.emplace_back();
ecm_param.key_params[0].key_data = even_key_str;
ecm_param.key_params[0].wrapped_key_iv = crypto_util::DeriveIv(even_key_str);
ecm_param.key_params[0].key_id = crypto_util::DeriveKeyId(even_key_str);
ecm_param.key_params[0].content_ivs.push_back(even_content_iv_str);
keys.emplace_back();
keys[0].key_value = even_key_str;
keys[0].wrapped_key_iv = crypto_util::DeriveIv(even_key_str);
keys[0].key_id = crypto_util::DeriveKeyId(even_key_str);
keys[0].content_iv = even_content_iv_str;
// Add odd entitlement key.
ecm_param.key_params.emplace_back();
ecm_param.key_params[1].key_data = odd_key_str;
ecm_param.key_params[1].wrapped_key_iv = crypto_util::DeriveIv(odd_key_str);
ecm_param.key_params[1].key_id = crypto_util::DeriveKeyId(odd_key_str);
ecm_param.key_params[1].content_ivs.push_back(odd_content_iv_str);
*ecm = ecm_generator.GenerateEcm(ecm_param);
keys.emplace_back();
keys[1].key_value = odd_key_str;
keys[1].wrapped_key_iv = crypto_util::DeriveIv(odd_key_str);
keys[1].key_id = crypto_util::DeriveKeyId(odd_key_str);
keys[1].content_iv = odd_content_iv_str;
status = cas_ecm->GenerateEcm(&keys[0], &keys[1], kDefaultTrackTypeSd, ecm);
size_t expected_ecm_size = content_iv_size_ == 8
? kEcmWith8BytesContentIvSizeBytes
@@ -239,9 +237,9 @@ WvCasStatus WvCasEcm::GenerateSingleKeyEcm(
}
std::string even_content_iv_str(even_content_iv, content_iv_size_);
std::string even_entitlement_key_id_str(even_entitlement_key_id,
kEntitlementKeyIdSizeBytes);
kEntitlementKeyIdSizeBytes);
std::string even_entitlement_key_str(even_entitlement_key,
kEntitlementKeySizeBytes);
kEntitlementKeySizeBytes);
// Double check some input sizes.
if (even_key_str.size() != kContentKeySizeBytes) {
@@ -254,7 +252,7 @@ WvCasStatus WvCasEcm::GenerateSingleKeyEcm(
}
// Create an instance of Ecm in order to set the entitlement keys.
std::unique_ptr<Ecm> cas_ecm = absl::make_unique<Ecm>();
auto cas_ecm = absl::make_unique<Ecm>();
std::string entitlement_request;
std::string entitlement_response;
EcmInitParameters ecm_init_params = CreateEcmInitParameters(
@@ -290,17 +288,12 @@ WvCasStatus WvCasEcm::GenerateSingleKeyEcm(
}
// Generate ECM.
EcmGenerator ecm_generator;
ecm_generator.set_ecm(std::move(cas_ecm));
EcmParameters ecm_param;
ecm_param.rotation_enabled = key_rotation_enabled_;
// Add even entitlement key.
ecm_param.key_params.emplace_back();
ecm_param.key_params[0].key_data = even_key_str;
ecm_param.key_params[0].wrapped_key_iv = crypto_util::DeriveIv(even_key_str);
ecm_param.key_params[0].key_id = crypto_util::DeriveKeyId(even_key_str);
ecm_param.key_params[0].content_ivs.push_back(even_content_iv_str);
*ecm = ecm_generator.GenerateEcm(ecm_param);
EntitledKeyInfo key;
key.key_value = even_key_str;
key.wrapped_key_iv = crypto_util::DeriveIv(even_key_str);
key.key_id = crypto_util::DeriveKeyId(key.key_value);
key.content_iv = even_content_iv_str;
status = cas_ecm->GenerateSingleKeyEcm(&key, kDefaultTrackTypeSd, ecm);
size_t expected_ecm_size = content_iv_size_ == 8
? kSingleKeyEcmWith8BytesContentIvSizeBytes
@@ -317,7 +310,7 @@ WvCasStatus WvCasEcm::GenerateSingleKeyEcm(
WvCasStatus WvCasEcm::GenerateTsPacket(const std::string& ecm, uint16_t pid,
uint8_t table_id,
uint8_t* continuity_counter,
uint8_t* packet) {
uint8_t* packet) const {
ssize_t bytes_modified = 0;
Status status = InsertEcmAsTsPacket(ecm, pid, table_id, continuity_counter,
packet, &bytes_modified);

View File

@@ -118,7 +118,7 @@ class WvCasEcm {
// - |pid| program ID for the ECM stream
// - |table_id| is the table ID byte put in the section header, it should be
// either 0x80 or 0x81. Changing table ID from 0x80 or 0x81 or
// 0x81 to 0x80 is used to singal to the client that the key contained
// 0x81 to 0x80 is used to signal to the client that the key contained
// in the ECM has changed. In other words, if you are building an ECM
// with a new key that was not in any previous ECM, you should flip the
// table ID so the client knows this is an important ECM it should process.
@@ -132,7 +132,7 @@ class WvCasEcm {
virtual WvCasStatus GenerateTsPacket(const std::string& ecm, uint16_t pid,
uint8_t table_id,
uint8_t* continuity_counter,
uint8_t* packet);
uint8_t* packet) const;
private:
bool initialized_ = false;

View File

@@ -138,7 +138,7 @@ TEST_F(WvCasEcmTest, GenerateEcm_8BytesContentIv_Ctr_Success) {
/* odd_entitlement_key= */ kOddEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40103806576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"4ad40203806576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"a94350a82ce961f90b1008c9cdce343b2827827aeb1ba30292c0061d80cf50ce7f657665"
"6e5f69762e6f64645f656e745f6b65795f69642e2e34cd74b6b998889aad0e71b44bdd8c"
"0e03e31ea68ab80a6ee79f59f0936bc6aa64fe976b6a4a5db2dc7e3ebba4a0bd876f6464"
@@ -160,7 +160,7 @@ TEST_F(WvCasEcmTest, GenerateSingleKeyEcm_8BytesContentIv_Ctr_Success) {
/* even_entitlement_key= */ kEvenEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40102806576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"4ad40202806576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"a94350a82ce961f90b1008c9cdce343b2827827aeb1ba30292c0061d80cf50ce7f657665"
"6e5f69762e",
absl::BytesToHexString(actual_ecm));
@@ -186,7 +186,7 @@ TEST_F(WvCasEcmTest, GenerateEcm_16BytesContentIv_Ctr_Success) {
/* odd_entitlement_key= */ kOddEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40103c06576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"4ad40203c06576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"a94350a82ce961f90b1008c9cdce343b2827827aeb1ba30292c0061d80cf50ce7f657665"
"6e5f69762e2e2e2e2e2e2e2e2e6f64645f656e745f6b65795f69642e2e34cd74b6b99888"
"9aad0e71b44bdd8c0e03e31ea68ab80a6ee79f59f0936bc6aa64fe976b6a4a5db2dc7e3e"
@@ -209,7 +209,7 @@ TEST_F(WvCasEcmTest, GenerateSingleKeyEcm_16BytesContentIv_Ctr_Success) {
/* even_entitlement_key= */ kEvenEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40102c06576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"4ad40202c06576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"a94350a82ce961f90b1008c9cdce343b2827827aeb1ba30292c0061d80cf50ce7f657665"
"6e5f69762e2e2e2e2e2e2e2e2e",
absl::BytesToHexString(actual_ecm));
@@ -235,7 +235,7 @@ TEST_F(WvCasEcmTest, GenerateEcm_16BytesContentIv_Cbc_Success) {
/* odd_entitlement_key= */ kOddEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40101c06576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"4ad40201c06576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"a94350a82ce961f90b1008c9cdce343b2827827aeb1ba30292c0061d80cf50ce7f657665"
"6e5f69762e2e2e2e2e2e2e2e2e6f64645f656e745f6b65795f69642e2e34cd74b6b99888"
"9aad0e71b44bdd8c0e03e31ea68ab80a6ee79f59f0936bc6aa64fe976b6a4a5db2dc7e3e"
@@ -258,7 +258,7 @@ TEST_F(WvCasEcmTest, GenerateSingleKeyEcm_16BytesContentIv_Cbc_Success) {
/* even_entitlement_key= */ kEvenEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40100c06576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"4ad40200c06576656e5f656e745f6b65795f69642e3d1798a8729c0a316583bd514cf952"
"a94350a82ce961f90b1008c9cdce343b2827827aeb1ba30292c0061d80cf50ce7f657665"
"6e5f69762e2e2e2e2e2e2e2e2e",
absl::BytesToHexString(actual_ecm));
@@ -284,7 +284,7 @@ TEST_F(WvCasEcmTest, GenerateEcm_8BytesContentIv_Csa_Success) {
/* odd_entitlement_key= */ kOddEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40105806576656e5f656e745f6b65795f69642ee9c009a9d6a07c7bc3ca82f39c1f10"
"4ad40205806576656e5f656e745f6b65795f69642ee9c009a9d6a07c7bc3ca82f39c1f10"
"e6b5f391e74f120cfb876efba02d7f506f0ef185b3398096111dafd86ff7d395a2657665"
"6e5f69762e6f64645f656e745f6b65795f69642e2e7f655fe61e99e89e03ac23df98cc02"
"1cf21dfe9637c72c3480727ab18332d4ee219e81b8f34c9df2704b0595501832736f6464"
@@ -307,7 +307,7 @@ TEST_F(WvCasEcmTest, GenerateSingleKeyEcm_8BytesContentIv_Csa_Success) {
/* even_entitlement_key= */ kEvenEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40104806576656e5f656e745f6b65795f69642ee9c009a9d6a07c7bc3ca82f39c1f10"
"4ad40204806576656e5f656e745f6b65795f69642ee9c009a9d6a07c7bc3ca82f39c1f10"
"e6b5f391e74f120cfb876efba02d7f506f0ef185b3398096111dafd86ff7d395a2657665"
"6e5f69762e",
absl::BytesToHexString(actual_ecm));
@@ -333,7 +333,7 @@ TEST_F(WvCasEcmTest, GenerateEcm_8BytesContentIv_Csa_NulCharInKey_Success) {
/* odd_entitlement_key= */ kOddEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40105806576656e5f656e745f6b65795f69642e71ffb7d9500261db7a92974405c2cf"
"4ad40205806576656e5f656e745f6b65795f69642e71ffb7d9500261db7a92974405c2cf"
"d0b085eb9a85a57dbdb799158e829996988524bf3b3cfe01b28d4474f85ec2991d657665"
"6e5f69762e6f64645f656e745f6b65795f69642e2e874aab870ffba640875a4521d3cd57"
"02f26d0f9c7e9c69d7059c9ad42b091ec1f151aaa190536f4f330edebe84fe5a786f6464"
@@ -357,7 +357,7 @@ TEST_F(WvCasEcmTest,
/* even_entitlement_key= */ kEvenEntitlementKey, &actual_ecm));
EXPECT_EQ(
"4ad40104806576656e5f656e745f6b65795f69642e71ffb7d9500261db7a92974405c2cf"
"4ad40204806576656e5f656e745f6b65795f69642e71ffb7d9500261db7a92974405c2cf"
"d0b085eb9a85a57dbdb799158e829996988524bf3b3cfe01b28d4474f85ec2991d657665"
"6e5f69762e",
absl::BytesToHexString(actual_ecm));

View File

@@ -40,8 +40,9 @@ DEFINE_string(signing_iv, "",
namespace widevine {
namespace cas {
Status WvCasKeyFetcher::RequestEntitlementKey(const std::string& request_string,
std::string* signed_response_string) {
Status WvCasKeyFetcher::RequestEntitlementKey(
const std::string& request_string,
std::string* signed_response_string) const {
if (FLAGS_signing_provider.empty() || FLAGS_signing_key.empty() ||
FLAGS_signing_iv.empty()) {
return Status(
@@ -115,7 +116,8 @@ Status WvCasKeyFetcher::RequestEntitlementKey(const std::string& request_string,
return OkStatus();
}
size_t AppendToString(void* ptr, size_t size, size_t count, std::string* output) {
size_t AppendToString(void* ptr, size_t size, size_t count,
std::string* output) {
const absl::string_view data(static_cast<char*>(ptr), size * count);
absl::StrAppend(output, data);
return data.size();
@@ -140,8 +142,9 @@ Status WvCasKeyFetcher::MakeHttpRequest(const std::string& signed_request_json,
(int64_t)strlen(signed_request_json.c_str()));
curl_code = curl_easy_perform(curl);
if (curl_code != CURLE_OK) {
return Status(error::INTERNAL, "curl_easy_perform() failed: " +
std::string(curl_easy_strerror(curl_code)));
return Status(error::INTERNAL,
"curl_easy_perform() failed: " +
std::string(curl_easy_strerror(curl_code)));
}
curl_easy_cleanup(curl);
} else {

View File

@@ -29,7 +29,7 @@ class WvCasKeyFetcher : public KeyFetcher {
WvCasKeyFetcher() = default;
WvCasKeyFetcher(const WvCasKeyFetcher&) = delete;
WvCasKeyFetcher& operator=(const WvCasKeyFetcher&) = delete;
virtual ~WvCasKeyFetcher() = default;
~WvCasKeyFetcher() override = default;
// Get entitlement keys from the license server. Send a
// SignedCasEncryptionRequest message to the license server, receive a
@@ -40,8 +40,9 @@ class WvCasKeyFetcher : public KeyFetcher {
// |signed_response_string| a serialized SignedCasEncryptionResponse
// message. It should be passed into
// widevine::cas::Ecm::ProcessCasEncryptionResponse().
Status RequestEntitlementKey(const std::string& request_string,
std::string* signed_response_string) override;
Status RequestEntitlementKey(
const std::string& request_string,
std::string* signed_response_string) const override;
protected:
// Makes a HTTP request to License Server for entitlement key(s).

View File

@@ -54,8 +54,9 @@ class MockWvCasKeyFetcher : public WvCasKeyFetcher {
public:
MockWvCasKeyFetcher() : WvCasKeyFetcher() {}
~MockWvCasKeyFetcher() override {}
MOCK_CONST_METHOD2(MakeHttpRequest, Status(const std::string& signed_request_json,
std::string* http_response_json));
MOCK_CONST_METHOD2(MakeHttpRequest,
Status(const std::string& signed_request_json,
std::string* http_response_json));
};
class WvCasKeyFetcherTest : public ::testing::Test {

View File

@@ -46,9 +46,13 @@ std::string GetWvCasStatusMessage(WvCasStatus status) {
// Numeric value of crypto mode is the index into strings array.
static const char* kCrypoModeStrings[] = {
"AesCbc",
"AesCtr",
"DvbCsa2",
"AesCbc", "AesCtr", "DvbCsa2", "DvbCsa3", "AesOfb", "AesScte",
};
// Numeric value of scrambling level is the index into strings array.
static const char* kScramblingLevelStrings[] = {
"PES",
"TS",
};
bool CryptoModeToString(CryptoMode mode, std::string* str) {
@@ -69,7 +73,7 @@ bool StringToCryptoMode(const std::string& str, CryptoMode* mode) {
return false;
}
for (int i = 0; i < arraysize(kCrypoModeStrings); ++i) {
if (str.compare(kCrypoModeStrings[i]) == 0) {
if (str == kCrypoModeStrings[i]) {
*mode = static_cast<CryptoMode>(i);
return true;
}
@@ -78,6 +82,33 @@ bool StringToCryptoMode(const std::string& str, CryptoMode* mode) {
return false;
}
bool ScramblingLevelToString(ScramblingLevel mode, std::string* str) {
if (str == nullptr) {
return false;
}
int mode_idx = static_cast<int>(mode);
if (mode_idx >= 0 && mode_idx < arraysize(kScramblingLevelStrings)) {
*str = kScramblingLevelStrings[mode_idx];
return true;
}
LOG(ERROR) << "Invalid scrambling mode: " << mode_idx;
return false;
}
bool StringToScramblingLevel(const std::string& str, ScramblingLevel* mode) {
if (mode == nullptr) {
return false;
}
for (int i = 0; i < arraysize(kScramblingLevelStrings); ++i) {
if (str == kScramblingLevelStrings[i]) {
*mode = static_cast<ScramblingLevel>(i);
return true;
}
}
LOG(ERROR) << "Invalid scrambling mode: " << str;
return false;
}
WvCasStatus CreateWvCasEncryptionRequestJson(
const WvCasEncryptionRequest& request, std::string* request_json) {
CHECK(request_json);

View File

@@ -52,19 +52,31 @@ enum WvCasStatus {
std::string GetWvCasStatusMessage(WvCasStatus status);
// Crypto mode for encryption / decryption. ENUM value should be consistent with
// https://docs.google.com/document/d/1A5vflf8tbKyUheV-xsvfxFqB6YyNLNdsGXYx8ZnhjfY/edit#heading=h.ej4ts3lifoio
// ECM V2 definition. Largest supported value for this CryptoMode ENUM is 15.
enum class CryptoMode : int {
kInvalid = -1,
kAesCbc = 0,
kAesCtr = 1,
kDvbCsa2 = 2,
kDvbCsa3 = 3,
kAesOfb = 4,
kAesScte = 5,
};
enum class ScramblingLevel : int { kPES = 0, kTS = 1 };
// Returns false if mode is not a valid CryptoMode.
bool CryptoModeToString(CryptoMode mode, std::string* str);
// Returns false if str is not a valid CryptoMode.
bool StringToCryptoMode(const std::string& str, CryptoMode* mode);
// Returns false if mode is not a valid ScramblingLevel.
bool ScramblingLevelToString(ScramblingLevel mode, std::string* str);
// Returns false if str is not a valid ScramblingLevel.
bool StringToScramblingLevel(const std::string& str, ScramblingLevel* mode);
struct WvCasEncryptionRequest {
std::string content_id;
std::string provider;
@@ -111,7 +123,7 @@ struct WvCasEncryptionResponse {
// This request JSON can be later put into the 'request' field of a signed
// request JSON message.
// And that signed JSON message can be sent to Widevine license server for
// aquiring entitlement keys.
// acquiring entitlement keys.
WvCasStatus CreateWvCasEncryptionRequestJson(
const WvCasEncryptionRequest& request, std::string* request_json);

View File

@@ -33,6 +33,12 @@ TEST(WvCasTypesTest, CryptoModeToString) {
EXPECT_EQ("AesCbc", crypto_mode);
ASSERT_TRUE(CryptoModeToString(CryptoMode::kDvbCsa2, &crypto_mode));
EXPECT_EQ("DvbCsa2", crypto_mode);
ASSERT_TRUE(CryptoModeToString(CryptoMode::kDvbCsa3, &crypto_mode));
EXPECT_EQ("DvbCsa3", crypto_mode);
ASSERT_TRUE(CryptoModeToString(CryptoMode::kAesOfb, &crypto_mode));
EXPECT_EQ("AesOfb", crypto_mode);
ASSERT_TRUE(CryptoModeToString(CryptoMode::kAesScte, &crypto_mode));
EXPECT_EQ("AesScte", crypto_mode);
EXPECT_FALSE(CryptoModeToString(static_cast<CryptoMode>(-1), &crypto_mode));
}
@@ -44,9 +50,34 @@ TEST(WvCasTypesTest, StringToCryptoMode) {
EXPECT_EQ(CryptoMode::kAesCbc, crypto_mode);
ASSERT_TRUE(StringToCryptoMode("DvbCsa2", &crypto_mode));
EXPECT_EQ(CryptoMode::kDvbCsa2, crypto_mode);
ASSERT_TRUE(StringToCryptoMode("DvbCsa3", &crypto_mode));
EXPECT_EQ(CryptoMode::kDvbCsa3, crypto_mode);
ASSERT_TRUE(StringToCryptoMode("AesScte", &crypto_mode));
EXPECT_EQ(CryptoMode::kAesScte, crypto_mode);
EXPECT_FALSE(StringToCryptoMode("invalid crypto mode", &crypto_mode));
}
TEST(WvCasTypesTest, ScramblingLevelToString) {
std::string scrambling_level;
ASSERT_TRUE(
ScramblingLevelToString(ScramblingLevel::kPES, &scrambling_level));
EXPECT_EQ("PES", scrambling_level);
ASSERT_TRUE(ScramblingLevelToString(ScramblingLevel::kTS, &scrambling_level));
EXPECT_EQ("TS", scrambling_level);
EXPECT_FALSE(ScramblingLevelToString(static_cast<ScramblingLevel>(-1),
&scrambling_level));
}
TEST(WvCasTypeStatus, StringToScramblingLevel) {
ScramblingLevel scrambling_level;
ASSERT_TRUE(StringToScramblingLevel("PES", &scrambling_level));
EXPECT_EQ(ScramblingLevel::kPES, scrambling_level);
ASSERT_TRUE(StringToScramblingLevel("TS", &scrambling_level));
EXPECT_EQ(ScramblingLevel::kTS, scrambling_level);
EXPECT_FALSE(
StringToScramblingLevel("invalid scrambling level", &scrambling_level));
}
TEST(WvCasTypesTest, CreateWvCasEncryptionRequestJson) {
WvCasEncryptionRequest request;
request.content_id = "test_content_id";

View File

@@ -11,6 +11,7 @@
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstddef>
#include <cstdio>
@@ -22,43 +23,50 @@
#include "glog/logging.h"
#include "absl/strings/str_cat.h"
#include "media_cas_packager_sdk/internal/ecmg_client_handler.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
static constexpr int32_t kDefaultDelayStart = 200;
static constexpr int32_t kDefaultDelayStop = 200;
static constexpr int32_t kDefaultEcmRepPeriod = 100;
static constexpr int32_t kDefaultMaxCompTime = 100;
static constexpr int32_t kAccessCriteriaTransferMode = 1;
static constexpr int32_t kAccessCriteriaTransferMode = 0;
static constexpr int32_t kNumberOfContentKeys = 2;
static constexpr char kDefaultCryptoMode[] = "AesCtr";
static constexpr bool kDefaultUseFixedFetcher = false;
DEFINE_int32(port, 0, "Server port number");
// ECMG related flags.
// TODO(user): Consider adding flags 'ac_delay_start', 'ac_delay_stop',
// 'transition_delay_start', 'transition_delay_stop'.
DEFINE_int32(delay_start, kDefaultDelayStart,
absl::StrCat("This flag sets the DVB SimulCrypt delay_start "
"parameter, in milliseconds. Default: ",
kDefaultDelayStart, " ms")
.c_str());
DEFINE_int32(delay_stop, kDefaultDelayStop,
absl::StrCat("This flag sets the DVB SimulCrypt delay_stop "
"parameter, in milliseconds. Default: ",
kDefaultDelayStop, " ms")
.c_str());
DEFINE_int32(ecm_rep_period, kDefaultEcmRepPeriod,
absl::StrCat("It sets the DVB SimulCrypt parameter "
"ECM_rep_period, in milliseconds. Default: ",
kDefaultEcmRepPeriod, " ms")
.c_str());
DEFINE_int32(max_comp_time, kDefaultMaxCompTime,
absl::StrCat("It sets the DVB SimulCrypt parameter max_comp_time, "
"in milliseconds. Default: ",
kDefaultMaxCompTime, " ms")
.c_str());
DEFINE_int32(access_criteria_transfer_mode, kAccessCriteriaTransferMode,
absl::StrCat("It sets the DVB SimulCrypt parameter "
"access_criteria_transfer_mode. Default: ",
kAccessCriteriaTransferMode)
.c_str());
DEFINE_int32(
delay_start, kDefaultDelayStart,
"This flag sets the DVB SimulCrypt delay_start parameter, in milliseconds");
DEFINE_int32(
delay_stop, kDefaultDelayStop,
"This flag sets the DVB SimulCrypt delay_stop parameter, in milliseconds");
DEFINE_int32(
ecm_rep_period, kDefaultEcmRepPeriod,
"It sets the DVB SimulCrypt parameter ECM_rep_period, in milliseconds");
DEFINE_int32(
max_comp_time, kDefaultMaxCompTime,
"It sets the DVB SimulCrypt parameter max_comp_time, in milliseconds.");
DEFINE_int32(
access_criteria_transfer_mode, kAccessCriteriaTransferMode,
"If it equals 0, it indicates that the access_criteria parameter is "
"required in the CW_provision message only when the contents of this "
"parameter change. If it equals 1, it indicates that the ECMG requires the "
"access_criteria parameter be present in each CW_provision message.");
DEFINE_int32(number_of_content_keys, kNumberOfContentKeys,
"It sets the number of content keys (CwPerMsg). Must be 1 (single "
"key) or 2 (key rotation enabled). It also sets LeadCw as "
"number_of_content_keys - 1.");
DEFINE_string(crypto_mode, kDefaultCryptoMode,
"Encryption mode. Choices are \"AesCtr\", \"AesCbc\", "
"\"DvbCsa2\", \"DvbCsa3\", \"AesOfb\", \"AesScte\".");
DEFINE_bool(use_fixed_fetcher, kDefaultUseFixedFetcher,
"Use fixed fetcher to fetch mocked entitlement licenses for "
"testing purposes.");
#define LISTEN_QUEUE_SIZE (20)
#define BUFFER_SIZE (1024)
@@ -73,6 +81,10 @@ void BuildEcmgConfig(EcmgConfig* config) {
config->ecm_rep_period = FLAGS_ecm_rep_period;
config->max_comp_time = FLAGS_max_comp_time;
config->access_criteria_transfer_mode = FLAGS_access_criteria_transfer_mode;
config->number_of_content_keys = FLAGS_number_of_content_keys;
CHECK(StringToCryptoMode(FLAGS_crypto_mode, &config->crypto_mode))
<< "Unknown crypto mode.";
config->use_fixed_fetcher = FLAGS_use_fixed_fetcher;
}
void PrintMessage(const std::string& description, const char* const message,
@@ -116,6 +128,8 @@ void ServeClient(int socket_fd, EcmgClientHandler* ecmg) {
int main(int argc, char** argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
CHECK(FLAGS_port != 0) << "need --port";
CHECK(FLAGS_number_of_content_keys == 1 || FLAGS_number_of_content_keys == 2)
<< "--number_of_content_keys must be 1 or 2.";
EcmgConfig ecmg_config;
BuildEcmgConfig(&ecmg_config);