Remove Init Data From WB_License_Create

Rather than having init data for the license white-box be passed in
via WB_License_Create, this changes it so that it is assumed that
the private key is compiled into the white-box code.

Minor changes in this code drop include:
  - Updating the git attributes to avoid line-ending conflicts between
    different operating systems

  - Resolving a linking issue seen on Windows

  - Removing default parameter for padding in conformance tests
This commit is contained in:
Aaron Vaage
2020-12-04 14:25:24 -08:00
parent 6b00ecfb33
commit 8ff9df8eeb
37 changed files with 609 additions and 616 deletions

9
whitebox/.gitattributes vendored Normal file
View File

@@ -0,0 +1,9 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.c text
*.cc text
*.h text
*.txt text

View File

@@ -10,12 +10,6 @@ cc_library(
visibility = ["//visibility:public"],
)
cc_library(
name = "export",
hdrs = ["export.h"],
visibility = ["//visibility:private"],
)
cc_library(
name = "aead_whitebox",
hdrs = [
@@ -23,7 +17,6 @@ cc_library(
],
visibility = ["//visibility:public"],
deps = [
":export",
":result",
],
)
@@ -35,16 +28,24 @@ cc_library(
],
visibility = ["//visibility:public"],
deps = [
":export",
":result",
],
)
cc_library(
name = "test_data",
name = "test_public_key",
testonly = True,
hdrs = [
"test_data.h",
"test_public_key.h",
],
visibility = ["//visibility:public"],
)
cc_library(
name = "aead_test_data",
testonly = True,
hdrs = [
"aead_test_data.h",
],
visibility = ["//visibility:public"],
)
@@ -90,10 +91,11 @@ cc_library(
],
visibility = ["//visibility:public"],
deps = [
":aead_test_data",
":aead_whitebox",
":test_data",
"//chromium_deps/testing",
],
alwayslink = True,
)
cc_library(
@@ -104,13 +106,14 @@ cc_library(
],
visibility = ["//visibility:public"],
deps = [
":aead_test_data",
":aead_whitebox",
":test_data",
"//benchmarking:data_source",
"//benchmarking:measurements",
"//chromium_deps/base:glog",
"//chromium_deps/testing",
],
alwayslink = True,
)
cc_library(
@@ -134,15 +137,17 @@ cc_library(
],
visibility = ["//visibility:public"],
deps = [
":aead_test_data",
":golden_data",
":license_whitebox",
":test_data",
":test_license_builder",
":test_public_key",
"//chromium_deps/cdm/keys:api",
"//chromium_deps/cdm/protos:license_protocol_proto",
"//chromium_deps/testing",
"//crypto_utils:rsa_key",
],
alwayslink = True,
)
cc_library(
@@ -160,15 +165,17 @@ cc_library(
],
visibility = ["//visibility:public"],
deps = [
":aead_test_data",
":license_whitebox",
":test_data",
":test_license_builder",
":test_public_key",
"//benchmarking:data_source",
"//benchmarking:measurements",
"//chromium_deps/base:glog",
"//chromium_deps/testing",
"//crypto_utils:crypto_util",
],
alwayslink = True,
)
cc_library(
@@ -182,4 +189,5 @@ cc_library(
":license_whitebox",
"//chromium_deps/testing",
],
alwayslink = True,
)

View File

@@ -1,27 +1,23 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#ifndef WHITEBOX_API_TEST_DATA_H_
#define WHITEBOX_API_TEST_DATA_H_
#ifndef WHITEBOX_API_AEAD_TEST_DATA_H_
#define WHITEBOX_API_AEAD_TEST_DATA_H_
#include <stdint.h>
#include <vector>
namespace widevine {
// Returns init data that the aead white-box will accept.
std::vector<uint8_t> GetValidAeadInitData();
// Returns init data that the aead white-box will reject.
std::vector<uint8_t> GetInvalidAeadInitData();
// Returns valid init_data needed by the license whitebox tests when calling
// WB_License_Create().
std::vector<uint8_t> GetLicenseInitData();
// Returns the matching public key for the data returned by
// GetLicenseInitData(). The format is a DER encoded PKCS#1 RSAPublicKey.
std::vector<uint8_t> GetMatchingLicensePublicKey();
// Returns invalid non-empty init_data that should be rejected by
// WB_License_Create().
std::vector<uint8_t> GetInvalidLicenseInitData();
} // namespace widevine
#endif // WHITEBOX_API_TEST_DATA_H_
#endif // WHITEBOX_API_AEAD_TEST_DATA_H_

View File

@@ -6,7 +6,6 @@
#include <stddef.h>
#include <stdint.h>
#include "api/export.h"
#include "api/result.h"
#ifdef __cplusplus
@@ -43,11 +42,11 @@ typedef struct WB_Aead_Whitebox WB_Aead_Whitebox;
// |context| was null, if |context_size| was zero, or if |whitebox| was null.
//
// WB_RESULT_OUT_OF_MEMORY if the necessary memory could not be allocated.
WB_API WB_Result WB_Aead_Create(const uint8_t* whitebox_init_data,
size_t whitebox_init_data_size,
const uint8_t* context,
size_t context_size,
WB_Aead_Whitebox** whitebox);
WB_Result WB_Aead_Create(const uint8_t* whitebox_init_data,
size_t whitebox_init_data_size,
const uint8_t* context,
size_t context_size,
WB_Aead_Whitebox** whitebox);
// Releases all resources used by the white-box instance pointed to by
// |whitebox|.
@@ -55,7 +54,7 @@ WB_API WB_Result WB_Aead_Create(const uint8_t* whitebox_init_data,
// Args:
// whitebox (in) : A pointer to a white-box instance. Passing in null will
// result in a no-op.
WB_API void WB_Aead_Delete(WB_Aead_Whitebox* whitebox);
void WB_Aead_Delete(WB_Aead_Whitebox* whitebox);
// Encrypts |input_data| and writes the cipher data, nonce and the data
// verification tag to |output_data|. The implementation should generate and use
@@ -86,11 +85,11 @@ WB_API void WB_Aead_Delete(WB_Aead_Whitebox* whitebox);
//
// WB_RESULT_BUFFER_TOO_SMALL if |output_data_size| (as input) was less than
// the required size.
WB_API WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data,
size_t* output_data_size);
WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data,
size_t* output_data_size);
// Decrypts |input_data| and writes the plaintext to |output_data|. |input_data|
// must have been encrypted using WB_Aead_Encrypt() with the same |whitebox|.
@@ -120,11 +119,11 @@ WB_API WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
//
// WB_RESULT_DATA_VERIFICATION_ERROR if |input_data| failed data verification.
// The state of |output_data| is undefined.
WB_API WB_Result WB_Aead_Decrypt(const WB_Aead_Whitebox* whitebox,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data,
size_t* output_data_size);
WB_Result WB_Aead_Decrypt(const WB_Aead_Whitebox* whitebox,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data,
size_t* output_data_size);
#ifdef __cplusplus
}

View File

@@ -5,8 +5,8 @@
#include <vector>
#include "api/aead_test_data.h"
#include "api/aead_whitebox.h"
#include "api/test_data.h"
#include "benchmarking/data_source.h"
#include "benchmarking/measurements.h"
#include "testing/gtest/include/gtest/gtest.h"

View File

@@ -2,11 +2,11 @@
#include <vector>
#include "api/aead_test_data.h"
#include "api/aead_whitebox.h"
#include "api/test_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
namespace widevine {
class AeadWhiteboxCreateTest : public ::testing::Test {
protected:
@@ -72,4 +72,4 @@ TEST_F(AeadWhiteboxCreateTest, InvalidParameterForNullWhitebox) {
WB_RESULT_INVALID_PARAMETER);
ASSERT_FALSE(whitebox_);
}
} // namespace
} // namespace widevine

View File

@@ -2,11 +2,12 @@
#include <vector>
#include "api/aead_test_data.h"
#include "api/aead_whitebox.h"
#include "api/test_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
namespace widevine {
// These tests focus on functionality that should and should not exist between
// different Aead White-box instances. They assume that all other functionality
// of the white-box has already been verified.
@@ -122,4 +123,4 @@ TEST_F(AeadWhiteboxCrossInstanceTest, DataVerificationErrorForCommonContext) {
ASSERT_EQ(plaintext, common_plaintext_);
}
} // namespace
} // namespace widevine

View File

@@ -2,11 +2,12 @@
#include <vector>
#include "api/aead_test_data.h"
#include "api/aead_whitebox.h"
#include "api/test_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
namespace widevine {
// For our decrypt tests, we assume that WB_Aead_Create() and WB_Aead_Encrypt()
// work and each test will have valid encrypted data.
class AeadWhiteboxDecryptTest : public ::testing::Test {
@@ -153,4 +154,4 @@ TEST_F(AeadWhiteboxDecryptTest, DataVerificationError) {
plaintext.data(), &plaintext_size),
WB_RESULT_DATA_VERIFICATION_ERROR);
}
} // namespace
} // namespace widevine

View File

@@ -2,15 +2,17 @@
#include <vector>
#include "api/aead_test_data.h"
#include "api/aead_whitebox.h"
#include "api/test_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace widevine {
namespace {
// Regardless of implementation, we need to have enough room in our output
// buffer to hold the additional information added by WB_Aead_Encrypt(). So
// this number just needs to be reasonably big compared to the input.
constexpr size_t kDefaultOutputSize = 256;
} // namespace
// For our encrypt tests, we assume that WB_Aead_Create() works and each test
// will have a functional instance. In these tests, we will not be checking the
@@ -116,4 +118,4 @@ TEST_F(AeadWhiteboxEncryptTest, BufferTooSmallForSmallOutputBuffer) {
// only check that |output_size| is larger than |input_.size()|.
ASSERT_GT(output_size, input_.size());
}
} // namespace
} // namespace widevine

View File

@@ -1,12 +0,0 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#ifndef WHITEBOX_API_EXPORT_H_
#define WHITEBOX_API_EXPORT_H_
#if defined(_WIN32)
#define WB_API _declspec(dllexport)
#else
#define WB_API __attribute__((visibility("default")))
#endif
#endif // WHITEBOX_API_EXPORT_H_

View File

@@ -6,7 +6,6 @@
#include <stddef.h>
#include <stdint.h>
#include "api/export.h"
#include "api/result.h"
#ifdef __cplusplus
@@ -21,27 +20,20 @@ typedef enum {
WB_CIPHER_MODE_CBC,
} WB_CipherMode;
// Creates a new white-box instance using |whitebox_init_data|. A pointer to the
// white-box instance will be returned via |whitebox|.
// Creates a new white-box instance using the implementation's internal private
// key|. A pointer to the white-box instance will be returned via |whitebox|.
//
// Args:
// whitebox_init_data (in) : The implementation-specific initialization data
// needed to initialize a new white-box instance.
//
// whitebox_init_data_size (in) : The number of bytes in |whitebox_init_data|.
//
// whitebox (out) : The output parameter used to return the new white-box
// instance.
//
// Returns:
// WB_RESULT_OK if the white-box instance was successfully created.
//
// WB_RESULT_INVALID_PARAMETER if |whitebox_init_data| was null or invalid.
// WB_RESULT_INVALID_PARAMETER if |whitebox| was null.
//
// WB_RESULT_OUT_OF_MEMORY if the necessary memory could not be allocated.
WB_API WB_Result WB_License_Create(const uint8_t* whitebox_init_data,
size_t whitebox_init_data_size,
WB_License_Whitebox** whitebox);
WB_Result WB_License_Create(WB_License_Whitebox** whitebox);
// Releases all resources used by the white-box instance pointed to by
// |whitebox|.
@@ -49,7 +41,7 @@ WB_API WB_Result WB_License_Create(const uint8_t* whitebox_init_data,
// Args:
// whitebox (in) : A pointer to a white-box instance. Passing in null will
// result in a no-op.
WB_API void WB_License_Delete(WB_License_Whitebox* whitebox);
void WB_License_Delete(WB_License_Whitebox* whitebox);
// Signs a license request using the CDM's private signing key.
//
@@ -75,12 +67,11 @@ WB_API void WB_License_Delete(WB_License_Whitebox* whitebox);
//
// WB_RESULT_BUFFER_TOO_SMALL if |signature_size| (as input) was less than the
// required size.
WB_API WB_Result
WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox,
const uint8_t* license_request,
size_t license_request_size,
uint8_t* signature,
size_t* signature_size);
WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox,
const uint8_t* license_request,
size_t license_request_size,
uint8_t* signature,
size_t* signature_size);
// Verifies a license response using HMAC and the server signing key.
//
@@ -141,18 +132,17 @@ WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox,
// verification to fail (therefore we return WB_RESULT_INVALID_SIGNATURE).
// Doing this was found to allow for better hardening of the license processing
// code.
WB_API WB_Result
WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
const uint8_t* core_message,
size_t core_message_size,
const uint8_t* message,
size_t message_size,
const uint8_t* signature,
size_t signature_size,
const uint8_t* session_key,
size_t session_key_size,
const uint8_t* license_request,
size_t license_request_size);
WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
const uint8_t* core_message,
size_t core_message_size,
const uint8_t* message,
size_t message_size,
const uint8_t* signature,
size_t signature_size,
const uint8_t* session_key,
size_t session_key_size,
const uint8_t* license_request,
size_t license_request_size);
// Signs |message| and return the signature via |signature| using HMAC and the
// client renewal signing key
@@ -181,12 +171,11 @@ WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox,
// required size.
//
// WB_RESULT_INVALID_STATE if |whitebox| had no signing keys.
WB_API WB_Result
WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox,
const uint8_t* message,
size_t message_size,
uint8_t* signature,
size_t* signature_size);
WB_Result WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox,
const uint8_t* message,
size_t message_size,
uint8_t* signature,
size_t* signature_size);
// Verifies the renewal response using HMAC and the server signing key.
//
@@ -212,12 +201,11 @@ WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox,
// |signature|.
//
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
WB_API WB_Result
WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox,
const uint8_t* message,
size_t message_size,
const uint8_t* signature,
size_t signature_size);
WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox,
const uint8_t* message,
size_t message_size,
const uint8_t* signature,
size_t signature_size);
// Gets the secret string needed by WB_License_Unmask() in order to unmask the
// masked decrypted content returned by WB_License_MaskedDecrypt().
@@ -261,12 +249,12 @@ WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox,
// the required size.
//
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
WB_API WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
WB_CipherMode mode,
const uint8_t* key_id,
size_t key_id_size,
uint8_t* secret_string,
size_t* secret_string_size);
WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
WB_CipherMode mode,
const uint8_t* key_id,
size_t key_id_size,
uint8_t* secret_string,
size_t* secret_string_size);
// Decrypts |input_data| and writes the plaintext to |output_data|.
//
@@ -316,16 +304,16 @@ WB_API WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox,
// the required size.
//
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
WB_API WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox,
WB_CipherMode mode,
const uint8_t* key_id,
size_t key_id_size,
const uint8_t* input_data,
size_t input_data_size,
const uint8_t* iv,
size_t iv_size,
uint8_t* output_data,
size_t* output_data_size);
WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox,
WB_CipherMode mode,
const uint8_t* key_id,
size_t key_id_size,
const uint8_t* input_data,
size_t input_data_size,
const uint8_t* iv,
size_t iv_size,
uint8_t* output_data,
size_t* output_data_size);
// Decrypts |input_data| and write the obfuscated plaintext to
// |masked_output_data|. The obfuscated plaintext can be deobfuscated using
@@ -380,16 +368,16 @@ WB_API WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox,
// than the required size.
//
// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license.
WB_API WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
WB_CipherMode mode,
const uint8_t* key_id,
size_t key_id_size,
const uint8_t* input_data,
size_t input_data_size,
const uint8_t* iv,
size_t iv_size,
uint8_t* masked_output_data,
size_t* masked_output_data_size);
WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
WB_CipherMode mode,
const uint8_t* key_id,
size_t key_id_size,
const uint8_t* input_data,
size_t input_data_size,
const uint8_t* iv,
size_t iv_size,
uint8_t* masked_output_data,
size_t* masked_output_data_size);
// Unmasks a subset of the data in |masked_data| using |secret_string| and
// writes it to |unmasked_data|.
@@ -417,12 +405,12 @@ WB_API WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox,
// secret_string_size (in) : The number of bytes in |secret_string|.
//
// unmasked_data (out) : The output buffer to write the unmasked data to.
WB_API void WB_License_Unmask(const uint8_t* masked_data,
size_t offset,
size_t size,
const uint8_t* secret_string,
size_t secret_string_size,
uint8_t* unmasked_data);
void WB_License_Unmask(const uint8_t* masked_data,
size_t offset,
size_t size,
const uint8_t* secret_string,
size_t secret_string_size,
uint8_t* unmasked_data);
#ifdef __cplusplus
}

View File

@@ -9,8 +9,8 @@
#include <vector>
#include "api/license_whitebox.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "api/test_public_key.h"
#include "benchmarking/data_source.h"
#include "crypto_utils/crypto_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,7 +25,7 @@ void LicenseWhiteboxBenchmark::SetUp() {
key_ = data_source_.Get(kBlockSize);
iv_ = data_source_.Get(kBlockSize);
const auto public_key_data = GetMatchingLicensePublicKey();
const auto public_key_data = GetLicensePublicKey();
public_key_.reset(widevine::RsaPublicKey::Create(
std::string(public_key_data.begin(), public_key_data.end())));
ASSERT_TRUE(public_key_);
@@ -33,12 +33,13 @@ void LicenseWhiteboxBenchmark::SetUp() {
License LicenseWhiteboxBenchmark::CreateLicense() const {
widevine::TestLicenseBuilder license_builder;
license_builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey());
license_builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey(),
TestLicenseBuilder::NoPadding());
// Use secure crypto as it will work with both Decrypt() and
// MaskedDecrypt().
license_builder.AddContentKey(
video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO,
key_id_, key_);
key_id_, key_, TestLicenseBuilder::NoPadding());
widevine::License license;
license_builder.Build(*public_key_, &license);

View File

@@ -56,15 +56,18 @@ class LicenseWhiteboxChromeOSTest
// Only use CBC keys so that we can always use the CBC content.
builder.AddContentKey(golden_data_.CBCCryptoKey().level,
golden_data_.CBCCryptoKey().id,
golden_data_.CBCCryptoKey().content->key);
golden_data_.CBCCryptoKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddContentKey(golden_data_.CBCDecodeKey().level,
golden_data_.CBCDecodeKey().id,
golden_data_.CBCDecodeKey().content->key);
golden_data_.CBCDecodeKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddContentKey(golden_data_.CBCHardwareKey().level,
golden_data_.CBCHardwareKey().id,
golden_data_.CBCHardwareKey().content->key);
golden_data_.CBCHardwareKey().content->key,
TestLicenseBuilder::NoPadding());
builder.SetRemoteAttestation(remote_attestation_);
builder.SetVerificationStatus(verification_status_);

View File

@@ -2,20 +2,12 @@
#include "api/license_whitebox.h"
#include <vector>
#include "api/test_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class LicenseWhiteboxCreateTest : public ::testing::Test {
protected:
void SetUp() override {
init_data_ = GetLicenseInitData();
ASSERT_GT(init_data_.size(), 0u);
}
void TearDown() override { WB_License_Delete(whitebox_); }
WB_License_Whitebox* whitebox_ = nullptr;
@@ -23,35 +15,12 @@ class LicenseWhiteboxCreateTest : public ::testing::Test {
};
TEST_F(LicenseWhiteboxCreateTest, Succeeds) {
ASSERT_EQ(WB_License_Create(init_data_.data(), init_data_.size(), &whitebox_),
WB_RESULT_OK);
ASSERT_EQ(WB_License_Create(&whitebox_), WB_RESULT_OK);
ASSERT_TRUE(whitebox_);
}
TEST_F(LicenseWhiteboxCreateTest, InvalidParameterForNullInitData) {
ASSERT_EQ(WB_License_Create(nullptr, init_data_.size(), &whitebox_),
WB_RESULT_INVALID_PARAMETER);
ASSERT_FALSE(whitebox_);
}
TEST_F(LicenseWhiteboxCreateTest, InvalidParameterForZeroInitDataSize) {
ASSERT_EQ(WB_License_Create(init_data_.data(), 0, &whitebox_),
WB_RESULT_INVALID_PARAMETER);
ASSERT_FALSE(whitebox_);
}
TEST_F(LicenseWhiteboxCreateTest, InvalidParameterForInvalidInitData) {
const std::vector<uint8_t> invalid_init_data = GetInvalidLicenseInitData();
ASSERT_EQ(WB_License_Create(invalid_init_data.data(),
invalid_init_data.size(), &whitebox_),
WB_RESULT_INVALID_PARAMETER);
ASSERT_FALSE(whitebox_);
}
TEST_F(LicenseWhiteboxCreateTest, InvalidParameterForNullWhitebox) {
ASSERT_EQ(WB_License_Create(init_data_.data(), init_data_.size(), nullptr),
WB_RESULT_INVALID_PARAMETER);
ASSERT_EQ(WB_License_Create(nullptr), WB_RESULT_INVALID_PARAMETER);
}
} // namespace

View File

@@ -9,7 +9,6 @@
#include "api/license_whitebox.h"
#include "api/license_whitebox_benchmark.h"
#include "api/result.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "benchmarking/data_source.h"
#include "benchmarking/measurements.h"
@@ -44,9 +43,7 @@ class LicenseWhiteboxDecryptBenchmark
masked_text_.resize(bytes_per_call);
plaintext_.resize(bytes_per_call);
const auto init_data = GetLicenseInitData();
ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_),
WB_RESULT_OK);
ASSERT_EQ(WB_License_Create(&whitebox_), WB_RESULT_OK);
const auto license = CreateLicense();
ASSERT_EQ(

View File

@@ -8,7 +8,6 @@
#include "api/golden_data.h"
#include "api/license_whitebox_test_base.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "crypto_utils/rsa_key.h"
#include "testing/gtest/include/gtest/gtest.h"

View File

@@ -7,7 +7,6 @@
#include "api/golden_data.h"
#include "api/license_whitebox_test_base.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "crypto_utils/rsa_key.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,15 +32,18 @@ class LicenseWhiteboxGetSecretStringTest : public LicenseWhiteboxTestBase {
builder.AddContentKey(golden_data_.CBCCryptoKey().level,
golden_data_.CBCCryptoKey().id,
golden_data_.CBCCryptoKey().content->key);
golden_data_.CBCCryptoKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddContentKey(golden_data_.CBCDecodeKey().level,
golden_data_.CBCDecodeKey().id,
golden_data_.CBCDecodeKey().content->key);
golden_data_.CBCDecodeKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddContentKey(golden_data_.CBCHardwareKey().level,
golden_data_.CBCHardwareKey().id,
golden_data_.CBCHardwareKey().content->key);
golden_data_.CBCHardwareKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddOperatorSessionKey(non_content_key_id_);

View File

@@ -315,9 +315,7 @@ class LicenseWhiteboxDecryptGoldenData : public ::testing::Test {
};
TEST_F(LicenseWhiteboxDecryptGoldenData, CryptoKeyWithCbcDataInCbcMode) {
ASSERT_EQ(WB_License_Create(kLicenseWhiteboxInitData,
kLicenseWhiteboxInitDataSize, &whitebox_),
WB_RESULT_OK);
ASSERT_EQ(WB_License_Create(&whitebox_), WB_RESULT_OK);
ASSERT_EQ(WB_License_ProcessLicenseResponse(
whitebox_, kCoreMessage, kCoreMessageSize, kMessage,

View File

@@ -9,7 +9,6 @@
#include "api/golden_data.h"
#include "api/license_whitebox_test_base.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "crypto_utils/crypto_util.h"
#include "crypto_utils/rsa_key.h"
@@ -42,23 +41,28 @@ class LicenseWhiteboxMaskedDecryptTest : public LicenseWhiteboxTestBase {
builder.AddContentKey(golden_data_.CBCCryptoKey().level,
golden_data_.CBCCryptoKey().id,
golden_data_.CBCCryptoKey().content->key);
golden_data_.CBCCryptoKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddContentKey(golden_data_.CTRCryptoKey().level,
golden_data_.CTRCryptoKey().id,
golden_data_.CTRCryptoKey().content->key);
golden_data_.CTRCryptoKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddContentKey(golden_data_.CBCDecodeKey().level,
golden_data_.CBCDecodeKey().id,
golden_data_.CBCDecodeKey().content->key);
golden_data_.CBCDecodeKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddContentKey(golden_data_.CTRDecodeKey().level,
golden_data_.CTRDecodeKey().id,
golden_data_.CTRDecodeKey().content->key);
golden_data_.CTRDecodeKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddContentKey(golden_data_.CBCHardwareKey().level,
golden_data_.CBCHardwareKey().id,
golden_data_.CBCHardwareKey().content->key);
golden_data_.CBCHardwareKey().content->key,
TestLicenseBuilder::NoPadding());
builder.AddOperatorSessionKey(non_content_key_id_);

View File

@@ -6,7 +6,6 @@
#include "api/license_whitebox.h"
#include "api/license_whitebox_benchmark.h"
#include "api/result.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "benchmarking/measurements.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,16 +36,13 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseBenchmark,
Sampler sampler;
for (size_t i = 0; i < kIterations; i++) {
const auto init_data = GetLicenseInitData();
// We can only call ProcessLicenseResponse() once per whitebox instance. So
// we need to create a new instance each time. Collect samples for create +
// process license + delete so that we know the cost of getting a new
// license.
timer.Reset();
ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_),
WB_RESULT_OK);
ASSERT_EQ(WB_License_Create(&whitebox_), WB_RESULT_OK);
ASSERT_EQ(WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(),
@@ -74,15 +70,12 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseBenchmark,
Sampler sampler;
for (size_t i = 0; i < kIterations; i++) {
const auto init_data = GetLicenseInitData();
// We can only call ProcessLicenseResponse() once per whitebox instance. So
// we need to create a new instance each time. Collect samples for create +
// process license so that we know the true start-up cost.
timer.Reset();
ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_),
WB_RESULT_OK);
ASSERT_EQ(WB_License_Create(&whitebox_), WB_RESULT_OK);
ASSERT_EQ(WB_License_ProcessLicenseResponse(
whitebox_, license_.core_message.data(),
@@ -111,9 +104,7 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseBenchmark, ProcessLicenseResponse) {
// We can only call ProcessLicenseResponse() once per whitebox instance. So
// we need to create a new instance each time. Do this before we reset the
// timer so that we are not counting it in the execution time.
const auto init_data = GetLicenseInitData();
ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_),
WB_RESULT_OK);
ASSERT_EQ(WB_License_Create(&whitebox_), WB_RESULT_OK);
timer.Reset();

View File

@@ -7,7 +7,6 @@
#include "api/golden_data.h"
#include "api/license_whitebox_test_base.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "crypto_utils/crypto_util.h"
#include "crypto_utils/rsa_key.h"
@@ -100,8 +99,7 @@ TEST_F(LicenseWhiteboxProcessLicenseResponseTest,
WB_RESULT_INVALID_PARAMETER);
}
TEST_F(LicenseWhiteboxProcessLicenseResponseTest,
InvalidParameterWithNoKeys) {
TEST_F(LicenseWhiteboxProcessLicenseResponseTest, InvalidParameterWithNoKeys) {
UseLicenseWithNoKeys();
ASSERT_EQ(

View File

@@ -9,7 +9,6 @@
#include "api/license_whitebox.h"
#include "api/license_whitebox_benchmark.h"
#include "api/result.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "benchmarking/data_source.h"
#include "benchmarking/measurements.h"
@@ -32,9 +31,7 @@ class LicenseWhiteboxSignBenchmark : public LicenseWhiteboxBenchmark {
message_ = Data().Get(kMessageSize);
signature_.resize(kSignatureSize);
const auto init_data = GetLicenseInitData();
ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_),
WB_RESULT_OK);
ASSERT_EQ(WB_License_Create(&whitebox_), WB_RESULT_OK);
const auto license = CreateLicense();
ASSERT_EQ(

View File

@@ -7,7 +7,6 @@
#include <vector>
#include "api/license_whitebox_test_base.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "crypto_utils/rsa_key.h"
#include "testing/gtest/include/gtest/gtest.h"

View File

@@ -7,7 +7,6 @@
#include <vector>
#include "api/license_whitebox_test_base.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "crypto_utils/crypto_util.h"
#include "crypto_utils/rsa_key.h"

View File

@@ -4,16 +4,14 @@
#include <string>
#include "api/test_data.h"
#include "api/test_public_key.h"
namespace widevine {
void LicenseWhiteboxTestBase::SetUp() {
const std::vector<uint8_t> init_data = GetLicenseInitData();
ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_),
WB_RESULT_OK);
ASSERT_EQ(WB_License_Create(&whitebox_), WB_RESULT_OK);
const auto public_key_data = GetMatchingLicensePublicKey();
const auto public_key_data = GetLicensePublicKey();
public_key_.reset(RsaPublicKey::Create(
std::string(public_key_data.begin(), public_key_data.end())));

View File

@@ -9,7 +9,6 @@
#include "api/license_whitebox.h"
#include "api/license_whitebox_benchmark.h"
#include "api/result.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "benchmarking/data_source.h"
#include "benchmarking/measurements.h"
@@ -28,9 +27,7 @@ class LicenseWhiteboxVerifyBenchmark : public LicenseWhiteboxBenchmark {
message_ = Data().Get(kMessageSize);
signature_ = SignAsServer(message_);
const auto init_data = GetLicenseInitData();
ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_),
WB_RESULT_OK);
ASSERT_EQ(WB_License_Create(&whitebox_), WB_RESULT_OK);
const auto license = CreateLicense();
ASSERT_EQ(

View File

@@ -7,7 +7,6 @@
#include <vector>
#include "api/license_whitebox_test_base.h"
#include "api/test_data.h"
#include "api/test_license_builder.h"
#include "crypto_utils/crypto_util.h"
#include "crypto_utils/rsa_key.h"

View File

@@ -50,7 +50,7 @@ class TestLicenseBuilder {
TestLicenseBuilder();
void AddSigningKey(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& padding = NoPadding());
const std::vector<uint8_t>& padding);
// Add a content key so that there is some key in the license. This should not
// be used with AddContentKey().
@@ -59,7 +59,7 @@ class TestLicenseBuilder {
void AddContentKey(video_widevine::License_KeyContainer_SecurityLevel level,
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& padding = NoPadding());
const std::vector<uint8_t>& padding);
// The key id will matter as we will need to reference it, but the key won't
// matter since we are only using it as a means to verify that a non-content

View File

@@ -0,0 +1,17 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#ifndef WHITEBOX_API_TEST_PUBLIC_KEY_H_
#define WHITEBOX_API_TEST_PUBLIC_KEY_H_
#include <stdint.h>
#include <vector>
namespace widevine {
// Returns the public key that matches the private key used by the license
// white-box. The public key should be a DER encoded PKCS#1 RSAPublicKey.
std::vector<uint8_t> GetLicensePublicKey();
} // namespace widevine
#endif // WHITEBOX_API_TEST_PUBLIC_KEY_H_

View File

@@ -19,12 +19,20 @@ cc_library(
],
)
cc_library(
name = "license_private_key",
hdrs = [
"license_private_key.h",
],
)
cc_library(
name = "license_whitebox",
srcs = [
"license_whitebox_impl.cc",
],
deps = [
":license_private_key",
":memory_util",
"//api:license_whitebox",
"//api:result",
@@ -39,13 +47,25 @@ cc_library(
)
cc_library(
name = "test_data",
name = "aead_test_data",
testonly = True,
srcs = [
"test_data.cc",
"aead_test_data.cc",
],
deps = [
"//api:test_data",
"//api:aead_test_data",
],
)
cc_library(
name = "license_test_data",
testonly = True,
srcs = [
"license_test_data.cc",
],
deps = [
":license_private_key",
"//api:test_public_key",
"//crypto_utils:rsa_test_keys",
],
)
@@ -54,8 +74,8 @@ cc_test(
name = "aead_whitebox_test",
size = "small",
deps = [
":aead_test_data",
":aead_whitebox",
":test_data",
"//api:aead_whitebox_test",
],
)
@@ -64,8 +84,8 @@ cc_test(
name = "aead_whitebox_benchmark",
size = "small",
deps = [
":aead_test_data",
":aead_whitebox",
":test_data",
"//api:aead_whitebox_benchmark",
],
)
@@ -74,8 +94,8 @@ cc_test(
name = "license_whitebox_test",
size = "small",
deps = [
":license_test_data",
":license_whitebox",
":test_data",
"//api:license_whitebox_test",
],
)
@@ -84,8 +104,8 @@ cc_test(
name = "license_whitebox_benchmark",
size = "small",
deps = [
":license_test_data",
":license_whitebox",
":test_data",
"//api:license_whitebox_benchmark",
],
)

View File

@@ -0,0 +1,24 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include "api/aead_test_data.h"
#include <string>
namespace widevine {
std::vector<uint8_t> GetValidAeadInitData() {
// Valid init data for our AEAD implementation is any AES key, so it just
// needs to be 16 bytes.
return {
0x00, 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0,
0x00, 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0,
};
}
std::vector<uint8_t> GetInvalidAeadInitData() {
// Valid init data would be any 16 bytes. To avoid returning a length of
// zero, just return one byte, that way we are still returning "some data".
return {0x00};
}
} // namespace widevine

View File

@@ -1,215 +1,215 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include "api/aead_whitebox.h"
#include <string.h>
#include <memory>
#include <vector>
#include "base/check_op.h"
#include "base/logging.h"
#include "crypto_utils/crypto_util.h"
#include "impl/reference/memory_util.h"
#include "third_party/boringssl/src/include/openssl/aead.h"
#include "third_party/boringssl/src/include/openssl/rand.h"
struct WB_Aead_Whitebox {
const EVP_AEAD* algorithm;
size_t nonce_size;
EVP_AEAD_CTX context;
};
namespace {
// EVP_AEAD_CTX_init(), EVP_AEAD_CTX_open(), and EVP_AEAD_CTX_seal() return 1
// for success and 0 for failure.
const int kAeadSuccess = 1;
void InitAeadMetadata(WB_Aead_Whitebox* whitebox) {
const EVP_AEAD* algorithm = EVP_aead_aes_128_gcm_siv();
whitebox->algorithm = algorithm;
whitebox->nonce_size = EVP_AEAD_nonce_length(algorithm);
}
std::vector<uint8_t> DeriveKey(const WB_Aead_Whitebox* whitebox,
const uint8_t* init_data,
size_t init_data_size,
const uint8_t* context,
size_t context_size) {
// To derive a key, we need a label to introduce some entropy. The label only
// needs to be some fixed, arbitrary non-trivial string.
constexpr char kLabel[] = "Covfefe";
const std::string init_data_view(init_data, init_data + init_data_size);
const std::string context_view(context, context + context_size);
// While we get the key size in bytes, DeriveKey() needs the key size in bits.
const auto derived_key = widevine::crypto_util::DeriveKey(
init_data_view, kLabel, context_view,
EVP_AEAD_key_length(whitebox->algorithm) * 8);
return std::vector<uint8_t>(derived_key.begin(), derived_key.end());
}
} // namespace
WB_Result WB_Aead_Create(const uint8_t* whitebox_init_data,
size_t whitebox_init_data_size,
const uint8_t* context,
size_t context_size,
::WB_Aead_Whitebox** whitebox) {
if (!whitebox_init_data || !context || !whitebox) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (whitebox_init_data_size == 0 || context_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
// Use a unique pointer internally so that we can return early and
// automatically release the pointer. Should always be non-null on modern
// compilers (https://isocpp.org/wiki/faq/freestore-mgmt).
std::unique_ptr<WB_Aead_Whitebox> aead_whitebox(new WB_Aead_Whitebox());
InitAeadMetadata(aead_whitebox.get());
// Rather than using a fixed key, shared across all instances, derive a key
// for each instance using the provided context. This will allow each instance
// to have its own unique key (assuming they provide a unique context) while
// still allowing a specific key to be recreated when needed (e.g.
// device-locked key).
const std::vector<uint8_t> key =
DeriveKey(aead_whitebox.get(), whitebox_init_data,
whitebox_init_data_size, context, context_size);
const int result = EVP_AEAD_CTX_init(
&aead_whitebox->context, aead_whitebox->algorithm, key.data(), key.size(),
EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr);
if (result != kAeadSuccess) {
DVLOG(1) << "Invalid parameter: invalid init data.";
return WB_RESULT_INVALID_PARAMETER;
}
// release() will release ownership of the pointer and return the unmanaged
// raw pointer.
*whitebox = aead_whitebox.release();
return WB_RESULT_OK;
}
void WB_Aead_Delete(WB_Aead_Whitebox* whitebox) {
if (whitebox != nullptr) {
EVP_AEAD_CTX_cleanup(&whitebox->context);
}
// Safe to delete nullptr (https://isocpp.org/wiki/faq/freestore-mgmt).
delete whitebox;
}
WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data,
size_t* output_data_size) {
if (!whitebox || !input_data || !output_data || !output_data_size) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (input_data_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
std::vector<uint8_t> nonce(whitebox->nonce_size);
RAND_bytes(nonce.data(), nonce.size());
std::vector<uint8_t> output(input_data_size +
EVP_AEAD_max_overhead(whitebox->algorithm));
size_t sealed_size;
CHECK_EQ(EVP_AEAD_CTX_seal(&whitebox->context, output.data(), &sealed_size,
output.size(), nonce.data(), nonce.size(),
input_data, input_data_size, nullptr, 0),
kAeadSuccess);
output.resize(sealed_size);
// At this point, |output| will have the encrypted data and authentication
// tag, but in order to decrypt later, we will need the nonce, so append the
// nonce to the output.
output.insert(output.end(), nonce.begin(), nonce.end());
if (!widevine::MemCopy(output.data(), output.size(), output_data,
*output_data_size)) {
DVLOG(1) << "Buffer too small: output needs " << output.size() << ".";
*output_data_size = output.size();
return WB_RESULT_BUFFER_TOO_SMALL;
}
*output_data_size = output.size();
return WB_RESULT_OK;
}
WB_Result WB_Aead_Decrypt(const WB_Aead_Whitebox* whitebox,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data,
size_t* output_data_size) {
if (!whitebox || !input_data || !output_data || !output_data_size) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
// If we were to encrypt nothing, we would still get the nonce, so the input
// must at least be large enough to contain the nonce.
if (input_data_size <= whitebox->nonce_size) {
DVLOG(1) << "Invalid parameter: invalid input size.";
return WB_RESULT_INVALID_PARAMETER;
}
// The input follows the structure:
// |--------input---------|
// |---payload---||-nonce-|
//
// The payload is the combination of authentication tag and ciphertext
// created by our previous call to EVP_AEAD_CTX_seal().
//
// To use EVP_AEAD_CTX_open(), we need to separate the payload and nonce as
// they must be passed to EVP_AEAD_CTX_open() separately. The result of
// calling EVP_AEAD_CTX_open() will be the plaintext, which will be smaller
// than the payload as the payload included the ciphertext and authentication
// tag.
const uint8_t* payload_start = input_data;
const size_t payload_size = input_data_size - whitebox->nonce_size;
const uint8_t* nonce_start = payload_start + payload_size;
const size_t nonce_size = whitebox->nonce_size;
// Remember, the plaintext will be smaller than the payload, but we are going
// to start with the payload size as it is our best estimate and will scale it
// down when we have the final size.
std::vector<uint8_t> plaintext(payload_size);
size_t plaintext_size;
const int result = EVP_AEAD_CTX_open(
&whitebox->context, plaintext.data(), &plaintext_size, plaintext.size(),
nonce_start, nonce_size, payload_start, payload_size, nullptr, 0);
if (result != kAeadSuccess) {
DVLOG(1) << "Data verification error: failed to verify input data.";
return WB_RESULT_DATA_VERIFICATION_ERROR;
}
// Know that EVP_AEAD_CTX_open() has opened the payload, we know the actual
// plaintext size and can now shrink the vector to the correct size.
plaintext.resize(plaintext_size);
if (!widevine::MemCopy(plaintext.data(), plaintext.size(), output_data,
*output_data_size)) {
DVLOG(1) << "Buffer too small: output needs " << plaintext.size() << ".";
*output_data_size = plaintext.size();
return WB_RESULT_BUFFER_TOO_SMALL;
}
*output_data_size = plaintext.size();
return WB_RESULT_OK;
}
// Copyright 2020 Google LLC. All Rights Reserved.
#include "api/aead_whitebox.h"
#include <string.h>
#include <memory>
#include <vector>
#include "base/check_op.h"
#include "base/logging.h"
#include "crypto_utils/crypto_util.h"
#include "impl/reference/memory_util.h"
#include "third_party/boringssl/src/include/openssl/aead.h"
#include "third_party/boringssl/src/include/openssl/rand.h"
struct WB_Aead_Whitebox {
const EVP_AEAD* algorithm;
size_t nonce_size;
EVP_AEAD_CTX context;
};
namespace {
// EVP_AEAD_CTX_init(), EVP_AEAD_CTX_open(), and EVP_AEAD_CTX_seal() return 1
// for success and 0 for failure.
const int kAeadSuccess = 1;
void InitAeadMetadata(WB_Aead_Whitebox* whitebox) {
const EVP_AEAD* algorithm = EVP_aead_aes_128_gcm_siv();
whitebox->algorithm = algorithm;
whitebox->nonce_size = EVP_AEAD_nonce_length(algorithm);
}
std::vector<uint8_t> DeriveKey(const WB_Aead_Whitebox* whitebox,
const uint8_t* init_data,
size_t init_data_size,
const uint8_t* context,
size_t context_size) {
// To derive a key, we need a label to introduce some entropy. The label only
// needs to be some fixed, arbitrary non-trivial string.
constexpr char kLabel[] = "Covfefe";
const std::string init_data_view(init_data, init_data + init_data_size);
const std::string context_view(context, context + context_size);
// While we get the key size in bytes, DeriveKey() needs the key size in bits.
const auto derived_key = widevine::crypto_util::DeriveKey(
init_data_view, kLabel, context_view,
EVP_AEAD_key_length(whitebox->algorithm) * 8);
return std::vector<uint8_t>(derived_key.begin(), derived_key.end());
}
} // namespace
WB_Result WB_Aead_Create(const uint8_t* whitebox_init_data,
size_t whitebox_init_data_size,
const uint8_t* context,
size_t context_size,
::WB_Aead_Whitebox** whitebox) {
if (!whitebox_init_data || !context || !whitebox) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (whitebox_init_data_size == 0 || context_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
// Use a unique pointer internally so that we can return early and
// automatically release the pointer. Should always be non-null on modern
// compilers (https://isocpp.org/wiki/faq/freestore-mgmt).
std::unique_ptr<WB_Aead_Whitebox> aead_whitebox(new WB_Aead_Whitebox());
InitAeadMetadata(aead_whitebox.get());
// Rather than using a fixed key, shared across all instances, derive a key
// for each instance using the provided context. This will allow each instance
// to have its own unique key (assuming they provide a unique context) while
// still allowing a specific key to be recreated when needed (e.g.
// device-locked key).
const std::vector<uint8_t> key =
DeriveKey(aead_whitebox.get(), whitebox_init_data,
whitebox_init_data_size, context, context_size);
const int result = EVP_AEAD_CTX_init(
&aead_whitebox->context, aead_whitebox->algorithm, key.data(), key.size(),
EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr);
if (result != kAeadSuccess) {
DVLOG(1) << "Invalid parameter: invalid init data.";
return WB_RESULT_INVALID_PARAMETER;
}
// release() will release ownership of the pointer and return the unmanaged
// raw pointer.
*whitebox = aead_whitebox.release();
return WB_RESULT_OK;
}
void WB_Aead_Delete(WB_Aead_Whitebox* whitebox) {
if (whitebox != nullptr) {
EVP_AEAD_CTX_cleanup(&whitebox->context);
}
// Safe to delete nullptr (https://isocpp.org/wiki/faq/freestore-mgmt).
delete whitebox;
}
WB_Result WB_Aead_Encrypt(const WB_Aead_Whitebox* whitebox,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data,
size_t* output_data_size) {
if (!whitebox || !input_data || !output_data || !output_data_size) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (input_data_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
std::vector<uint8_t> nonce(whitebox->nonce_size);
RAND_bytes(nonce.data(), nonce.size());
std::vector<uint8_t> output(input_data_size +
EVP_AEAD_max_overhead(whitebox->algorithm));
size_t sealed_size;
CHECK_EQ(EVP_AEAD_CTX_seal(&whitebox->context, output.data(), &sealed_size,
output.size(), nonce.data(), nonce.size(),
input_data, input_data_size, nullptr, 0),
kAeadSuccess);
output.resize(sealed_size);
// At this point, |output| will have the encrypted data and authentication
// tag, but in order to decrypt later, we will need the nonce, so append the
// nonce to the output.
output.insert(output.end(), nonce.begin(), nonce.end());
if (!widevine::MemCopy(output.data(), output.size(), output_data,
*output_data_size)) {
DVLOG(1) << "Buffer too small: output needs " << output.size() << ".";
*output_data_size = output.size();
return WB_RESULT_BUFFER_TOO_SMALL;
}
*output_data_size = output.size();
return WB_RESULT_OK;
}
WB_Result WB_Aead_Decrypt(const WB_Aead_Whitebox* whitebox,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data,
size_t* output_data_size) {
if (!whitebox || !input_data || !output_data || !output_data_size) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
// If we were to encrypt nothing, we would still get the nonce, so the input
// must at least be large enough to contain the nonce.
if (input_data_size <= whitebox->nonce_size) {
DVLOG(1) << "Invalid parameter: invalid input size.";
return WB_RESULT_INVALID_PARAMETER;
}
// The input follows the structure:
// |--------input---------|
// |---payload---||-nonce-|
//
// The payload is the combination of authentication tag and ciphertext
// created by our previous call to EVP_AEAD_CTX_seal().
//
// To use EVP_AEAD_CTX_open(), we need to separate the payload and nonce as
// they must be passed to EVP_AEAD_CTX_open() separately. The result of
// calling EVP_AEAD_CTX_open() will be the plaintext, which will be smaller
// than the payload as the payload included the ciphertext and authentication
// tag.
const uint8_t* payload_start = input_data;
const size_t payload_size = input_data_size - whitebox->nonce_size;
const uint8_t* nonce_start = payload_start + payload_size;
const size_t nonce_size = whitebox->nonce_size;
// Remember, the plaintext will be smaller than the payload, but we are going
// to start with the payload size as it is our best estimate and will scale it
// down when we have the final size.
std::vector<uint8_t> plaintext(payload_size);
size_t plaintext_size;
const int result = EVP_AEAD_CTX_open(
&whitebox->context, plaintext.data(), &plaintext_size, plaintext.size(),
nonce_start, nonce_size, payload_start, payload_size, nullptr, 0);
if (result != kAeadSuccess) {
DVLOG(1) << "Data verification error: failed to verify input data.";
return WB_RESULT_DATA_VERIFICATION_ERROR;
}
// Know that EVP_AEAD_CTX_open() has opened the payload, we know the actual
// plaintext size and can now shrink the vector to the correct size.
plaintext.resize(plaintext_size);
if (!widevine::MemCopy(plaintext.data(), plaintext.size(), output_data,
*output_data_size)) {
DVLOG(1) << "Buffer too small: output needs " << plaintext.size() << ".";
*output_data_size = plaintext.size();
return WB_RESULT_BUFFER_TOO_SMALL;
}
*output_data_size = plaintext.size();
return WB_RESULT_OK;
}

View File

@@ -0,0 +1,16 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#ifndef WHITEBOX_IMPL_REFERENCE_LICENSE_PRIVATE_KEY_H_
#define WHITEBOX_IMPL_REFERENCE_LICENSE_PRIVATE_KEY_H_
#include <stdint.h>
#include <vector>
namespace widevine {
// Return a RSA 2048-bit private key.
std::vector<uint8_t> GetLicensePrivateKey();
} // namespace widevine
#endif // WHITEBOX_IMPL_REFERENCE_LICENSE_PRIVATE_KEY_H_

View File

@@ -0,0 +1,23 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include <string>
#include "api/test_public_key.h"
#include "crypto_utils/rsa_test_keys.h"
#include "impl/reference/license_private_key.h"
namespace widevine {
std::vector<uint8_t> GetLicensePrivateKey() {
widevine::RsaTestKeys key_generator;
std::string init_data = key_generator.private_test_key_2_2048_bits();
return std::vector<uint8_t>(init_data.begin(), init_data.end());
}
std::vector<uint8_t> GetLicensePublicKey() {
widevine::RsaTestKeys key_generator;
std::string init_data = key_generator.public_test_key_2_2048_bits();
return std::vector<uint8_t>(init_data.begin(), init_data.end());
}
} // namespace widevine

View File

@@ -3,111 +3,113 @@
#include <cstddef>
#include <cstdint>
#include "impl/reference/license_private_key.h"
namespace widevine {
extern const uint8_t kLicenseWhiteboxInitData[] = {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xae, 0xa6, 0xa8, 0xea, 0xdd, 0xac, 0x6f, 0xb4, 0x41, 0x47, 0xcb, 0x18,
0x81, 0xeb, 0xdf, 0x4f, 0x17, 0xf7, 0x17, 0xc0, 0xab, 0x6f, 0x47, 0x50,
0xbf, 0xe4, 0x8c, 0xc9, 0x45, 0x24, 0x5e, 0x1c, 0x2e, 0x86, 0x9f, 0xcb,
0x47, 0x05, 0xf9, 0xfe, 0x91, 0x90, 0xaf, 0xbd, 0x22, 0x14, 0x47, 0xa7,
0x34, 0x39, 0x79, 0x44, 0xe9, 0x92, 0x83, 0x4a, 0x80, 0xa8, 0x2a, 0xe6,
0x9f, 0x2b, 0xb7, 0xda, 0x2a, 0xd2, 0xae, 0x57, 0x5b, 0xfa, 0xb6, 0xdf,
0xca, 0x3e, 0xb1, 0xb8, 0x42, 0x0b, 0xde, 0x46, 0x36, 0xdb, 0x42, 0x33,
0x8b, 0xda, 0x5c, 0x60, 0x44, 0x7c, 0x99, 0xb4, 0x98, 0xb4, 0x1e, 0xd8,
0x25, 0x6d, 0x67, 0x84, 0xc9, 0x67, 0xde, 0x05, 0xe6, 0x06, 0xb5, 0xb5,
0xca, 0xbc, 0xfa, 0xb0, 0xa7, 0x46, 0x29, 0x3f, 0x63, 0x47, 0x9d, 0x70,
0x8d, 0xa2, 0x8d, 0x22, 0xc6, 0xeb, 0x06, 0xd4, 0x5c, 0x3b, 0x62, 0x98,
0xc7, 0xda, 0x16, 0x8f, 0x17, 0x59, 0xd5, 0xcb, 0xd1, 0x5d, 0xe3, 0xe1,
0x07, 0xe6, 0x97, 0x87, 0xf4, 0x22, 0x53, 0xfa, 0xf9, 0xa9, 0xf5, 0xeb,
0xd7, 0x55, 0xdf, 0x32, 0x2d, 0x4e, 0x07, 0x86, 0x25, 0x44, 0x93, 0xd6,
0xf7, 0xc6, 0xf9, 0x78, 0x91, 0x24, 0x1e, 0xd4, 0x6b, 0xe3, 0x4a, 0xff,
0x4a, 0x3a, 0xb9, 0x89, 0x90, 0x61, 0x87, 0xb9, 0x41, 0x45, 0x02, 0xfd,
0xd0, 0xc5, 0x5a, 0x98, 0x41, 0x88, 0xa4, 0xe3, 0xe2, 0xa2, 0x9d, 0x9a,
0x90, 0x3f, 0x44, 0x8e, 0x3a, 0xe1, 0xd1, 0xe9, 0x79, 0x9a, 0xc6, 0xe2,
0x7c, 0x8e, 0x9c, 0x3d, 0xb2, 0xe0, 0x26, 0x5a, 0x46, 0x13, 0xc8, 0x43,
0x9f, 0xf7, 0x51, 0x7e, 0xbb, 0x55, 0x6d, 0xcc, 0x97, 0x38, 0xdb, 0xa4,
0x4b, 0x96, 0x40, 0xe5, 0x2d, 0x8f, 0x43, 0xe3, 0x21, 0x15, 0xda, 0x34,
0x97, 0x7a, 0x9e, 0xbb, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x56, 0x73, 0xe7, 0x1f, 0xc3, 0xb5, 0x4c, 0xe2, 0x24, 0x82, 0x5e,
0x55, 0x76, 0x52, 0x85, 0x0a, 0xc8, 0xe9, 0x26, 0x57, 0xd8, 0x44, 0xd0,
0x3f, 0x77, 0x8d, 0xb1, 0xe7, 0x1b, 0x93, 0xc2, 0x06, 0x1f, 0x3d, 0xc2,
0xb1, 0xc4, 0x29, 0x80, 0x33, 0x74, 0x68, 0xf3, 0xa5, 0x22, 0xce, 0x79,
0x1d, 0x9a, 0x6b, 0x6c, 0xcd, 0x20, 0xf5, 0xc6, 0x89, 0xc5, 0x9f, 0xf9,
0x04, 0x89, 0xfc, 0x01, 0x19, 0x3c, 0xa3, 0x67, 0x6b, 0x94, 0xfb, 0x49,
0x35, 0x04, 0x0e, 0xfe, 0xb8, 0x1f, 0xf1, 0x72, 0x08, 0xbd, 0xb4, 0xd1,
0x53, 0x64, 0xc2, 0x25, 0x81, 0xfd, 0xc4, 0xd3, 0xed, 0x22, 0xbd, 0xde,
0x9a, 0xce, 0x04, 0x16, 0xff, 0x13, 0x17, 0x98, 0x3e, 0xc1, 0x3b, 0xc7,
0x0d, 0x03, 0x1b, 0x82, 0xd8, 0x99, 0x24, 0xd0, 0xdc, 0x30, 0xcf, 0xcd,
0x6e, 0x5e, 0x9d, 0xfd, 0x51, 0x1e, 0xb8, 0x4e, 0x7b, 0x54, 0x83, 0x9b,
0x4f, 0xf8, 0xa6, 0x03, 0xc1, 0x96, 0xf1, 0x6d, 0xc0, 0xa7, 0x17, 0xbd,
0xf1, 0x60, 0xcb, 0xe2, 0x05, 0xa5, 0x9b, 0x05, 0x2e, 0xaf, 0xdc, 0xa7,
0x88, 0xde, 0x53, 0x42, 0xa9, 0xf4, 0x0f, 0xae, 0xf9, 0x96, 0xe9, 0x2c,
0xa6, 0xe8, 0x9d, 0x2c, 0x6b, 0xbc, 0xd8, 0x0f, 0x09, 0x5f, 0x64, 0xb2,
0x21, 0x6f, 0xc0, 0x79, 0x3d, 0x6e, 0xad, 0x93, 0x79, 0x35, 0x87, 0x9a,
0x41, 0xcc, 0x06, 0x24, 0xf0, 0x62, 0x09, 0xfe, 0x46, 0x9a, 0x38, 0xee,
0xc0, 0xc8, 0x08, 0xce, 0x65, 0xda, 0xe4, 0x89, 0x1a, 0xfb, 0xe9, 0x53,
0x0c, 0xd1, 0x80, 0x40, 0xfd, 0xc4, 0x97, 0xf8, 0x19, 0x4e, 0x03, 0x90,
0x4a, 0xda, 0xfd, 0x13, 0x27, 0x89, 0xde, 0x12, 0x8d, 0x52, 0x5a, 0x07,
0xf1, 0x9a, 0xa4, 0x54, 0x98, 0x86, 0xb2, 0x78, 0x76, 0xbf, 0x3a, 0xa9,
0x8b, 0xed, 0xc7, 0x8b, 0x31, 0x02, 0x81, 0x81, 0x00, 0xe2, 0xf3, 0xab,
0x53, 0x7b, 0xee, 0x36, 0xdb, 0xca, 0xa8, 0x74, 0x03, 0xdd, 0xe2, 0xce,
0x87, 0xe2, 0x8c, 0x55, 0x8e, 0xd4, 0x0f, 0x32, 0xec, 0xd2, 0xf9, 0x8b,
0x1f, 0x93, 0xdb, 0x84, 0xd2, 0x42, 0xe1, 0xc7, 0x21, 0x24, 0x2e, 0x36,
0x0c, 0x02, 0x5d, 0x49, 0xea, 0xe0, 0x42, 0xd7, 0x7a, 0x3e, 0xc8, 0x51,
0x92, 0x39, 0x56, 0x10, 0xd7, 0x90, 0x67, 0xa3, 0x34, 0xd6, 0xc2, 0x4a,
0x33, 0x74, 0xfd, 0xe2, 0x7e, 0xe1, 0x3e, 0x59, 0xd7, 0x36, 0x6d, 0x7d,
0xd4, 0xd8, 0x82, 0xfb, 0x2f, 0x1e, 0x5e, 0x32, 0xcd, 0xc3, 0x0a, 0x7f,
0xbd, 0xb0, 0xb3, 0xf9, 0x77, 0x75, 0xb9, 0x0c, 0x63, 0x54, 0xff, 0x25,
0xa3, 0xaf, 0x4a, 0x70, 0x61, 0x32, 0x91, 0xde, 0xfb, 0x95, 0x25, 0xb4,
0x06, 0x98, 0x9d, 0xeb, 0x49, 0xc8, 0xe0, 0xc0, 0x7e, 0x45, 0xfb, 0xe5,
0xf8, 0x72, 0x5b, 0x6b, 0x19, 0x02, 0x81, 0x81, 0x00, 0xc5, 0x01, 0x4b,
0xb7, 0x5f, 0x6d, 0xbc, 0xa6, 0x8c, 0xb8, 0xeb, 0xa5, 0xff, 0x0b, 0xd7,
0x15, 0xd7, 0xef, 0xf6, 0xc9, 0xfe, 0x69, 0xcc, 0xe5, 0xbd, 0x5c, 0xa8,
0x05, 0xa0, 0x4d, 0x3b, 0x1f, 0xa6, 0xcc, 0x37, 0x7b, 0xb1, 0x46, 0xf2,
0xc7, 0x67, 0xcd, 0xc1, 0x20, 0xc4, 0x14, 0xbd, 0x0e, 0x01, 0xa7, 0xd6,
0x3c, 0xe8, 0x18, 0x9d, 0x71, 0x71, 0x37, 0x2a, 0xc0, 0x45, 0x6a, 0x54,
0xe8, 0x63, 0xf0, 0x6e, 0xd2, 0x9f, 0x95, 0x3b, 0xde, 0xb3, 0xc5, 0x60,
0x57, 0x3d, 0xed, 0xef, 0x57, 0xcb, 0x3d, 0x35, 0x3a, 0x2e, 0x5d, 0xb8,
0x0e, 0xf8, 0xff, 0xd2, 0xca, 0xdd, 0xce, 0x0b, 0x10, 0x53, 0xb4, 0xdb,
0x53, 0xf6, 0x02, 0xa5, 0xf1, 0x23, 0x4d, 0x21, 0x6e, 0xc7, 0x52, 0x5a,
0x7a, 0x5d, 0x88, 0x32, 0xa8, 0x65, 0x50, 0x21, 0xf5, 0x81, 0x3f, 0x96,
0xd4, 0x57, 0x48, 0x66, 0xf3, 0x02, 0x81, 0x81, 0x00, 0xdd, 0x83, 0xd6,
0x62, 0x9a, 0xe1, 0x0c, 0xfc, 0x84, 0x96, 0xdc, 0xfd, 0xf5, 0x31, 0xee,
0x42, 0x25, 0x76, 0xb1, 0xff, 0xc1, 0xad, 0xc0, 0x17, 0xf5, 0x68, 0x8a,
0x49, 0x5d, 0x08, 0xf3, 0x60, 0x42, 0xd5, 0x9a, 0x86, 0x17, 0x89, 0x5f,
0x49, 0x63, 0x79, 0x68, 0xaf, 0x6f, 0x0a, 0xee, 0xc4, 0xab, 0xc8, 0xdc,
0x0d, 0x6c, 0x17, 0x3c, 0x43, 0x1a, 0xf8, 0x7d, 0x0d, 0x12, 0xdc, 0xfa,
0x8d, 0xb5, 0x10, 0x25, 0x65, 0x90, 0x36, 0x4a, 0x7c, 0x4b, 0xec, 0x9c,
0xd8, 0x06, 0x27, 0xfa, 0x41, 0xa8, 0x53, 0x6b, 0x24, 0xf8, 0xcd, 0x23,
0x97, 0xa3, 0x84, 0x56, 0xe7, 0x29, 0xa9, 0x5f, 0x95, 0x08, 0x9e, 0x2d,
0x3f, 0xd1, 0xd5, 0x47, 0x51, 0x27, 0x89, 0xc7, 0x6a, 0x29, 0xce, 0x6e,
0x23, 0xce, 0x0c, 0xbd, 0x5d, 0xfc, 0x4a, 0x9a, 0xb7, 0xe5, 0x59, 0x13,
0xc2, 0xe6, 0xe3, 0xa1, 0xe9, 0x02, 0x81, 0x81, 0x00, 0xc3, 0x6f, 0x98,
0xa4, 0xae, 0x97, 0xd7, 0xb9, 0xc6, 0x0a, 0xc1, 0x43, 0xa8, 0xf4, 0x1f,
0x08, 0xfd, 0x72, 0x81, 0xfa, 0x3b, 0x58, 0xcc, 0x3a, 0xf1, 0x93, 0x54,
0xe0, 0x57, 0xf9, 0xa5, 0xf8, 0xad, 0x69, 0x14, 0x75, 0xb2, 0x15, 0x77,
0x4d, 0xd8, 0xad, 0xa6, 0xb5, 0x11, 0xb0, 0x9d, 0x28, 0xa2, 0xfd, 0xd4,
0xac, 0x11, 0x78, 0x31, 0xe0, 0xd3, 0x76, 0xee, 0x03, 0x56, 0x19, 0xb9,
0x67, 0xdd, 0x95, 0x2c, 0xeb, 0xe8, 0x02, 0x8d, 0x25, 0x4e, 0x64, 0x35,
0x41, 0xf7, 0x1e, 0xee, 0xfc, 0xc2, 0x93, 0xd3, 0x15, 0x07, 0xe0, 0x53,
0x73, 0x0f, 0x14, 0x03, 0x12, 0xdb, 0xdd, 0xc6, 0xde, 0x08, 0x9c, 0x77,
0xa5, 0x20, 0x7d, 0xda, 0x0f, 0x91, 0x7c, 0xb7, 0xf9, 0x04, 0xe5, 0xae,
0xfa, 0x8b, 0x85, 0x4c, 0xf3, 0xff, 0xa5, 0xf2, 0x3a, 0x72, 0x61, 0x1a,
0x09, 0x47, 0x19, 0x7d, 0x7f, 0x02, 0x81, 0x80, 0x65, 0xce, 0x33, 0x53,
0xca, 0xfb, 0xe0, 0x29, 0x83, 0x12, 0x93, 0x6c, 0xd9, 0xeb, 0x3b, 0xaa,
0xc5, 0xc4, 0xd1, 0xb0, 0x01, 0x85, 0xba, 0xc7, 0x6d, 0xdb, 0x3f, 0x86,
0x06, 0x4c, 0x7e, 0xc4, 0x64, 0x65, 0x14, 0x5d, 0x9c, 0xe9, 0x54, 0x62,
0x5c, 0xf2, 0x6e, 0xe3, 0x14, 0x80, 0x48, 0x0c, 0xbc, 0xb4, 0xa1, 0xb6,
0x6d, 0x2f, 0xa3, 0x21, 0xc0, 0xfc, 0x45, 0xa9, 0x2e, 0x3d, 0x34, 0x2d,
0x05, 0x39, 0x4f, 0x4b, 0xf1, 0x8c, 0xd3, 0x61, 0xbb, 0x80, 0x2d, 0xa3,
0x50, 0x5c, 0xe0, 0xf4, 0xcd, 0xff, 0x95, 0xdc, 0xa8, 0x23, 0x8f, 0x92,
0x69, 0xcd, 0x36, 0x8a, 0xba, 0xa5, 0xe3, 0xfe, 0xce, 0x8e, 0x67, 0xc5,
0x54, 0x41, 0x8c, 0x44, 0xc5, 0x50, 0x55, 0x7a, 0x7c, 0x91, 0xc9, 0x2e,
0x9e, 0x32, 0x63, 0x37, 0x42, 0x68, 0x29, 0x76, 0x41, 0xdb, 0x77, 0xfd,
0xcb, 0x6a, 0x73, 0x10};
extern const size_t kLicenseWhiteboxInitDataSize =
sizeof(kLicenseWhiteboxInitData);
std::vector<uint8_t> GetLicensePrivateKey() {
return {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xae, 0xa6, 0xa8, 0xea, 0xdd, 0xac, 0x6f, 0xb4, 0x41, 0x47, 0xcb, 0x18,
0x81, 0xeb, 0xdf, 0x4f, 0x17, 0xf7, 0x17, 0xc0, 0xab, 0x6f, 0x47, 0x50,
0xbf, 0xe4, 0x8c, 0xc9, 0x45, 0x24, 0x5e, 0x1c, 0x2e, 0x86, 0x9f, 0xcb,
0x47, 0x05, 0xf9, 0xfe, 0x91, 0x90, 0xaf, 0xbd, 0x22, 0x14, 0x47, 0xa7,
0x34, 0x39, 0x79, 0x44, 0xe9, 0x92, 0x83, 0x4a, 0x80, 0xa8, 0x2a, 0xe6,
0x9f, 0x2b, 0xb7, 0xda, 0x2a, 0xd2, 0xae, 0x57, 0x5b, 0xfa, 0xb6, 0xdf,
0xca, 0x3e, 0xb1, 0xb8, 0x42, 0x0b, 0xde, 0x46, 0x36, 0xdb, 0x42, 0x33,
0x8b, 0xda, 0x5c, 0x60, 0x44, 0x7c, 0x99, 0xb4, 0x98, 0xb4, 0x1e, 0xd8,
0x25, 0x6d, 0x67, 0x84, 0xc9, 0x67, 0xde, 0x05, 0xe6, 0x06, 0xb5, 0xb5,
0xca, 0xbc, 0xfa, 0xb0, 0xa7, 0x46, 0x29, 0x3f, 0x63, 0x47, 0x9d, 0x70,
0x8d, 0xa2, 0x8d, 0x22, 0xc6, 0xeb, 0x06, 0xd4, 0x5c, 0x3b, 0x62, 0x98,
0xc7, 0xda, 0x16, 0x8f, 0x17, 0x59, 0xd5, 0xcb, 0xd1, 0x5d, 0xe3, 0xe1,
0x07, 0xe6, 0x97, 0x87, 0xf4, 0x22, 0x53, 0xfa, 0xf9, 0xa9, 0xf5, 0xeb,
0xd7, 0x55, 0xdf, 0x32, 0x2d, 0x4e, 0x07, 0x86, 0x25, 0x44, 0x93, 0xd6,
0xf7, 0xc6, 0xf9, 0x78, 0x91, 0x24, 0x1e, 0xd4, 0x6b, 0xe3, 0x4a, 0xff,
0x4a, 0x3a, 0xb9, 0x89, 0x90, 0x61, 0x87, 0xb9, 0x41, 0x45, 0x02, 0xfd,
0xd0, 0xc5, 0x5a, 0x98, 0x41, 0x88, 0xa4, 0xe3, 0xe2, 0xa2, 0x9d, 0x9a,
0x90, 0x3f, 0x44, 0x8e, 0x3a, 0xe1, 0xd1, 0xe9, 0x79, 0x9a, 0xc6, 0xe2,
0x7c, 0x8e, 0x9c, 0x3d, 0xb2, 0xe0, 0x26, 0x5a, 0x46, 0x13, 0xc8, 0x43,
0x9f, 0xf7, 0x51, 0x7e, 0xbb, 0x55, 0x6d, 0xcc, 0x97, 0x38, 0xdb, 0xa4,
0x4b, 0x96, 0x40, 0xe5, 0x2d, 0x8f, 0x43, 0xe3, 0x21, 0x15, 0xda, 0x34,
0x97, 0x7a, 0x9e, 0xbb, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x56, 0x73, 0xe7, 0x1f, 0xc3, 0xb5, 0x4c, 0xe2, 0x24, 0x82, 0x5e,
0x55, 0x76, 0x52, 0x85, 0x0a, 0xc8, 0xe9, 0x26, 0x57, 0xd8, 0x44, 0xd0,
0x3f, 0x77, 0x8d, 0xb1, 0xe7, 0x1b, 0x93, 0xc2, 0x06, 0x1f, 0x3d, 0xc2,
0xb1, 0xc4, 0x29, 0x80, 0x33, 0x74, 0x68, 0xf3, 0xa5, 0x22, 0xce, 0x79,
0x1d, 0x9a, 0x6b, 0x6c, 0xcd, 0x20, 0xf5, 0xc6, 0x89, 0xc5, 0x9f, 0xf9,
0x04, 0x89, 0xfc, 0x01, 0x19, 0x3c, 0xa3, 0x67, 0x6b, 0x94, 0xfb, 0x49,
0x35, 0x04, 0x0e, 0xfe, 0xb8, 0x1f, 0xf1, 0x72, 0x08, 0xbd, 0xb4, 0xd1,
0x53, 0x64, 0xc2, 0x25, 0x81, 0xfd, 0xc4, 0xd3, 0xed, 0x22, 0xbd, 0xde,
0x9a, 0xce, 0x04, 0x16, 0xff, 0x13, 0x17, 0x98, 0x3e, 0xc1, 0x3b, 0xc7,
0x0d, 0x03, 0x1b, 0x82, 0xd8, 0x99, 0x24, 0xd0, 0xdc, 0x30, 0xcf, 0xcd,
0x6e, 0x5e, 0x9d, 0xfd, 0x51, 0x1e, 0xb8, 0x4e, 0x7b, 0x54, 0x83, 0x9b,
0x4f, 0xf8, 0xa6, 0x03, 0xc1, 0x96, 0xf1, 0x6d, 0xc0, 0xa7, 0x17, 0xbd,
0xf1, 0x60, 0xcb, 0xe2, 0x05, 0xa5, 0x9b, 0x05, 0x2e, 0xaf, 0xdc, 0xa7,
0x88, 0xde, 0x53, 0x42, 0xa9, 0xf4, 0x0f, 0xae, 0xf9, 0x96, 0xe9, 0x2c,
0xa6, 0xe8, 0x9d, 0x2c, 0x6b, 0xbc, 0xd8, 0x0f, 0x09, 0x5f, 0x64, 0xb2,
0x21, 0x6f, 0xc0, 0x79, 0x3d, 0x6e, 0xad, 0x93, 0x79, 0x35, 0x87, 0x9a,
0x41, 0xcc, 0x06, 0x24, 0xf0, 0x62, 0x09, 0xfe, 0x46, 0x9a, 0x38, 0xee,
0xc0, 0xc8, 0x08, 0xce, 0x65, 0xda, 0xe4, 0x89, 0x1a, 0xfb, 0xe9, 0x53,
0x0c, 0xd1, 0x80, 0x40, 0xfd, 0xc4, 0x97, 0xf8, 0x19, 0x4e, 0x03, 0x90,
0x4a, 0xda, 0xfd, 0x13, 0x27, 0x89, 0xde, 0x12, 0x8d, 0x52, 0x5a, 0x07,
0xf1, 0x9a, 0xa4, 0x54, 0x98, 0x86, 0xb2, 0x78, 0x76, 0xbf, 0x3a, 0xa9,
0x8b, 0xed, 0xc7, 0x8b, 0x31, 0x02, 0x81, 0x81, 0x00, 0xe2, 0xf3, 0xab,
0x53, 0x7b, 0xee, 0x36, 0xdb, 0xca, 0xa8, 0x74, 0x03, 0xdd, 0xe2, 0xce,
0x87, 0xe2, 0x8c, 0x55, 0x8e, 0xd4, 0x0f, 0x32, 0xec, 0xd2, 0xf9, 0x8b,
0x1f, 0x93, 0xdb, 0x84, 0xd2, 0x42, 0xe1, 0xc7, 0x21, 0x24, 0x2e, 0x36,
0x0c, 0x02, 0x5d, 0x49, 0xea, 0xe0, 0x42, 0xd7, 0x7a, 0x3e, 0xc8, 0x51,
0x92, 0x39, 0x56, 0x10, 0xd7, 0x90, 0x67, 0xa3, 0x34, 0xd6, 0xc2, 0x4a,
0x33, 0x74, 0xfd, 0xe2, 0x7e, 0xe1, 0x3e, 0x59, 0xd7, 0x36, 0x6d, 0x7d,
0xd4, 0xd8, 0x82, 0xfb, 0x2f, 0x1e, 0x5e, 0x32, 0xcd, 0xc3, 0x0a, 0x7f,
0xbd, 0xb0, 0xb3, 0xf9, 0x77, 0x75, 0xb9, 0x0c, 0x63, 0x54, 0xff, 0x25,
0xa3, 0xaf, 0x4a, 0x70, 0x61, 0x32, 0x91, 0xde, 0xfb, 0x95, 0x25, 0xb4,
0x06, 0x98, 0x9d, 0xeb, 0x49, 0xc8, 0xe0, 0xc0, 0x7e, 0x45, 0xfb, 0xe5,
0xf8, 0x72, 0x5b, 0x6b, 0x19, 0x02, 0x81, 0x81, 0x00, 0xc5, 0x01, 0x4b,
0xb7, 0x5f, 0x6d, 0xbc, 0xa6, 0x8c, 0xb8, 0xeb, 0xa5, 0xff, 0x0b, 0xd7,
0x15, 0xd7, 0xef, 0xf6, 0xc9, 0xfe, 0x69, 0xcc, 0xe5, 0xbd, 0x5c, 0xa8,
0x05, 0xa0, 0x4d, 0x3b, 0x1f, 0xa6, 0xcc, 0x37, 0x7b, 0xb1, 0x46, 0xf2,
0xc7, 0x67, 0xcd, 0xc1, 0x20, 0xc4, 0x14, 0xbd, 0x0e, 0x01, 0xa7, 0xd6,
0x3c, 0xe8, 0x18, 0x9d, 0x71, 0x71, 0x37, 0x2a, 0xc0, 0x45, 0x6a, 0x54,
0xe8, 0x63, 0xf0, 0x6e, 0xd2, 0x9f, 0x95, 0x3b, 0xde, 0xb3, 0xc5, 0x60,
0x57, 0x3d, 0xed, 0xef, 0x57, 0xcb, 0x3d, 0x35, 0x3a, 0x2e, 0x5d, 0xb8,
0x0e, 0xf8, 0xff, 0xd2, 0xca, 0xdd, 0xce, 0x0b, 0x10, 0x53, 0xb4, 0xdb,
0x53, 0xf6, 0x02, 0xa5, 0xf1, 0x23, 0x4d, 0x21, 0x6e, 0xc7, 0x52, 0x5a,
0x7a, 0x5d, 0x88, 0x32, 0xa8, 0x65, 0x50, 0x21, 0xf5, 0x81, 0x3f, 0x96,
0xd4, 0x57, 0x48, 0x66, 0xf3, 0x02, 0x81, 0x81, 0x00, 0xdd, 0x83, 0xd6,
0x62, 0x9a, 0xe1, 0x0c, 0xfc, 0x84, 0x96, 0xdc, 0xfd, 0xf5, 0x31, 0xee,
0x42, 0x25, 0x76, 0xb1, 0xff, 0xc1, 0xad, 0xc0, 0x17, 0xf5, 0x68, 0x8a,
0x49, 0x5d, 0x08, 0xf3, 0x60, 0x42, 0xd5, 0x9a, 0x86, 0x17, 0x89, 0x5f,
0x49, 0x63, 0x79, 0x68, 0xaf, 0x6f, 0x0a, 0xee, 0xc4, 0xab, 0xc8, 0xdc,
0x0d, 0x6c, 0x17, 0x3c, 0x43, 0x1a, 0xf8, 0x7d, 0x0d, 0x12, 0xdc, 0xfa,
0x8d, 0xb5, 0x10, 0x25, 0x65, 0x90, 0x36, 0x4a, 0x7c, 0x4b, 0xec, 0x9c,
0xd8, 0x06, 0x27, 0xfa, 0x41, 0xa8, 0x53, 0x6b, 0x24, 0xf8, 0xcd, 0x23,
0x97, 0xa3, 0x84, 0x56, 0xe7, 0x29, 0xa9, 0x5f, 0x95, 0x08, 0x9e, 0x2d,
0x3f, 0xd1, 0xd5, 0x47, 0x51, 0x27, 0x89, 0xc7, 0x6a, 0x29, 0xce, 0x6e,
0x23, 0xce, 0x0c, 0xbd, 0x5d, 0xfc, 0x4a, 0x9a, 0xb7, 0xe5, 0x59, 0x13,
0xc2, 0xe6, 0xe3, 0xa1, 0xe9, 0x02, 0x81, 0x81, 0x00, 0xc3, 0x6f, 0x98,
0xa4, 0xae, 0x97, 0xd7, 0xb9, 0xc6, 0x0a, 0xc1, 0x43, 0xa8, 0xf4, 0x1f,
0x08, 0xfd, 0x72, 0x81, 0xfa, 0x3b, 0x58, 0xcc, 0x3a, 0xf1, 0x93, 0x54,
0xe0, 0x57, 0xf9, 0xa5, 0xf8, 0xad, 0x69, 0x14, 0x75, 0xb2, 0x15, 0x77,
0x4d, 0xd8, 0xad, 0xa6, 0xb5, 0x11, 0xb0, 0x9d, 0x28, 0xa2, 0xfd, 0xd4,
0xac, 0x11, 0x78, 0x31, 0xe0, 0xd3, 0x76, 0xee, 0x03, 0x56, 0x19, 0xb9,
0x67, 0xdd, 0x95, 0x2c, 0xeb, 0xe8, 0x02, 0x8d, 0x25, 0x4e, 0x64, 0x35,
0x41, 0xf7, 0x1e, 0xee, 0xfc, 0xc2, 0x93, 0xd3, 0x15, 0x07, 0xe0, 0x53,
0x73, 0x0f, 0x14, 0x03, 0x12, 0xdb, 0xdd, 0xc6, 0xde, 0x08, 0x9c, 0x77,
0xa5, 0x20, 0x7d, 0xda, 0x0f, 0x91, 0x7c, 0xb7, 0xf9, 0x04, 0xe5, 0xae,
0xfa, 0x8b, 0x85, 0x4c, 0xf3, 0xff, 0xa5, 0xf2, 0x3a, 0x72, 0x61, 0x1a,
0x09, 0x47, 0x19, 0x7d, 0x7f, 0x02, 0x81, 0x80, 0x65, 0xce, 0x33, 0x53,
0xca, 0xfb, 0xe0, 0x29, 0x83, 0x12, 0x93, 0x6c, 0xd9, 0xeb, 0x3b, 0xaa,
0xc5, 0xc4, 0xd1, 0xb0, 0x01, 0x85, 0xba, 0xc7, 0x6d, 0xdb, 0x3f, 0x86,
0x06, 0x4c, 0x7e, 0xc4, 0x64, 0x65, 0x14, 0x5d, 0x9c, 0xe9, 0x54, 0x62,
0x5c, 0xf2, 0x6e, 0xe3, 0x14, 0x80, 0x48, 0x0c, 0xbc, 0xb4, 0xa1, 0xb6,
0x6d, 0x2f, 0xa3, 0x21, 0xc0, 0xfc, 0x45, 0xa9, 0x2e, 0x3d, 0x34, 0x2d,
0x05, 0x39, 0x4f, 0x4b, 0xf1, 0x8c, 0xd3, 0x61, 0xbb, 0x80, 0x2d, 0xa3,
0x50, 0x5c, 0xe0, 0xf4, 0xcd, 0xff, 0x95, 0xdc, 0xa8, 0x23, 0x8f, 0x92,
0x69, 0xcd, 0x36, 0x8a, 0xba, 0xa5, 0xe3, 0xfe, 0xce, 0x8e, 0x67, 0xc5,
0x54, 0x41, 0x8c, 0x44, 0xc5, 0x50, 0x55, 0x7a, 0x7c, 0x91, 0xc9, 0x2e,
0x9e, 0x32, 0x63, 0x37, 0x42, 0x68, 0x29, 0x76, 0x41, 0xdb, 0x77, 0xfd,
0xcb, 0x6a, 0x73, 0x10,
};
}
} // namespace widevine

View File

@@ -16,6 +16,7 @@
#include "crypto_utils/aes_ctr_encryptor.h"
#include "crypto_utils/crypto_util.h"
#include "crypto_utils/rsa_key.h"
#include "impl/reference/license_private_key.h"
#include "impl/reference/memory_util.h"
#include "oemcrypto/odk/include/odk.h"
#include "oemcrypto/odk/include/odk_structs.h"
@@ -343,27 +344,16 @@ bool IsPlatformHardwareVerified(const video_widevine::License& license) {
} // namespace
WB_Result WB_License_Create(const uint8_t* whitebox_init_data,
size_t whitebox_init_data_size,
WB_License_Whitebox** whitebox) {
if (!whitebox_init_data || !whitebox) {
WB_Result WB_License_Create(WB_License_Whitebox** whitebox) {
if (whitebox == nullptr) {
DVLOG(1) << "Invalid parameter: null pointer.";
return WB_RESULT_INVALID_PARAMETER;
}
if (whitebox_init_data_size == 0) {
DVLOG(1) << "Invalid parameter: array size 0.";
return WB_RESULT_INVALID_PARAMETER;
}
// |whitebox_init_data| is simply the bytes of a PKCS #8 PrivateKeyInfo block
// of a RSA 2048 bit key.
std::unique_ptr<RsaPrivateKey> key(RsaPrivateKey::Create(std::string(
whitebox_init_data, whitebox_init_data + whitebox_init_data_size)));
if (!key) {
DVLOG(1) << "Invalid parameter: invalid init data.";
return WB_RESULT_INVALID_PARAMETER;
}
const auto init_data = widevine::GetLicensePrivateKey();
std::unique_ptr<RsaPrivateKey> key(
RsaPrivateKey::Create(std::string(init_data.begin(), init_data.end())));
DCHECK(key) << "Failed to load (internal) private key.";
// Should always be non-null on modern compilers
// (https://isocpp.org/wiki/faq/freestore-mgmt).

View File

@@ -1,42 +0,0 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include "api/test_data.h"
#include <string>
#include "crypto_utils/rsa_test_keys.h"
std::vector<uint8_t> GetValidAeadInitData() {
// Valid init data for our AEAD implementation is any AES key, so it just
// needs to be 16 bytes.
return {
0x00, 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0,
0x00, 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0,
};
}
std::vector<uint8_t> GetInvalidAeadInitData() {
// Valid init data would be any 16 bytes. To avoid returning a length of
// zero, just return one byte, that way we are still returning "some data".
return {0x00};
}
std::vector<uint8_t> GetLicenseInitData() {
// For the OpenSSL implementation |init_data| is simply a RSA 2048-bit
// private key. Matching public key is public_test_key_2_2048_bits().
widevine::RsaTestKeys key_generator;
std::string init_data = key_generator.private_test_key_2_2048_bits();
return std::vector<uint8_t>(init_data.begin(), init_data.end());
}
std::vector<uint8_t> GetMatchingLicensePublicKey() {
widevine::RsaTestKeys key_generator;
std::string init_data = key_generator.public_test_key_2_2048_bits();
return std::vector<uint8_t>(init_data.begin(), init_data.end());
}
std::vector<uint8_t> GetInvalidLicenseInitData() {
// For the OpenSSL implementation |init_data| is a private key. So a random
// collection of bytes should not be accepted.
return {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
}