Initial Code Drop

This is the initial code drop of the reference implementation and
test cases for the Widevine Whitebox API.

In this drop, the full reference implementation for the AEAD
white-box is provided and all test cases verifying the top-level
behave have are enabled. Since the implementations can vary so much
the testing is mostly left to verifying the return codes for specific
parameter conditions.

A full reference implementation for the license white-box is provided,
however not all tests are implemented or enabled. A number of tests
have been disabled as they required a loaded license and test licenses
are still being worked on.

The two license white-box API functions that are the further from
competition are ProcessLicenseResponse() and MaskedDecryt().
ProcessLicenseResponse() is still being worked on and MaskedDecrypt()
is waiting on Decrypt() to be fully functional.

Most tests focus on verifying return code for specific parameter
conditions, but as test licenses are created, tests looking to test
the internal behaviour of license management will be added to
ProcessLicenseResponse(), Decrypt(), and MaskedDecrypt().
This commit is contained in:
Aaron Vaage
2020-05-18 19:45:53 -07:00
commit 77f7ef98c0
91 changed files with 9597 additions and 0 deletions

220
crypto_utils/BUILD Normal file
View File

@@ -0,0 +1,220 @@
################################################################################
# Copyright 2017 Google LLC.
#
# This software is licensed under the terms defined in the Widevine Master
# License Agreement. For a copy of this agreement, please contact
# widevine-licensing@google.com.
################################################################################
#
# Constants, data structures, util classes for Widevine libraries.
cc_library(
name = "aes_cbc_decryptor",
srcs = ["aes_cbc_decryptor.cc"],
hdrs = ["aes_cbc_decryptor.h"],
visibility = ["//visibility:public"],
deps = [
"//chromium_deps/base",
"//chromium_deps/third_party/boringssl",
],
)
cc_test(
name = "aes_cbc_decryptor_test",
size = "small",
srcs = ["aes_cbc_decryptor_test.cc"],
deps = [
":aes_cbc_decryptor",
"//chromium_deps/testing:gtest",
],
)
cc_library(
name = "aes_cbc_encryptor",
srcs = ["aes_cbc_encryptor.cc"],
hdrs = ["aes_cbc_encryptor.h"],
visibility = ["//visibility:public"],
deps = [
"//chromium_deps/base",
"//chromium_deps/third_party/boringssl",
],
)
cc_test(
name = "aes_cbc_encryptor_test",
size = "small",
srcs = ["aes_cbc_encryptor_test.cc"],
deps = [
":aes_cbc_encryptor",
"//chromium_deps/testing:gtest",
],
)
cc_library(
name = "aes_ctr_encryptor",
srcs = ["aes_ctr_encryptor.cc"],
hdrs = ["aes_ctr_encryptor.h"],
visibility = ["//visibility:public"],
deps = [
"//chromium_deps/base",
"//chromium_deps/third_party/boringssl",
],
)
cc_test(
name = "aes_ctr_encryptor_test",
size = "small",
srcs = ["aes_ctr_encryptor_test.cc"],
deps = [
":aes_ctr_encryptor",
"//chromium_deps/testing:gtest",
],
)
cc_library(
name = "crypto_util",
srcs = ["crypto_util.cc"],
hdrs = ["crypto_util.h"],
visibility = ["//visibility:public"],
deps = [
"//chromium_deps/base",
"//chromium_deps/third_party/boringssl",
# TODO(hmchen): replace absl::string_view with std::string so that
# these files can be used by other projects which does not use absl.
"@abseil_repo//absl/strings",
],
)
cc_test(
name = "crypto_util_test",
size = "small",
srcs = ["crypto_util_test.cc"],
deps = [
":crypto_util",
"//chromium_deps/testing:gtest",
],
)
cc_library(
name = "private_key_util",
hdrs = ["private_key_util.h"],
visibility = ["//visibility:public"],
deps = [
"//chromium_deps/base",
"//chromium_deps/third_party/boringssl",
],
)
cc_library(
name = "rsa_util",
srcs = ["rsa_util.cc"],
hdrs = ["rsa_util.h"],
visibility = ["//visibility:public"],
deps = [
":private_key_util",
"//chromium_deps/base",
"//chromium_deps/third_party/boringssl",
],
)
cc_test(
name = "rsa_util_test",
size = "medium",
timeout = "short",
srcs = ["rsa_util_test.cc"],
deps = [
":rsa_test_keys",
":rsa_util",
"//chromium_deps/base",
"//chromium_deps/testing:gtest",
"//chromium_deps/third_party/boringssl",
],
)
cc_library(
name = "openssl_util",
hdrs = ["openssl_util.h"],
visibility = ["//visibility:public"],
deps = [
"//chromium_deps/third_party/boringssl",
],
)
cc_library(
name = "random_util",
srcs = ["random_util.cc"],
hdrs = ["random_util.h"],
visibility = ["//visibility:public"],
deps = [
"//chromium_deps/base",
"//chromium_deps/third_party/boringssl",
],
)
cc_test(
name = "random_util_test",
size = "small",
srcs = ["random_util_test.cc"],
deps = [
":random_util",
"//chromium_deps/testing:gtest",
],
)
cc_library(
name = "rsa_key",
srcs = ["rsa_key.cc"],
hdrs = ["rsa_key.h"],
visibility = ["//visibility:public"],
deps = [
":rsa_util",
":sha_util",
"//chromium_deps/base",
"//chromium_deps/third_party/boringssl",
],
)
cc_test(
name = "rsa_key_test",
size = "medium",
timeout = "short",
srcs = ["rsa_key_test.cc"],
deps = [
":rsa_key",
":rsa_test_keys",
":rsa_util",
"//chromium_deps/testing:gtest",
],
)
cc_library(
name = "rsa_test_keys",
testonly = 1,
srcs = ["rsa_test_keys.cc"],
hdrs = ["rsa_test_keys.h"],
visibility = ["//visibility:public"],
deps = [
"//chromium_deps/base",
],
)
cc_library(
name = "sha_util",
srcs = ["sha_util.cc"],
hdrs = ["sha_util.h"],
visibility = ["//visibility:public"],
deps = [
"//chromium_deps/base",
"//chromium_deps/third_party/boringssl",
],
)
cc_test(
name = "sha_util_test",
srcs = ["sha_util_test.cc"],
deps = [
":sha_util",
"//chromium_deps/testing:gtest",
"@abseil_repo//absl/strings",
],
)

View File

@@ -0,0 +1,61 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include "crypto_utils/aes_cbc_decryptor.h"
#include <cstddef>
#include <cstdint>
#include <vector>
#include "base/logging.h"
namespace widevine {
namespace {
constexpr size_t kAesBlockSize = 16;
} // namespace
bool AesCbcDecryptor::SetKey(const uint8_t* key, size_t key_size) {
DCHECK(key);
if (key_size != kAesBlockSize && key_size != kAesBlockSize * 2) {
LOG(WARNING) << "Incorrect key size " << key_size;
return false;
}
if (AES_set_decrypt_key(key, key_size * 8, &aes_key_) != 0) {
LOG(WARNING) << "Invalid AES key.";
return false;
}
aes_key_size_ = key_size;
return true;
}
bool AesCbcDecryptor::Decrypt(const uint8_t* iv,
size_t iv_size,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data) {
DCHECK(iv);
DCHECK(input_data);
DCHECK(output_data);
if (aes_key_size_ == 0) {
LOG(WARNING) << "This class has not been initialized.";
return false;
}
// IV is allowed to be either AES BLOCK size or half of it.
if (iv_size != kAesBlockSize && iv_size != kAesBlockSize / 2) {
LOG(WARNING) << "Invalid IV size " << iv_size;
return false;
}
if ((input_data_size % kAesBlockSize) != 0) {
LOG(WARNING) << "Input data size must be multiple of 16: "
<< input_data_size;
return false;
}
std::vector<uint8_t> local_iv(iv, iv + iv_size);
local_iv.resize(kAesBlockSize);
AES_cbc_encrypt(input_data, output_data, input_data_size, &aes_key_,
local_iv.data(), AES_DECRYPT);
return true;
}
} // namespace widevine

View File

@@ -0,0 +1,32 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#ifndef WHITEBOX_CRYPTO_UTILS_AES_CBC_DECRYPTOR_H_
#define WHITEBOX_CRYPTO_UTILS_AES_CBC_DECRYPTOR_H_
#include <cstddef>
#include <cstdint>
#include "third_party/boringssl/src/include/openssl/aes.h"
namespace widevine {
class AesCbcDecryptor {
public:
// Prepares the encryptor with the key.
virtual bool SetKey(const uint8_t* key, size_t key_size);
// Puts the decrypted result of |input_data| into |output_data|.
virtual bool Decrypt(const uint8_t* iv,
size_t iv_size,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data);
private:
AES_KEY aes_key_;
size_t aes_key_size_ = 0;
};
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_AES_CBC_DECRYPTOR_H_

View File

@@ -0,0 +1,91 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include "crypto_utils/aes_cbc_decryptor.h"
#include <cstdint>
#include <vector>
#include "testing/include/gmock/gmock.h"
#include "testing/include/gtest/gtest.h"
using ::testing::ElementsAreArray;
namespace widevine {
TEST(AesCbcDecryptorTest, NistTestCase) {
// NIST SP 800-38A test vector F.2.1 CBC-AES128.Encrypt.
static const uint8_t kAesCbcKey[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae,
0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88,
0x09, 0xcf, 0x4f, 0x3c};
static const uint8_t kAesCbcIv[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f};
static const uint8_t kAesCbcPlaintext[] = {
// Block #1
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11,
0x73, 0x93, 0x17, 0x2a,
// Block #2
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac,
0x45, 0xaf, 0x8e, 0x51,
// Block #3
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19,
0x1a, 0x0a, 0x52, 0xef,
// Block #4
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b,
0xe6, 0x6c, 0x37, 0x10};
static const uint8_t kAesCbcCiphertext[] = {
// Block #1
0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b,
0x12, 0xe9, 0x19, 0x7d,
// Block #2
0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a,
0x91, 0x76, 0x78, 0xb2,
// Block #3
0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e,
0x22, 0x22, 0x95, 0x16,
// Block #4
0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30,
0x75, 0x86, 0xe1, 0xa7};
AesCbcDecryptor decryptor;
ASSERT_TRUE(decryptor.SetKey(kAesCbcKey, sizeof(kAesCbcKey)));
std::vector<uint8_t> output(sizeof(kAesCbcCiphertext));
ASSERT_TRUE(decryptor.Decrypt(kAesCbcIv, sizeof(kAesCbcIv), kAesCbcCiphertext,
sizeof(kAesCbcCiphertext), output.data()));
EXPECT_THAT(output,
ElementsAreArray(kAesCbcPlaintext, sizeof(kAesCbcPlaintext)));
}
TEST(AesCbcEncryptorTest, NistTestCase2) {
// NIST SP 800-38A test vector F.2.1 CBC-AES128.Encrypt.
static const uint8_t kAesCbcKey[] = {
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
};
static const uint8_t kAesCbcIv[] = {
0x2B, 0x70, 0xA4, 0xB5, 0xC2, 0x67, 0x8F, 0xD7,
0xEC, 0x75, 0xB6, 0x44, 0xE8, 0xC7, 0x6A, 0x2B,
};
static const uint8_t kAesCbcPlaintext[] = {
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41,
0x42, 0x43, 0x44, 0x45, 0x46, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
};
static const uint8_t kAesCbcCiphertext[] = {
0xF5, 0x9B, 0x16, 0x1F, 0x4B, 0xBC, 0x45, 0xC5, 0x16, 0x02, 0x25,
0xD3, 0x7D, 0xDA, 0x22, 0xF4, 0xA7, 0x5D, 0x5F, 0x1A, 0x75, 0x2A,
0xD0, 0xFF, 0x4C, 0x78, 0x7E, 0x2B, 0x36, 0x37, 0xC1, 0x7F,
};
AesCbcDecryptor decryptor;
ASSERT_TRUE(decryptor.SetKey(kAesCbcKey, sizeof(kAesCbcKey)));
std::vector<uint8_t> output(sizeof(kAesCbcPlaintext));
ASSERT_TRUE(decryptor.Decrypt(kAesCbcIv, sizeof(kAesCbcIv), kAesCbcCiphertext,
sizeof(kAesCbcCiphertext), output.data()));
EXPECT_THAT(output,
ElementsAreArray(kAesCbcPlaintext, sizeof(kAesCbcPlaintext)));
}
} // namespace widevine

View File

@@ -0,0 +1,61 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include "crypto_utils/aes_cbc_encryptor.h"
#include <cstddef>
#include <cstdint>
#include <vector>
#include "base/logging.h"
namespace widevine {
namespace {
constexpr size_t kAesBlockSize = 16;
} // namespace
bool AesCbcEncryptor::SetKey(const uint8_t* key, size_t key_size) {
DCHECK(key);
if (key_size != kAesBlockSize && key_size != kAesBlockSize * 2) {
LOG(WARNING) << "Incorrect key size " << key_size;
return false;
}
if (AES_set_encrypt_key(key, key_size * 8, &aes_key_) != 0) {
LOG(WARNING) << "Invalid AES key.";
return false;
}
aes_key_size_ = key_size;
return true;
}
bool AesCbcEncryptor::Encrypt(const uint8_t* iv,
size_t iv_size,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data) {
DCHECK(iv);
DCHECK(input_data);
DCHECK(output_data);
if (aes_key_size_ == 0) {
LOG(WARNING) << "This class has not been initialized.";
return false;
}
// IV is allowed to be either AES BLOCK size or half of it.
if (iv_size != kAesBlockSize && iv_size != kAesBlockSize / 2) {
LOG(WARNING) << "Invalid IV size " << iv_size;
return false;
}
if ((input_data_size % kAesBlockSize) != 0) {
LOG(WARNING) << "Input data size must be multiple of 16: "
<< input_data_size;
return false;
}
std::vector<uint8_t> local_iv(iv, iv + iv_size);
local_iv.resize(kAesBlockSize);
AES_cbc_encrypt(input_data, output_data, input_data_size, &aes_key_,
local_iv.data(), AES_ENCRYPT);
return true;
}
} // namespace widevine

View File

@@ -0,0 +1,32 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#ifndef WHITEBOX_CRYPTO_UTILS_AES_CBC_ENCRYPTOR_H_
#define WHITEBOX_CRYPTO_UTILS_AES_CBC_ENCRYPTOR_H_
#include <cstddef>
#include <cstdint>
#include "third_party/boringssl/src/include/openssl/aes.h"
namespace widevine {
class AesCbcEncryptor {
public:
// Prepares the encryptor with the key.
virtual bool SetKey(const uint8_t* key, size_t key_size);
// Puts the encrypted result of |input_data| into |output_data|.
virtual bool Encrypt(const uint8_t* iv,
size_t iv_size,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data);
private:
AES_KEY aes_key_;
size_t aes_key_size_ = 0;
};
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_AES_CBC_ENCRYPTOR_H_

View File

@@ -0,0 +1,60 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include "crypto_utils/aes_cbc_encryptor.h"
#include <cstdint>
#include <vector>
#include "testing/include/gmock/gmock.h"
#include "testing/include/gtest/gtest.h"
using ::testing::ElementsAreArray;
namespace widevine {
TEST(AesCbcEncryptorTest, NistTestCase) {
// NIST SP 800-38A test vector F.2.1 CBC-AES128.Encrypt.
static const uint8_t kAesCbcKey[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae,
0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88,
0x09, 0xcf, 0x4f, 0x3c};
static const uint8_t kAesCbcIv[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f};
static const uint8_t kAesCbcPlaintext[] = {
// Block #1
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11,
0x73, 0x93, 0x17, 0x2a,
// Block #2
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac,
0x45, 0xaf, 0x8e, 0x51,
// Block #3
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19,
0x1a, 0x0a, 0x52, 0xef,
// Block #4
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b,
0xe6, 0x6c, 0x37, 0x10};
static const uint8_t kAesCbcCiphertext[] = {
// Block #1
0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b,
0x12, 0xe9, 0x19, 0x7d,
// Block #2
0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a,
0x91, 0x76, 0x78, 0xb2,
// Block #3
0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e,
0x22, 0x22, 0x95, 0x16,
// Block #4
0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30,
0x75, 0x86, 0xe1, 0xa7};
AesCbcEncryptor encryptor;
ASSERT_TRUE(encryptor.SetKey(kAesCbcKey, sizeof(kAesCbcKey)));
std::vector<uint8_t> output(sizeof(kAesCbcPlaintext));
ASSERT_TRUE(encryptor.Encrypt(kAesCbcIv, sizeof(kAesCbcIv), kAesCbcPlaintext,
sizeof(kAesCbcPlaintext), output.data()));
EXPECT_THAT(output,
ElementsAreArray(kAesCbcCiphertext, sizeof(kAesCbcCiphertext)));
}
} // namespace widevine

View File

@@ -0,0 +1,78 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#include "crypto_utils/aes_ctr_encryptor.h"
#include <cstddef>
#include <cstdint>
#include <vector>
#include "base/logging.h"
namespace widevine {
namespace {
constexpr size_t kAesBlockSize = 16;
// Increment an 8-byte counter by 1. Return true if overflowed.
bool Increment64(uint8_t* counter) {
DCHECK(counter);
for (int i = 7; i >= 0; --i) {
if (++counter[i] != 0)
return false;
}
return true;
}
} // namespace
bool AesCtrEncryptor::SetKey(const uint8_t* key, size_t key_size) {
DCHECK(key);
if (key_size != kAesBlockSize && key_size != kAesBlockSize * 2) {
LOG(WARNING) << "Incorrect key size " << key_size;
return false;
}
if (AES_set_encrypt_key(key, key_size * 8, &aes_key_) != 0) {
LOG(WARNING) << "Invalid AES key.";
return false;
}
aes_key_size_ = key_size;
return true;
}
bool AesCtrEncryptor::Encrypt(const uint8_t* iv,
size_t iv_size,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data) {
DCHECK(iv);
DCHECK(input_data);
DCHECK(output_data);
if (aes_key_size_ == 0) {
LOG(WARNING) << "This class has not been initialized.";
return false;
}
// IV is allowed to be either AES BLOCK size or half of it.
if (iv_size != kAesBlockSize && iv_size != kAesBlockSize / 2) {
LOG(WARNING) << "Invalid IV size " << iv_size;
return false;
}
std::vector<uint8_t> counter(iv, iv + iv_size);
counter.resize(kAesBlockSize);
std::vector<uint8_t> encrypted_counter(kAesBlockSize);
for (size_t i = 0; i < input_data_size; i += 16) {
AES_encrypt(counter.data(), encrypted_counter.data(), &aes_key_);
// As mentioned in ISO/IEC 23001-7:2016 CENC spec, of the 16 byte counter
// block, bytes 8 to 15 (i.e. the least significant bytes) are used as a
// simple 64 bit unsigned integer that is incremented by one for each
// subsequent block of sample data processed and is kept in network byte
// order.
Increment64(counter.data() + 8);
for (size_t j = 0; j < kAesBlockSize && i + j < input_data_size; j++)
output_data[i + j] = input_data[i + j] ^ encrypted_counter[j];
}
return true;
}
} // namespace widevine

View File

@@ -0,0 +1,32 @@
// Copyright 2020 Google LLC. All Rights Reserved.
#ifndef WHITEBOX_CRYPTO_UTILS_AES_CTR_ENCRYPTOR_H_
#define WHITEBOX_CRYPTO_UTILS_AES_CTR_ENCRYPTOR_H_
#include <cstddef>
#include <cstdint>
#include "third_party/boringssl/src/include/openssl/aes.h"
namespace widevine {
class AesCtrEncryptor {
public:
// Prepares the encryptor with the key.
virtual bool SetKey(const uint8_t* key, size_t key_size);
// Puts the encrypted result of |input_data| into |output_data|.
virtual bool Encrypt(const uint8_t* iv,
size_t iv_size,
const uint8_t* input_data,
size_t input_data_size,
uint8_t* output_data);
private:
AES_KEY aes_key_;
size_t aes_key_size_ = 0;
};
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_AES_CTR_ENCRYPTOR_H_

View File

@@ -0,0 +1,86 @@
#include "crypto_utils/aes_ctr_encryptor.h"
#include <cstdint>
#include <vector>
#include "testing/include/gmock/gmock.h"
#include "testing/include/gtest/gtest.h"
using ::testing::ElementsAreArray;
namespace widevine {
namespace {
// From NIST SP 800-38a test case: - F.5.1 CTR-AES128.Encrypt
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
const uint8_t kAesKey[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
const uint8_t kAesIv[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
const uint8_t kAesCtrPlaintext[] = {
// Block #1
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11,
0x73, 0x93, 0x17, 0x2a,
// Block #2
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac,
0x45, 0xaf, 0x8e, 0x51,
// Block #3
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19,
0x1a, 0x0a, 0x52, 0xef,
// Block #4
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b,
0xe6, 0x6c, 0x37, 0x10};
const uint8_t kAesCtrCiphertext[] = {
// Block #1
0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64,
0x99, 0x0d, 0xb6, 0xce,
// Block #2
0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b,
0xb9, 0xff, 0xfd, 0xff,
// Block #3
0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02,
0x0d, 0xb0, 0x3e, 0xab,
// Block #4
0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0,
0xf3, 0x00, 0x9c, 0xee};
const uint8_t kIv128Zero[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const uint8_t kIv128Max64[] = {0, 0, 0, 0, 0, 0, 0, 0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
} // namespace
TEST(AesCtrEncryptorTest, NistTestCase) {
AesCtrEncryptor encryptor;
ASSERT_TRUE(encryptor.SetKey(kAesKey, sizeof(kAesKey)));
std::vector<uint8_t> output(sizeof(kAesCtrPlaintext));
ASSERT_TRUE(encryptor.Encrypt(kAesIv, sizeof(kAesIv), kAesCtrPlaintext,
sizeof(kAesCtrPlaintext), output.data()));
EXPECT_THAT(output,
ElementsAreArray(kAesCtrCiphertext, sizeof(kAesCtrCiphertext)));
}
TEST(AesCtrEncryptorTest, 128BitIVMax64BoundaryCaseEncryption) {
AesCtrEncryptor encryptor;
ASSERT_TRUE(encryptor.SetKey(kAesKey, sizeof(kAesKey)));
std::vector<uint8_t> output(sizeof(kAesCtrPlaintext));
ASSERT_TRUE(encryptor.Encrypt(kIv128Max64, sizeof(kIv128Max64),
kAesCtrPlaintext, sizeof(kAesCtrPlaintext),
output.data()));
// There are four blocks in plain text. The first block should be encrypted
// with IV = kIv128Max64, the subsequent blocks should be encrypted with iv 0
// to 3.
std::vector<uint8_t> output2(sizeof(kAesCtrPlaintext));
ASSERT_TRUE(encryptor.Encrypt(kIv128Max64, sizeof(kIv128Max64),
kAesCtrPlaintext, 16, &output2[0]));
ASSERT_TRUE(encryptor.Encrypt(kIv128Zero, sizeof(kIv128Zero),
&kAesCtrPlaintext[16],
sizeof(kAesCtrPlaintext) - 16, &output2[16]));
EXPECT_EQ(output, output2);
}
} // namespace widevine

205
crypto_utils/crypto_util.cc Normal file
View File

@@ -0,0 +1,205 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// Implementation of Common crypto utilities used by Widevine services.
#include "crypto_utils/crypto_util.h"
#include "absl/strings/string_view.h"
#include "base/logging.h"
#include "third_party/boringssl/src/include/openssl/aes.h"
#include "third_party/boringssl/src/include/openssl/cmac.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/hmac.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
namespace widevine {
namespace crypto_util {
const char kWrappingKeyLabel[] = "ENCRYPTION";
const int kWrappingKeySizeBits = 128;
const char kSigningKeyLabel[] = "AUTHENTICATION";
const int kSigningKeySizeBits = 256;
const size_t kSigningKeySizeBytes = 32;
const char kIvMasterKey[] = "1234567890123456";
const char kIvLabel[] = "IV_ENCRYPTION";
const int kIvSizeBits = 128;
const char kKeyIdMasterKey[] = "0123456789abcdef";
const char kKeyIdLabel[] = "KEY_ID_ENCRYPTION";
const int kKeyIdSizeBits = 128;
const char kGroupKeyLabel[] = "GROUP_ENCRYPTION";
// TODO(user): This is a temporary key for development. Replace this with
// a real group master key in keystore.
// TODO(user): figure out why VerifySignatureHmacSha256 can not crypto_mcmcpy
// like VerifySignatureHmacSha1.
const char kPhonyGroupMasterKey[] = "fedcba9876543210";
const int kAes128KeySizeBits = 128;
const int kAes128KeySizeBytes = 16;
const int kAes256KeySizeBytes = 32;
const char kKeyboxV3Label[] = "Keyboxv3";
const int kAesBlockSizeBits = AES_BLOCK_SIZE * 8;
const int kAesMaxDerivedBlocks = 255;
const uint32_t kCENCSchemeID = 0x63656E63; // 'cenc' (AES-CTR): 0x63656E63
const uint32_t kCBC1SchemeID = 0x63626331; // 'cbc1' (AES-CBC): 0x63626331
const uint32_t kCENSSchemeID =
0x63656E73; // 'cens' (AES-CTR subsample): 0x63656E73
const uint32_t kCBCSSchemeID =
0x63626373; // 'cbcs' (AES-CBC subsample): 0x63626373
// Creates a SHA-256 HMAC signature for the given message.
std::string CreateSignatureHmacSha256(absl::string_view key,
absl::string_view message) {
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init(&ctx, key.data(), key.size(), EVP_sha256());
HMAC_Update(&ctx, reinterpret_cast<const unsigned char*>(message.data()),
message.size());
unsigned char digest[SHA256_DIGEST_LENGTH];
unsigned int digest_len;
HMAC_Final(&ctx, digest, &digest_len);
HMAC_CTX_cleanup(&ctx);
std::string s(reinterpret_cast<char*>(digest), digest_len);
return s;
}
// Compares the SHA-256 HMAC against the provided signature.
bool VerifySignatureHmacSha256(absl::string_view key,
absl::string_view signature,
absl::string_view message) {
return CreateSignatureHmacSha256(key, message) == signature;
}
// Creates a SHA-1 HMAC signature for the given message.
std::string CreateSignatureHmacSha1(absl::string_view key,
absl::string_view message) {
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init(&ctx, key.data(), key.size(), EVP_sha1());
HMAC_Update(&ctx, reinterpret_cast<const unsigned char*>(message.data()),
message.size());
unsigned char digest[SHA_DIGEST_LENGTH];
unsigned int digest_len;
HMAC_Final(&ctx, digest, &digest_len);
HMAC_CTX_cleanup(&ctx);
std::string s(reinterpret_cast<char*>(digest), digest_len);
return s;
}
// Compares the SHA-1 HMAC against the provided signature.
bool VerifySignatureHmacSha1(absl::string_view key,
absl::string_view signature,
absl::string_view message) {
return CreateSignatureHmacSha1(key, message) == signature;
}
// Derives a key from the provided AES 128 or 256 key and additional info.
std::string DeriveKey(absl::string_view key,
absl::string_view label,
absl::string_view context,
const uint32_t size_bits) {
// We only handle multiples of AES blocks (16 bytes) with a maximum of 255
// blocks.
const uint32_t output_block_count = size_bits / kAesBlockSizeBits;
if (size_bits % kAesBlockSizeBits ||
output_block_count > kAesMaxDerivedBlocks) {
return "";
}
const EVP_CIPHER* cipher = nullptr;
const size_t key_size_bytes = key.size();
switch (key_size_bytes) {
case kAes128KeySizeBytes:
cipher = EVP_aes_128_cbc();
break;
case kAes256KeySizeBytes:
cipher = EVP_aes_256_cbc();
break;
default:
return "";
}
std::string result;
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
for (unsigned char counter = 0; counter < output_block_count; counter++) {
if (CMAC_Init(cmac_ctx, key.data(), key_size_bytes, cipher, nullptr)) {
std::string message;
message.append(1, counter + 1);
message.append(label.data(), label.size());
message.append(1, '\0');
message.append(context.data(), context.size());
message.append(1, (size_bits >> 24) & 0xFF);
message.append(1, (size_bits >> 16) & 0xFF);
message.append(1, (size_bits >> 8) & 0xFF);
message.append(1, size_bits & 0xFF);
if (CMAC_Update(cmac_ctx,
reinterpret_cast<const uint8_t*>(message.data()),
message.size())) {
size_t reslen;
unsigned char res[AES_BLOCK_SIZE];
if (CMAC_Final(cmac_ctx, res, &reslen)) {
result.append(reinterpret_cast<const char*>(res), reslen);
}
DCHECK(reslen == AES_BLOCK_SIZE);
}
}
}
CMAC_CTX_free(cmac_ctx);
return result;
}
// Derives an IV from the provided info.
std::string DeriveIv(absl::string_view context) {
return DeriveKey(kIvMasterKey, kIvLabel, context, kIvSizeBits);
}
// Derives a key ID from the provided info.
std::string DeriveKeyId(absl::string_view context) {
return DeriveKey(kKeyIdMasterKey, kKeyIdLabel, context, kKeyIdSizeBits);
}
std::string DeriveGroupSessionKey(absl::string_view context,
const uint32_t size_bits) {
return DeriveKey(kPhonyGroupMasterKey, kGroupKeyLabel, context, size_bits);
}
std::string DeriveSigningKey(absl::string_view key,
absl::string_view context,
const uint32_t size_bits) {
return DeriveKey(key, kSigningKeyLabel, context, size_bits);
}
bool FourCCEncryptionSchemeIDFromString(const std::string& requested,
uint32_t* four_cc_code) {
if (requested.size() != 4 || four_cc_code == nullptr)
return false;
uint32_t result = 0;
for (auto i = 0; i < 4; ++i) {
result <<= 8;
result |= requested[i];
}
switch (result) {
case kCENCSchemeID:
case kCBC1SchemeID:
case kCENSSchemeID:
case kCBCSSchemeID:
*four_cc_code = result;
return true;
default:
return false;
}
}
} // namespace crypto_util
} // namespace widevine

View File

@@ -0,0 +1,94 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// Contains common crypto routines for widevine protocols. These routines are
// used as part of licensing and provisioning request handling.
#ifndef WHITEBOX_CRYPTO_UTILS_CRYPTO_UTIL_H_
#define WHITEBOX_CRYPTO_UTILS_CRYPTO_UTIL_H_
#include <string>
#include "absl/strings/string_view.h"
namespace widevine {
namespace crypto_util {
// Default constants used for key derivation for encryption and signing.
// TODO(user): These are duplicated in session.cc in the sdk. de-dup.
extern const char kWrappingKeyLabel[];
extern const int kWrappingKeySizeBits;
extern const char kSigningKeyLabel[];
extern const int kSigningKeySizeBits;
extern const size_t kSigningKeySizeBytes;
extern const char kIvMasterKey[];
extern const char kIvLabel[];
extern const int kIvSizeBits;
extern const int kAes128KeySizeBits;
extern const int kAes128KeySizeBytes;
extern const char kKeyboxV3Label[];
extern const uint32_t kCENCSchemeID; // 'cenc' (AES-CTR): 0x63656E63
extern const uint32_t kCBC1SchemeID; // 'cbc1' (AES-CBC): 0x63626331
extern const uint32_t kCENSSchemeID; // 'cens' (AES-CTR subsample): 0x63656E73
extern const uint32_t kCBCSSchemeID; // 'cbcs' (AES-CBC subsample): 0x63626373
// DeriveKey uses the NIST 800-108 KDF recommendation, using AES-CMAC PRF.
// NIST 800-108:
// http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf
// AES-CMAC:
// http://tools.ietf.org/html/rfc4493
std::string DeriveKey(absl::string_view key,
absl::string_view label,
absl::string_view context,
const uint32_t size_bits);
// Derives an IV from the provided |context|.
std::string DeriveIv(absl::string_view context);
// Derives a key ID from the provided |context|.
std::string DeriveKeyId(absl::string_view context);
// Helper function to derive a key using the group master key and context.
std::string DeriveGroupSessionKey(absl::string_view context,
const uint32_t size_bits);
// Helper function to derive a signing key for from the signing context.
std::string DeriveSigningKey(absl::string_view key,
absl::string_view context,
const uint32_t size_bits);
// Helper function to create a SHA-256 HMAC signature for the given message.
std::string CreateSignatureHmacSha256(absl::string_view key,
absl::string_view message);
// Helper function which compares the SHA-256 HMAC against the provided
// signature.
bool VerifySignatureHmacSha256(absl::string_view key,
absl::string_view signature,
absl::string_view message);
// Helper function to create a SHA-1 HMAC signature for the given message.
std::string CreateSignatureHmacSha1(absl::string_view key,
absl::string_view message);
// Helper function which compares the SHA-1 HMAC against the provided
// signature.
bool VerifySignatureHmacSha1(absl::string_view key,
absl::string_view signature,
absl::string_view message);
// Converts a requested 4CC encryption scheme ID from a std::string to a
// uint32_t and verifies it is a correct value.
bool FourCCEncryptionSchemeIDFromString(const std::string& requested,
uint32_t* four_cc_code);
} // namespace crypto_util
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_CRYPTO_UTIL_H_

View File

@@ -0,0 +1,308 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// Unit tests for the crypto_util helper functions.
#include "crypto_utils/crypto_util.h"
#include <string>
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "testing/include/gmock/gmock.h"
#include "testing/include/gtest/gtest.h"
#include "third_party/boringssl/src/include/openssl/aes.h"
namespace widevine {
namespace crypto_util {
const char kCENCStr[] = "cenc";
const char kCBC1Str[] = "cbc1";
const char kCENSStr[] = "cens";
const char kCBCSStr[] = "cbcs";
static unsigned char kAes128KeyData[] = {0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82,
0x32, 0x9e, 0x6b, 0x3b, 0x4e, 0x29,
0xfa, 0x3b, 0x00, 0x4b};
static unsigned char kAes256KeyData[] = {
0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82, 0x32, 0x9e, 0x6b, 0x3b, 0x4e,
0x29, 0xfa, 0x3b, 0x00, 0x4b, 0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82,
0x32, 0x9e, 0x6b, 0x3b, 0x4e, 0x29, 0xfa, 0x3b, 0x00, 0x4b};
static unsigned char kAes128IvData[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f};
class CryptoUtilTest : public ::testing::Test {
public:
CryptoUtilTest()
: aes_128_key_(kAes128KeyData, kAes128KeyData + sizeof(kAes128KeyData)),
aes_256_key_(kAes256KeyData, kAes256KeyData + sizeof(kAes256KeyData)),
iv_128_(kAes128IvData, kAes128IvData + sizeof(kAes128IvData)) {}
protected:
std::string aes_128_key_;
std::string aes_256_key_;
std::string iv_128_;
};
TEST_F(CryptoUtilTest, DeriveAes128MasterKeyTest) {
unsigned char label[] = {0x16, 0xf1, 0xa4, 0x32, 0x9f, 0x94, 0x55, 0xc1, 0x92,
0xa0, 0x34, 0x8a, 0x8b, 0x6b, 0x77, 0x08, 0xbc, 0x23,
0x70, 0x16, 0xbc, 0xda, 0xfb, 0x60, 0xd1, 0xcf, 0x6a,
0x4d, 0x40, 0xa1, 0xe3, 0xfe, 0xd3, 0xe9, 0xa6, 0x58,
0x4c, 0xd4, 0xad, 0xa4, 0xa2};
unsigned char context[] = {0x4c, 0x53, 0xc0, 0xe9, 0x9e, 0x7f, 0x7d,
0x6d, 0x0a, 0x76, 0x7c, 0xc7, 0x25, 0xb5,
0x5b, 0x80, 0x81, 0x91, 0xff};
unsigned char output0[] = {0xd5, 0xad, 0x2d, 0xb1, 0x5a, 0x06, 0xcb, 0x50,
0xf2, 0x59, 0x5a, 0xb2, 0xb2, 0x0d, 0x44, 0x4e};
unsigned char output1[] = {
0xdf, 0x38, 0x45, 0x97, 0x5d, 0x7a, 0x81, 0xb4, 0x94, 0x86, 0xaf, 0x0c,
0xdc, 0x4d, 0xeb, 0x62, 0x31, 0x39, 0x67, 0x8f, 0xff, 0x5d, 0x68, 0x35,
0xdc, 0x89, 0x5f, 0x47, 0xca, 0xe0, 0x2d, 0x3a, 0x10, 0x24, 0xf8, 0x7e,
0x5b, 0x70, 0xe1, 0xa3, 0x4a, 0x47, 0x2f, 0x04, 0xe0, 0x34, 0x75, 0x22};
std::string label_str(label, label + sizeof(label));
std::string context_str(context, context + sizeof(context));
std::string result = DeriveKey(aes_128_key_, label_str, context_str, 128);
std::string output_128(output0, output0 + sizeof(output0));
ASSERT_EQ(result, output_128);
result = DeriveKey(aes_128_key_, label_str, context_str, 384);
std::string output_384(output1, output1 + sizeof(output1));
ASSERT_EQ(result, output_384);
}
TEST_F(CryptoUtilTest, DeriveAes256MasterKeyTest) {
const unsigned char label[] = {
0x16, 0xf1, 0xa4, 0x32, 0x9f, 0x94, 0x55, 0xc1, 0x92, 0xa0, 0x34,
0x8a, 0x8b, 0x6b, 0x77, 0x08, 0xbc, 0x23, 0x70, 0x16, 0xbc, 0xda,
0xfb, 0x60, 0xd1, 0xcf, 0x6a, 0x4d, 0x40, 0xa1, 0xe3, 0xfe, 0xd3,
0xe9, 0xa6, 0x58, 0x4c, 0xd4, 0xad, 0xa4, 0xa2};
const unsigned char context[] = {0x4c, 0x53, 0xc0, 0xe9, 0x9e, 0x7f, 0x7d,
0x6d, 0x0a, 0x76, 0x7c, 0xc7, 0x25, 0xb5,
0x5b, 0x80, 0x81, 0x91, 0xff};
const unsigned char expected_128[] = {0x76, 0x36, 0x33, 0x0e, 0x0b, 0x2c,
0x38, 0xc2, 0x9e, 0x53, 0x23, 0x8d,
0x2e, 0xc6, 0x3a, 0x46};
const std::string label_str(label, label + sizeof(label));
const std::string context_str(context, context + sizeof(context));
std::string result = DeriveKey(aes_256_key_, label_str, context_str, 128);
EXPECT_EQ(std::string(expected_128, expected_128 + sizeof(expected_128)),
result)
<< absl::BytesToHexString(result);
const unsigned char expected_256[] = {
0xfb, 0x8f, 0xdf, 0x0e, 0x22, 0xfe, 0xf7, 0x2b, 0xd1, 0x9a, 0x1d,
0xd2, 0xcb, 0xb0, 0x11, 0x5c, 0x6c, 0xa7, 0xe1, 0x7f, 0x72, 0xce,
0x3a, 0x60, 0x34, 0x89, 0x6d, 0x08, 0xef, 0xde, 0x19, 0x45};
result = DeriveKey(aes_256_key_, label_str, context_str, 256);
EXPECT_EQ(std::string(expected_256, expected_256 + sizeof(expected_256)),
result)
<< absl::BytesToHexString(result);
const unsigned char expected_384[] = {
0x65, 0xbc, 0xe3, 0xf3, 0xfb, 0xfa, 0xce, 0x1d, 0x24, 0x63, 0x9c, 0x8f,
0x48, 0x0e, 0xbd, 0x76, 0xd1, 0x14, 0x0b, 0xb1, 0x3a, 0x3d, 0x6e, 0x30,
0xa9, 0xf4, 0x40, 0x35, 0x0d, 0x6b, 0xc5, 0x1e, 0x9c, 0xa9, 0x5f, 0xf9,
0xde, 0x96, 0xa0, 0xa4, 0x22, 0x62, 0x21, 0xc5, 0xd6, 0xd4, 0xf4, 0x6f};
result = DeriveKey(aes_256_key_, label_str, context_str, 384);
EXPECT_EQ(std::string(expected_384, expected_384 + sizeof(expected_384)),
result)
<< absl::BytesToHexString(result);
}
TEST_F(CryptoUtilTest, DeriveAesInvalidSizeModulus) {
// This is the control case that we correctly derive 128 bits.
EXPECT_NE("", DeriveKey(aes_128_key_, "foo", "bar", 128));
EXPECT_EQ("", DeriveKey(aes_128_key_, "foo", "bar", 127));
}
TEST_F(CryptoUtilTest, DeriveAesMaxBlocks) {
EXPECT_EQ(
255 * AES_BLOCK_SIZE,
DeriveKey(aes_128_key_, "foo", "bar", AES_BLOCK_SIZE * 8 * 255).size());
}
TEST_F(CryptoUtilTest, DeriveAesTooManyBlocks) {
EXPECT_EQ("",
DeriveKey(aes_128_key_, "foo", "bar", AES_BLOCK_SIZE * 8 * 256));
}
TEST_F(CryptoUtilTest, DeriveAes128InvalidKeySize) {
EXPECT_EQ("", DeriveKey(aes_128_key_.substr(0, 15), "foo", "bar", 128));
}
TEST_F(CryptoUtilTest, DeriveAes256InvalidKeySize) {
EXPECT_EQ("", DeriveKey(aes_256_key_.substr(0, 31), "foo", "bar", 128));
}
TEST_F(CryptoUtilTest, DeriveGroupSesionKey) {
unsigned char output[] = {0x92, 0x6c, 0x2f, 0x5, 0xa6, 0x4f, 0xff, 0xb1,
0x86, 0x4a, 0x1a, 0x14, 0x95, 0xeb, 0xb0, 0xf1};
std::string group_session_key = DeriveGroupSessionKey("test_group_id", 128);
EXPECT_EQ(crypto_util::kAes128KeySizeBytes, group_session_key.size());
const std::string output_128(output, output + sizeof(output));
ASSERT_EQ(output_128, group_session_key);
}
TEST_F(CryptoUtilTest, TestCreateAndVerifySignatureHmacSha256) {
unsigned char message_data[] = {
0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53, 0x99, 0x7a, 0x7d,
0x9b, 0x0c, 0xcf, 0xfd, 0xb2, 0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad,
0x23, 0x91, 0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde, 0xf6,
0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f, 0x99, 0x7a, 0x63, 0x47,
0x2e, 0x54, 0x35, 0xb5, 0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2,
0x54, 0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda};
std::string message(message_data, message_data + sizeof(message_data));
std::string signature(CreateSignatureHmacSha256(aes_128_key_, message));
ASSERT_EQ(signature.size(), 32);
ASSERT_TRUE(VerifySignatureHmacSha256(aes_128_key_, signature, message));
}
TEST_F(CryptoUtilTest, TestFailCreateAndVerifyHmacSha256) {
unsigned char message_data[] = {
0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53, 0x99, 0x7a, 0x7d,
0x9b, 0x0c, 0xcf, 0xfd, 0xb2, 0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad,
0x23, 0x91, 0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde, 0xf6,
0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f, 0x99, 0x7a, 0x63, 0x47,
0x2e, 0x54, 0x35, 0xb5, 0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2,
0x54, 0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda};
std::string message(message_data, message_data + sizeof(message_data));
// Test with bogus key;
std::string bogus_key("bogus");
std::string signature(CreateSignatureHmacSha256(bogus_key, message));
// This should still produce an hmac signature.
ASSERT_EQ(signature.size(), 32);
// Create valid signature to compare.
signature = CreateSignatureHmacSha256(aes_128_key_, message);
// Test with bogus key.
ASSERT_FALSE(VerifySignatureHmacSha256(bogus_key, signature, message));
// Test with munged signature.
signature[0] = 0xFF;
ASSERT_FALSE(VerifySignatureHmacSha256(aes_128_key_, signature, message));
// Test with bogus signature.
ASSERT_FALSE(VerifySignatureHmacSha256(aes_128_key_, "bogus", message));
}
TEST_F(CryptoUtilTest, TestCreateAndVerifySignatureHmacSha1) {
unsigned char message_data[] = {
0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53, 0x99, 0x7a, 0x7d,
0x9b, 0x0c, 0xcf, 0xfd, 0xb2, 0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad,
0x23, 0x91, 0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde, 0xf6,
0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f, 0x99, 0x7a, 0x63, 0x47,
0x2e, 0x54, 0x35, 0xb5, 0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2,
0x54, 0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda};
std::string message(message_data, message_data + sizeof(message_data));
std::string signature(CreateSignatureHmacSha1(aes_128_key_, message));
ASSERT_EQ(20, signature.size());
ASSERT_TRUE(VerifySignatureHmacSha1(aes_128_key_, signature, message));
}
TEST_F(CryptoUtilTest, TestFailCreateAndVerifyHmacSha1) {
unsigned char message_data[] = {
0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53, 0x99, 0x7a, 0x7d,
0x9b, 0x0c, 0xcf, 0xfd, 0xb2, 0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad,
0x23, 0x91, 0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde, 0xf6,
0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f, 0x99, 0x7a, 0x63, 0x47,
0x2e, 0x54, 0x35, 0xb5, 0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2,
0x54, 0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda};
std::string message(message_data, message_data + sizeof(message_data));
// Test with bogus key;
std::string bogus_key("bogus");
std::string signature(CreateSignatureHmacSha1(bogus_key, message));
// This should still produce an hmac signature.
ASSERT_EQ(20, signature.size());
// Create valid signature to compare.
signature = CreateSignatureHmacSha1(aes_128_key_, message);
// Test with bogus key.
ASSERT_FALSE(VerifySignatureHmacSha1(bogus_key, signature, message));
// Test with munged signature.
signature[0] = 0xFF;
ASSERT_FALSE(VerifySignatureHmacSha1(aes_128_key_, signature, message));
// Test with bogus signature.
ASSERT_FALSE(VerifySignatureHmacSha1(aes_128_key_, "bogus", message));
}
TEST_F(CryptoUtilTest, DeriveIv) {
// First value in the pair is the key_id, second value is the expected IV.
std::pair<std::string, std::string> id_iv_pairs[] = {
{"1234567890123456", "3278234c7682d1a2e153af4912975f5f"},
{"0987654321098765", "cf09abd30f04b60544910791a6b904cf"}};
for (const auto& id_iv_pair : id_iv_pairs) {
SCOPED_TRACE(absl::StrCat("test case:", id_iv_pair.first));
EXPECT_EQ(id_iv_pair.second,
absl::BytesToHexString(DeriveIv(id_iv_pair.first)));
// Repeat same call to verify derivied result is repeatable.
EXPECT_EQ(id_iv_pair.second,
absl::BytesToHexString(DeriveIv(id_iv_pair.first)));
}
}
TEST_F(CryptoUtilTest, DeriveKeyId) {
// First value in the pair is the context, second value is the expected id.
std::pair<std::string, std::string> context_id_pairs[] = {
{"1234567890123456", "a3c4a8c0d0e24e96f38f492254186a9d"},
{"0987654321098765", "084fc6bece9688ccce6b1672d9b47e22"}};
for (const auto& context_id_pair : context_id_pairs) {
SCOPED_TRACE(absl::StrCat("test case:", context_id_pair.first));
EXPECT_EQ(context_id_pair.second,
absl::BytesToHexString(DeriveKeyId(context_id_pair.first)));
// Repeat same call to verify derivied result is repeatable.
EXPECT_EQ(context_id_pair.second,
absl::BytesToHexString(DeriveKeyId(context_id_pair.first)));
}
}
TEST_F(CryptoUtilTest, Verify4CCEncryptionIDFromBadString) {
uint32_t cc_code;
ASSERT_FALSE(FourCCEncryptionSchemeIDFromString("garbage", &cc_code));
ASSERT_FALSE(FourCCEncryptionSchemeIDFromString("junk", &cc_code));
ASSERT_FALSE(FourCCEncryptionSchemeIDFromString("cencc", &cc_code));
}
TEST_F(CryptoUtilTest, Verify4CCEncryptionIDFromString) {
uint32_t cc_code = 0;
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCENCStr, &cc_code));
ASSERT_EQ(kCENCSchemeID, cc_code);
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCBC1Str, &cc_code));
ASSERT_EQ(kCBC1SchemeID, cc_code);
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCENSStr, &cc_code));
ASSERT_EQ(kCENSSchemeID, cc_code);
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCBCSStr, &cc_code));
ASSERT_EQ(kCBCSSchemeID, cc_code);
}
} // namespace crypto_util
} // namespace widevine

View File

@@ -0,0 +1,81 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// RAII wrapper classes for cleaning up various OpenSSL dynamically allocated
// structures.
#ifndef WHITEBOX_CRYPTO_UTILS_OPENSSL_UTIL_H_
#define WHITEBOX_CRYPTO_UTILS_OPENSSL_UTIL_H_
#include "third_party/boringssl/src/include/openssl/bio.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/pkcs7.h"
#include "third_party/boringssl/src/include/openssl/rsa.h"
#include "third_party/boringssl/src/include/openssl/x509v3.h"
template <typename T, void (*func)(T*)>
struct OpenSSLDeleter {
void operator()(T* obj) { func(obj); }
};
template <typename StackType, typename T, void (*func)(T*)>
struct OpenSSLStackDeleter {
void operator()(StackType* obj) {
sk_pop_free(reinterpret_cast<_STACK*>(obj),
reinterpret_cast<void (*)(void*)>(func));
}
};
template <typename StackType>
struct OpenSSLStackOnlyDeleter {
void operator()(StackType* obj) { sk_free(reinterpret_cast<_STACK*>(obj)); }
};
template <typename T, void (*func)(T*)>
using ScopedOpenSSLType = std::unique_ptr<T, OpenSSLDeleter<T, func>>;
template <typename StackType, typename T, void (*func)(T*)>
using ScopedOpenSSLStack =
std::unique_ptr<StackType, OpenSSLStackDeleter<StackType, T, func>>;
template <typename StackType>
using ScopedOpenSSLStackOnly =
std::unique_ptr<StackType, OpenSSLStackOnlyDeleter<StackType>>;
using ScopedBIGNUM = ScopedOpenSSLType<BIGNUM, BN_free>;
using ScopedBIO = ScopedOpenSSLType<BIO, BIO_vfree>;
typedef ScopedOpenSSLType<EC_KEY, EC_KEY_free> ScopedECKEY;
using ScopedPKCS7 = ScopedOpenSSLType<PKCS7, PKCS7_free>;
using ScopedPKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
using ScopedX509 = ScopedOpenSSLType<X509, X509_free>;
using ScopedX509Extension =
ScopedOpenSSLType<X509_EXTENSION, X509_EXTENSION_free>;
using ScopedX509Name = ScopedOpenSSLType<X509_NAME, X509_NAME_free>;
using ScopedX509NameEntry =
ScopedOpenSSLType<X509_NAME_ENTRY, X509_NAME_ENTRY_free>;
using ScopedX509Store = ScopedOpenSSLType<X509_STORE, X509_STORE_free>;
using ScopedX509StoreCtx =
ScopedOpenSSLType<X509_STORE_CTX, X509_STORE_CTX_free>;
using ScopedX509Req = ScopedOpenSSLType<X509_REQ, X509_REQ_free>;
using ScopedAsn1UtcTime = ScopedOpenSSLType<ASN1_UTCTIME, ASN1_UTCTIME_free>;
using ScopedAsn1Time = ScopedOpenSSLType<ASN1_TIME, ASN1_TIME_free>;
using ScopedAsn1Utc8String =
ScopedOpenSSLType<ASN1_UTF8STRING, ASN1_UTF8STRING_free>;
using ScopedAsn1Integer = ScopedOpenSSLType<ASN1_INTEGER, ASN1_INTEGER_free>;
using ScopedAsn1Object = ScopedOpenSSLType<ASN1_OBJECT, ASN1_OBJECT_free>;
using ScopedAsn1OctetString =
ScopedOpenSSLType<ASN1_OCTET_STRING, ASN1_OCTET_STRING_free>;
// XxxStack deallocates the stack and its members while XxxStackOnly deallocates
// the stack only.
using ScopedX509Stack = ScopedOpenSSLStack<STACK_OF(X509), X509, X509_free>;
using ScopedX509StackOnly = ScopedOpenSSLStackOnly<STACK_OF(X509)>;
using ScopedX509InfoStack =
ScopedOpenSSLStack<STACK_OF(X509_INFO), X509_INFO, X509_INFO_free>;
using ScopedX509InfoStackOnly = ScopedOpenSSLStackOnly<STACK_OF(X509_INFO)>;
#endif // WHITEBOX_CRYPTO_UTILS_OPENSSL_UTIL_H_

View File

@@ -0,0 +1,86 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2019 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Shared private key utilities between RSA and EC.
#ifndef WHITEBOX_CRYPTO_UTILS_PRIVATE_KEY_UTIL_H_
#define WHITEBOX_CRYPTO_UTILS_PRIVATE_KEY_UTIL_H_
#include <string>
#include "base/logging.h"
#include "third_party/boringssl/src/include/openssl/bio.h"
namespace widevine {
namespace private_key_util {
template <class Key>
bool SerializeKey(const Key* key,
int (*serialization_func)(BIO*, Key*),
std::string* serialized_key) {
if (key == nullptr) {
LOG(ERROR) << "Key is nullptr.";
return false;
}
if (serialized_key == nullptr) {
LOG(ERROR) << "Pointer to hold serialized key is nullptr.";
return false;
}
BIO* bio = BIO_new(BIO_s_mem());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new returned nullptr";
return false;
}
bool success = false;
if (serialization_func(bio, const_cast<Key*>(key)) != 0) {
int serialized_size = BIO_pending(bio);
serialized_key->assign(serialized_size, 0);
if (BIO_read(bio, &(*serialized_key)[0], serialized_size) ==
serialized_size) {
success = true;
} else {
LOG(ERROR) << "BIO_read failure";
}
} else {
LOG(ERROR) << "Key serialization failure";
}
BIO_free(bio);
return success;
}
template <class Key>
bool DeserializeKey(const std::string& serialized_key,
Key* (*deserialization_func)(BIO*, Key**),
Key** key) {
if (serialized_key.empty()) {
LOG(ERROR) << "Serialized key is empty.";
return false;
}
if (key == nullptr) {
LOG(ERROR) << "Pointer to hold new key is nullptr.";
return false;
}
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_key.data()),
serialized_key.size());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new_mem_buf returned nullptr";
return false;
}
*key = deserialization_func(bio, nullptr);
BIO_free(bio);
if (*key == nullptr) {
LOG(ERROR) << "Key deserialization failure";
}
return *key != nullptr;
}
} // namespace private_key_util
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_PRIVATE_KEY_UTIL_H_

View File

@@ -0,0 +1,27 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "crypto_utils/random_util.h"
#include "base/logging.h"
#include "third_party/boringssl/src/include/openssl/rand.h"
namespace widevine {
bool RandomBytes(size_t num_bytes, std::string* output) {
DCHECK(output);
output->resize(num_bytes);
return RAND_bytes(reinterpret_cast<uint8_t*>(&(*output)[0]), num_bytes);
}
std::string Random16Bytes() {
std::string output;
CHECK(RandomBytes(16u, &output));
return output;
}
} // namespace widevine

View File

@@ -0,0 +1,25 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef WHITEBOX_CRYPTO_UTILS_RANDOM_UTIL_H_
#define WHITEBOX_CRYPTO_UTILS_RANDOM_UTIL_H_
#include <string>
namespace widevine {
// Generates a random string.
// Returns true on success, false otherwise.
bool RandomBytes(size_t num_bytes, std::string* output);
// Returns a 16-byte std::string suitable for use as an AES key
std::string Random16Bytes();
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_RANDOM_UTIL_H_

View File

@@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "crypto_utils/random_util.h"
#include "testing/include/gtest/gtest.h"
namespace widevine {
TEST(RandomUtilTest, Test) {
std::string output;
ASSERT_TRUE(RandomBytes(16u, &output));
EXPECT_EQ(16u, output.size());
std::string output2;
ASSERT_TRUE(RandomBytes(16u, &output2));
EXPECT_EQ(16u, output2.size());
EXPECT_NE(output, output2);
ASSERT_TRUE(RandomBytes(10u, &output2));
EXPECT_EQ(10u, output2.size());
}
} // namespace widevine

335
crypto_utils/rsa_key.cc Normal file
View File

@@ -0,0 +1,335 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Definition of classes representing RSA private and public keys used
// for message signing, signature verification, encryption and decryption.
//
// RSA signature details:
// Algorithm: RSASSA-PSS
// Hash algorithm: SHA1
// Mask generation function: mgf1SHA1
// Salt length: 20 bytes
// Trailer field: 0xbc
//
// RSA encryption details:
// Algorithm: RSA-OAEP
// Mask generation function: mgf1SHA1
// Label (encoding paramter): empty std::string
#include "crypto_utils/rsa_key.h"
#include "base/logging.h"
#include "third_party/boringssl/src/include/openssl/bn.h"
#include "third_party/boringssl/src/include/openssl/err.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/rsa.h"
#include "third_party/boringssl/src/include/openssl/sha.h"
#include "crypto_utils/rsa_util.h"
#include "crypto_utils/sha_util.h"
static const int kPssSaltLength = 20;
namespace {
// Check if two RSA keys match. If matches, they are either a public-private key
// pair or the same public key or the same private key.
bool RsaKeyMatch(const RSA* key1, const RSA* key2) {
if (!key1 || !key2)
return false;
return BN_cmp(key1->n, key2->n) == 0;
}
std::string OpenSSLErrorString(uint32_t error) {
char buf[ERR_ERROR_STRING_BUF_LEN];
ERR_error_string_n(error, buf, sizeof(buf));
return buf;
}
} // namespace
namespace widevine {
RsaPrivateKey::RsaPrivateKey(RSA* key) : key_(key) {
CHECK(key_ != nullptr);
}
RsaPrivateKey::RsaPrivateKey(const RsaPrivateKey& rsa_key)
: key_(RSAPrivateKey_dup(rsa_key.key_)) {
CHECK(key_ != nullptr);
}
RsaPrivateKey::~RsaPrivateKey() {
RSA_free(key_);
}
RsaPrivateKey* RsaPrivateKey::Create(const std::string& serialized_key) {
RSA* key;
if (!rsa_util::DeserializeRsaPrivateKey(serialized_key, &key))
return nullptr;
if (RSA_check_key(key) != 1) {
LOG(ERROR) << "Invalid private RSA key: "
<< OpenSSLErrorString(ERR_get_error());
RSA_free(key);
}
return new RsaPrivateKey(key);
}
bool RsaPrivateKey::Decrypt(const std::string& encrypted_message,
std::string* decrypted_message) const {
DCHECK(decrypted_message);
size_t rsa_size = RSA_size(key_);
if (encrypted_message.size() != rsa_size) {
LOG(ERROR) << "Encrypted RSA message has the wrong size (expected "
<< rsa_size << ", actual " << encrypted_message.size() << ")";
return false;
}
decrypted_message->assign(rsa_size, 0);
int decrypted_size = RSA_private_decrypt(
rsa_size,
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(encrypted_message.data())),
reinterpret_cast<unsigned char*>(&(*decrypted_message)[0]), key_,
RSA_PKCS1_OAEP_PADDING);
if (decrypted_size == -1) {
LOG(ERROR) << "RSA private decrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
decrypted_message->resize(decrypted_size);
return true;
}
bool RsaPrivateKey::GenerateSignature(const std::string& message,
std::string* signature) const {
DCHECK(signature);
if (message.empty()) {
LOG(ERROR) << "Message to be signed is empty";
return false;
}
// Hash the message using SHA1.
std::string message_digest = Sha1_Hash(message);
// Add PSS padding.
size_t rsa_size = RSA_size(key_);
std::string padded_digest(rsa_size, 0);
if (!RSA_padding_add_PKCS1_PSS_mgf1(
key_, reinterpret_cast<unsigned char*>(&padded_digest[0]),
reinterpret_cast<unsigned char*>(&message_digest[0]), EVP_sha1(),
EVP_sha1(), kPssSaltLength)) {
LOG(ERROR) << "RSA padding failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
// Encrypt PSS padded digest.
signature->assign(rsa_size, 0);
if (RSA_private_encrypt(padded_digest.size(),
reinterpret_cast<unsigned char*>(&padded_digest[0]),
reinterpret_cast<unsigned char*>(&(*signature)[0]),
key_, RSA_NO_PADDING) !=
static_cast<int>(signature->size())) {
LOG(ERROR) << "RSA private encrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
return true;
}
bool RsaPrivateKey::GenerateSignatureSha256Pkcs7(const std::string& message,
std::string* signature) const {
DCHECK(signature);
if (message.empty()) {
LOG(ERROR) << "Empty signature verification message";
return false;
}
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
digest);
unsigned int sig_len = RSA_size(key_);
signature->resize(sig_len);
return RSA_sign(NID_sha256, digest, sizeof(digest),
reinterpret_cast<unsigned char*>(&(*signature)[0]), &sig_len,
key_) == 1;
}
bool RsaPrivateKey::MatchesPrivateKey(const RsaPrivateKey& private_key) const {
return RsaKeyMatch(key(), private_key.key());
}
bool RsaPrivateKey::MatchesPublicKey(const RsaPublicKey& public_key) const {
return RsaKeyMatch(key(), public_key.key());
}
uint32_t RsaPrivateKey::KeySize() const {
return RSA_size(key_);
}
RsaPublicKey::RsaPublicKey(RSA* key) : key_(key) {
CHECK(key_ != nullptr);
}
RsaPublicKey::RsaPublicKey(const RsaPublicKey& rsa_key)
: key_(RSAPublicKey_dup(rsa_key.key_)) {
CHECK(key_ != nullptr);
}
RsaPublicKey::RsaPublicKey(const RsaPrivateKey& rsa_key)
: key_(RSAPublicKey_dup(rsa_key.key_)) {
CHECK(key_ != nullptr);
}
RsaPublicKey::~RsaPublicKey() {
RSA_free(key_);
}
RsaPublicKey* RsaPublicKey::Create(const std::string& serialized_key) {
RSA* key;
if (!rsa_util::DeserializeRsaPublicKey(serialized_key, &key))
return nullptr;
if (RSA_size(key) == 0) {
LOG(ERROR) << "Invalid public RSA key: "
<< OpenSSLErrorString(ERR_get_error());
RSA_free(key);
}
return new RsaPublicKey(key);
}
bool RsaPublicKey::Encrypt(const std::string& clear_message,
std::string* encrypted_message) const {
DCHECK(encrypted_message);
if (clear_message.empty()) {
LOG(ERROR) << "Message to be encrypted is empty";
return false;
}
size_t rsa_size = RSA_size(key_);
encrypted_message->assign(rsa_size, 0);
if (RSA_public_encrypt(
clear_message.size(),
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(clear_message.data())),
reinterpret_cast<unsigned char*>(&(*encrypted_message)[0]), key_,
RSA_PKCS1_OAEP_PADDING) != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA public encrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
return true;
}
bool RsaPublicKey::VerifySignature(const std::string& message,
const std::string& signature) const {
if (message.empty()) {
LOG(ERROR) << "Signed message is empty";
return false;
}
size_t rsa_size = RSA_size(key_);
if (signature.size() != rsa_size) {
LOG(ERROR) << "Message signature is of the wrong size (expected "
<< rsa_size << ", actual " << signature.size() << ")";
return false;
}
// Decrypt the signature.
std::string padded_digest(signature.size(), 0);
if (RSA_public_decrypt(
signature.size(),
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(signature.data())),
reinterpret_cast<unsigned char*>(&padded_digest[0]), key_,
RSA_NO_PADDING) != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA public decrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
// Hash the message using SHA1.
std::string message_digest = Sha1_Hash(message);
// Verify PSS padding.
if (RSA_verify_PKCS1_PSS_mgf1(
key_, reinterpret_cast<unsigned char*>(&message_digest[0]),
EVP_sha1(), EVP_sha1(),
reinterpret_cast<unsigned char*>(&padded_digest[0]),
kPssSaltLength) == 0) {
LOG(ERROR) << "RSA Verify PSS padding failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
return true;
}
bool RsaPublicKey::VerifySignatureSha256Pkcs7(
const std::string& message,
const std::string& signature) const {
if (message.empty()) {
LOG(ERROR) << "Empty signature verification message";
return false;
}
if (signature.empty()) {
LOG(ERROR) << "Empty signature";
return false;
}
if (signature.size() != RSA_size(key_)) {
LOG(ERROR) << "RSA signature has the wrong size";
return false;
}
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
digest);
return RSA_verify(NID_sha256, digest, sizeof(digest),
reinterpret_cast<const unsigned char*>(signature.data()),
signature.size(), key_) == 1;
}
bool RsaPublicKey::MatchesPrivateKey(const RsaPrivateKey& private_key) const {
return RsaKeyMatch(key(), private_key.key());
}
bool RsaPublicKey::MatchesPublicKey(const RsaPublicKey& public_key) const {
return RsaKeyMatch(key(), public_key.key());
}
uint32_t RsaPublicKey::KeySize() const {
return RSA_size(key_);
}
RsaKeyFactory::RsaKeyFactory() {}
RsaKeyFactory::~RsaKeyFactory() {}
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs1PrivateKey(
const std::string& private_key) const {
return std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key));
}
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs8PrivateKey(
const std::string& private_key,
const std::string& private_key_passphrase) const {
std::string pkcs1_key;
const bool result =
private_key_passphrase.empty()
? rsa_util::PrivateKeyInfoToRsaPrivateKey(private_key, &pkcs1_key)
: rsa_util::EncryptedPrivateKeyInfoToRsaPrivateKey(
private_key, private_key_passphrase, &pkcs1_key);
if (!result) {
LOG(WARNING) << "Failed to get pkcs1_key.";
return std::unique_ptr<RsaPrivateKey>();
}
return std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(pkcs1_key));
}
std::unique_ptr<RsaPublicKey> RsaKeyFactory::CreateFromPkcs1PublicKey(
const std::string& public_key) const {
return std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key));
}
} // namespace widevine

163
crypto_utils/rsa_key.h Normal file
View File

@@ -0,0 +1,163 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Declaration of classes representing RSA private and public keys used
// for message signing, signature verification, encryption and decryption.
#ifndef WHITEBOX_CRYPTO_UTILS_RSA_KEY_H_
#define WHITEBOX_CRYPTO_UTILS_RSA_KEY_H_
#include <cstdint>
#include <memory>
#include <string>
#include "third_party/boringssl/src/include/openssl/rsa.h"
namespace widevine {
class RsaPublicKey;
class RsaPrivateKey {
public:
explicit RsaPrivateKey(RSA* key);
RsaPrivateKey(const RsaPrivateKey&);
virtual ~RsaPrivateKey();
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
// Returns NULL on failure.
static RsaPrivateKey* Create(const std::string& serialized_key);
// Decrypt a message using RSA-OAEP. Caller retains ownership of all
// parameters. Returns true if successful, false otherwise.
virtual bool Decrypt(const std::string& encrypted_message,
std::string* decrypted_message) const;
// Generate RSSASSA-PSS signature. Caller retains ownership of all parameters.
// Returns true if successful, false otherwise.
virtual bool GenerateSignature(const std::string& message,
std::string* signature) const;
// Generate SHA256 digest, PKCS#7 padded signature. Caller retains ownership
// of all parameters. Returns true if successful, false otherwise.
virtual bool GenerateSignatureSha256Pkcs7(const std::string& message,
std::string* signature) const;
// Return true if the underlying key matches with |private_key|.
virtual bool MatchesPrivateKey(const RsaPrivateKey& private_key) const;
// Return true if the underlying key is a public-private key pair with
// |public_key|.
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
// Returns the RSA key size (modulus) in bytes.
virtual uint32_t KeySize() const;
private:
friend class RsaPublicKey;
friend class X509CertificateBuilder; // TODO(user): Get rid of this.
const RSA* key() const { return key_; }
RSA* key_;
// SWIG appears to think this declaration is a syntax error. Excluding it for
// python SWIG wrapping.
#ifndef SWIG
// Disallow assignment operator.
RsaPrivateKey& operator=(const RsaPrivateKey&) = delete;
#endif // SWIG
};
class RsaPublicKey {
public:
explicit RsaPublicKey(RSA* key);
// Copy constructor.
RsaPublicKey(const RsaPublicKey& rsa_key);
// Construct RsaPublicKey object from RsaPrivateKey.
explicit RsaPublicKey(const RsaPrivateKey& rsa_key);
virtual ~RsaPublicKey();
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
// Returns NULL on failure.
static RsaPublicKey* Create(const std::string& serialized_key);
// Encrypt a message using RSA-OAEP. Caller retains ownership of all
// parameters. Returns true if successful, false otherwise.
virtual bool Encrypt(const std::string& clear_message,
std::string* encrypted_message) const;
// Verify RSSASSA-PSS signature. Caller retains ownership of all parameters.
// Returns true if validation succeeds, false otherwise.
virtual bool VerifySignature(const std::string& message,
const std::string& signature) const;
// Verify a signature. This method takes two parameters: |message| which is a
// std::string containing the data which was signed, and |signature| which is
// a std::string containing the message SHA256 digest signature with PKCS#7
// padding. Returns true if verification succeeds, false otherwise.
virtual bool VerifySignatureSha256Pkcs7(const std::string& message,
const std::string& signature) const;
// Return true if the underlying key is a public-private key pair with
// |private_key|.
virtual bool MatchesPrivateKey(const RsaPrivateKey& private_key) const;
// Return true if the underlying key matches with |public_key|.
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
// Returns the RSA key size (modulus) in bytes.
virtual uint32_t KeySize() const;
private:
friend class RsaPrivateKey;
friend class X509CertificateBuilder; // TODO(user): Get rid of this.
const RSA* key() const { return key_; }
RSA* key_;
// SWIG appears to think this declaration is a syntax error. Excluding it for
// python SWIG wrapping.
#ifndef SWIG
// Disallow assignment operator.
RsaPublicKey& operator=(const RsaPublicKey&) = delete;
#endif // SWIG
};
class RsaKeyFactory {
public:
RsaKeyFactory();
RsaKeyFactory(const RsaKeyFactory&) = delete;
RsaKeyFactory& operator=(const RsaKeyFactory&) = delete;
virtual ~RsaKeyFactory();
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs1PrivateKey(
const std::string& private_key) const;
// Create a PKCS#1 RsaPrivateKey object using an PKCS#8 PrivateKeyInfo or
// EncryptedPrivateKeyInfo (if |private_key_passprhase| is not empty).
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs8PrivateKey(
const std::string& private_key,
const std::string& private_key_passphrase) const;
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
virtual std::unique_ptr<RsaPublicKey> CreateFromPkcs1PublicKey(
const std::string& public_key) const;
};
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_RSA_KEY_H_

View File

@@ -0,0 +1,268 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit test for rsa_key RSA encryption and signing.
#include "crypto_utils/rsa_key.h"
#include <memory>
#include "testing/include/gtest/gtest.h"
#include "crypto_utils/rsa_test_keys.h"
#include "crypto_utils/rsa_util.h"
namespace widevine {
static const char kTestMessage[] =
"A fool thinks himself to be wise, but a wise man knows himself to be a "
"fool.";
class RsaKeyTest : public ::testing::Test {
protected:
void TestEncryption(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key);
void TestSigning(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key);
void TestSigningSha256Pkcs7(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key);
RsaTestKeys test_keys_;
RsaKeyFactory factory_;
};
TEST_F(RsaKeyTest, CopyConstructor) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits()));
std::unique_ptr<RsaPrivateKey> private_key_copy(
new RsaPrivateKey(*private_key));
std::unique_ptr<RsaPublicKey> public_key_copy(new RsaPublicKey(*public_key));
EXPECT_TRUE(public_key_copy->MatchesPublicKey(*public_key));
EXPECT_TRUE(public_key_copy->MatchesPrivateKey(*private_key));
EXPECT_TRUE(private_key_copy->MatchesPublicKey(*public_key));
EXPECT_TRUE(private_key_copy->MatchesPrivateKey(*private_key));
}
void RsaKeyTest::TestEncryption(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key) {
ASSERT_TRUE(private_key);
ASSERT_TRUE(public_key);
std::string encrypted_message;
EXPECT_TRUE(public_key->Encrypt(kTestMessage, &encrypted_message));
std::string decrypted_message;
EXPECT_TRUE(private_key->Decrypt(encrypted_message, &decrypted_message));
EXPECT_EQ(kTestMessage, decrypted_message);
// Add a byte to the encrypted message.
std::string bad_enc_message(encrypted_message);
bad_enc_message += '\0';
EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message));
// Remove a byte from the encrypted message.
bad_enc_message = encrypted_message.substr(0, encrypted_message.size() - 1);
EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message));
// Change a byte in the encrypted message.
bad_enc_message = encrypted_message;
bad_enc_message[128] ^= 0x55;
EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message));
}
void RsaKeyTest::TestSigning(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key) {
ASSERT_TRUE(private_key);
ASSERT_TRUE(public_key);
std::string signature;
EXPECT_TRUE(private_key->GenerateSignature(kTestMessage, &signature));
EXPECT_TRUE(public_key->VerifySignature(kTestMessage, signature));
// Add a byte to the signature.
std::string bad_signature(signature);
bad_signature += '\0';
EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature));
// Remove a byte from the signature.
bad_signature = signature.substr(0, signature.size() - 1);
EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature));
// Change a byte in the signature.
bad_signature = signature;
bad_signature[32] ^= 0x55;
EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature));
}
void RsaKeyTest::TestSigningSha256Pkcs7(
std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key) {
ASSERT_TRUE(private_key);
ASSERT_TRUE(public_key);
std::string signature;
EXPECT_TRUE(
private_key->GenerateSignatureSha256Pkcs7(kTestMessage, &signature));
EXPECT_TRUE(public_key->VerifySignatureSha256Pkcs7(kTestMessage, signature));
// Add a byte to the signature.
std::string bad_signature(signature);
bad_signature += '\0';
EXPECT_FALSE(
public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature));
// Remove a byte from the signature.
bad_signature = signature.substr(0, signature.size() - 1);
EXPECT_FALSE(
public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature));
// Change a byte in the signature.
bad_signature = signature;
bad_signature[32] ^= 0x55;
EXPECT_FALSE(
public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature));
}
TEST_F(RsaKeyTest, BadKey) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create("bad_private_key"));
EXPECT_TRUE(!private_key);
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create("bad_public_key"));
EXPECT_TRUE(!public_key);
}
TEST_F(RsaKeyTest, EncryptAndDecrypt_3072) {
const std::string& private_key = test_keys_.private_test_key_1_3072_bits();
const std::string& public_key = test_keys_.public_test_key_1_3072_bits();
TestEncryption(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
TestEncryption(factory_.CreateFromPkcs1PrivateKey(private_key),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, EncryptAndDecrypt_2048) {
const std::string& private_key = test_keys_.private_test_key_2_2048_bits();
const std::string& public_key = test_keys_.public_test_key_2_2048_bits();
TestEncryption(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
std::string pkcs8_key;
std::string passphrase("passphrase");
ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
private_key, passphrase, &pkcs8_key));
TestEncryption(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase),
factory_.CreateFromPkcs1PublicKey(public_key));
ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key));
TestEncryption(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, RsaPublicKeyFromPrivateKey) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
ASSERT_TRUE(private_key);
std::unique_ptr<RsaPublicKey> public_key(new RsaPublicKey(*private_key));
ASSERT_TRUE(public_key);
EXPECT_TRUE(private_key->MatchesPublicKey(*public_key));
EXPECT_TRUE(public_key->MatchesPrivateKey(*private_key));
TestEncryption(std::move(private_key), std::move(public_key));
}
TEST_F(RsaKeyTest, SignAndVerify_3072) {
const std::string& private_key = test_keys_.private_test_key_1_3072_bits();
const std::string& public_key = test_keys_.public_test_key_1_3072_bits();
TestSigning(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
TestSigning(factory_.CreateFromPkcs1PrivateKey(private_key),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerify_2048) {
const std::string& private_key = test_keys_.private_test_key_2_2048_bits();
const std::string& public_key = test_keys_.public_test_key_2_2048_bits();
TestSigning(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
std::string pkcs8_key;
std::string passphrase("passphrase");
ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
private_key, passphrase, &pkcs8_key));
TestSigning(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase),
factory_.CreateFromPkcs1PublicKey(public_key));
ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key));
TestSigning(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_3072) {
const std::string& private_key = test_keys_.private_test_key_1_3072_bits();
const std::string& public_key = test_keys_.public_test_key_1_3072_bits();
TestSigningSha256Pkcs7(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
TestSigningSha256Pkcs7(factory_.CreateFromPkcs1PrivateKey(private_key),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_2048) {
const std::string& private_key = test_keys_.private_test_key_2_2048_bits();
const std::string& public_key = test_keys_.public_test_key_2_2048_bits();
TestSigningSha256Pkcs7(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
std::string pkcs8_key;
std::string passphrase("passphrase");
ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
private_key, passphrase, &pkcs8_key));
TestSigningSha256Pkcs7(
factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase),
factory_.CreateFromPkcs1PublicKey(public_key));
ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key));
TestSigningSha256Pkcs7(
factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, KeySize) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits()));
EXPECT_EQ(256, private_key->KeySize());
EXPECT_EQ(256, public_key->KeySize());
}
TEST_F(RsaKeyTest, RsaKeyMatch) {
std::unique_ptr<RsaPrivateKey> private_key2(
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
std::unique_ptr<RsaPrivateKey> private_key3(
RsaPrivateKey::Create(test_keys_.private_test_key_3_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key2(
RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key3(
RsaPublicKey::Create(test_keys_.public_test_key_3_2048_bits()));
EXPECT_TRUE(public_key2->MatchesPublicKey(*public_key2));
EXPECT_FALSE(public_key2->MatchesPublicKey(*public_key3));
EXPECT_TRUE(public_key2->MatchesPrivateKey(*private_key2));
EXPECT_FALSE(public_key2->MatchesPrivateKey(*private_key3));
EXPECT_TRUE(private_key2->MatchesPublicKey(*public_key2));
EXPECT_FALSE(private_key2->MatchesPublicKey(*public_key3));
EXPECT_TRUE(private_key2->MatchesPrivateKey(*private_key2));
EXPECT_FALSE(private_key2->MatchesPrivateKey(*private_key3));
}
} // namespace widevine

View File

@@ -0,0 +1,786 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA keys generated using fake_prng for purposes of testing.
#include "crypto_utils/rsa_test_keys.h"
namespace widevine {
static const unsigned char kTestRsaPrivateKey1_3072[] = {
0x30, 0x82, 0x06, 0xe3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x81, 0x00,
0xa5, 0x62, 0x07, 0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0,
0x78, 0x76, 0xbe, 0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3,
0x0f, 0xe9, 0x61, 0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2,
0xca, 0xe4, 0xdd, 0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55,
0x1b, 0x83, 0xbe, 0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29,
0x46, 0xc2, 0x65, 0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17,
0x01, 0xb5, 0x11, 0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37,
0x5c, 0xb4, 0x7a, 0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1,
0x14, 0xf1, 0x22, 0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86,
0xcd, 0xa0, 0x0a, 0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3,
0xb6, 0x0e, 0x85, 0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4,
0xde, 0xf2, 0x59, 0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb,
0x31, 0xa0, 0xee, 0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee,
0x3a, 0xae, 0xb2, 0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb,
0x90, 0x97, 0x2c, 0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca,
0x49, 0x94, 0x53, 0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0,
0x5f, 0x07, 0x53, 0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6,
0xda, 0xea, 0x1e, 0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb,
0x17, 0xe8, 0xc9, 0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab,
0x30, 0xb7, 0xf5, 0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26,
0xaf, 0x39, 0xf3, 0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10,
0x16, 0x9c, 0xee, 0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b,
0x42, 0x72, 0x85, 0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21,
0xf9, 0xa6, 0x82, 0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64,
0xe4, 0x3a, 0x3b, 0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05,
0x4a, 0xe9, 0x4c, 0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1,
0x72, 0x71, 0x04, 0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab,
0xde, 0x8f, 0xe1, 0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50,
0x04, 0xb5, 0xd7, 0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85,
0x1b, 0x38, 0xff, 0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0,
0x33, 0x61, 0x53, 0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b,
0x67, 0xd5, 0xf0, 0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87,
0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x80, 0x5a, 0x09, 0x3f,
0x9e, 0x2e, 0x4d, 0x26, 0x50, 0x7b, 0x70, 0x21, 0xb0, 0x0c, 0x25, 0x21,
0x1f, 0xd9, 0x89, 0x5a, 0xca, 0x35, 0x23, 0x0b, 0x58, 0xa9, 0x7d, 0xf6,
0x19, 0xc4, 0x29, 0x87, 0xc7, 0xd4, 0x94, 0x85, 0xb4, 0x2c, 0xaf, 0x62,
0xb1, 0xe8, 0x62, 0x5b, 0xda, 0xdb, 0x70, 0x40, 0x37, 0xb1, 0x4e, 0x0c,
0xc8, 0x62, 0xee, 0xa2, 0xfc, 0x3c, 0xd2, 0x39, 0x90, 0x15, 0x2c, 0xba,
0x20, 0x50, 0xb7, 0x82, 0x2a, 0xa0, 0x76, 0x83, 0x20, 0x7f, 0x56, 0x73,
0x43, 0x8a, 0x9b, 0xa7, 0x6c, 0x63, 0xb6, 0xad, 0x56, 0xb2, 0x8a, 0xb2,
0xbc, 0x8f, 0xe2, 0xef, 0x83, 0x9d, 0x98, 0x0b, 0xc7, 0x62, 0x0e, 0x51,
0x6e, 0x57, 0x1d, 0x1b, 0x0e, 0x3a, 0xea, 0x3b, 0x76, 0x63, 0x35, 0xd0,
0xd1, 0xcf, 0xbe, 0xad, 0xbb, 0x1d, 0xde, 0x0f, 0x05, 0x48, 0x55, 0x29,
0xc1, 0xbc, 0x21, 0xc7, 0x87, 0xf2, 0x75, 0x12, 0x7d, 0x92, 0x9e, 0xbf,
0xad, 0x04, 0x68, 0xc4, 0xc9, 0x9d, 0x35, 0xd6, 0xa8, 0x62, 0xc1, 0x69,
0x6a, 0xb6, 0x41, 0xb7, 0x37, 0x66, 0xdf, 0xb2, 0xb9, 0x8c, 0x8b, 0x15,
0x08, 0x4c, 0x3d, 0xf1, 0xed, 0x82, 0x0f, 0xe3, 0xd5, 0xff, 0x46, 0xbd,
0xf7, 0x85, 0x43, 0xc0, 0x8b, 0xba, 0x47, 0xf1, 0x41, 0x57, 0xc3, 0x7f,
0x8b, 0x0d, 0x48, 0xea, 0xc2, 0xed, 0xc0, 0x69, 0x84, 0xb6, 0x32, 0x08,
0x49, 0x74, 0x14, 0x84, 0xa4, 0x1b, 0x48, 0x5b, 0xec, 0xd3, 0x0b, 0x12,
0x2b, 0x4c, 0x9e, 0x5c, 0x01, 0x60, 0xad, 0xef, 0xcb, 0x2b, 0x56, 0x84,
0x07, 0xfa, 0x62, 0xc6, 0x08, 0x92, 0x98, 0x70, 0xc9, 0x5b, 0x18, 0xc8,
0xfa, 0x27, 0x0c, 0xe2, 0xbd, 0xfb, 0x3e, 0x43, 0xa5, 0xb7, 0x06, 0x2c,
0x4e, 0xf1, 0x07, 0x5d, 0x8d, 0xdd, 0x53, 0xc5, 0x8c, 0x4a, 0xf2, 0x2f,
0x8e, 0x80, 0x96, 0x16, 0xc0, 0xfc, 0xf9, 0x20, 0x4f, 0x35, 0xc7, 0x53,
0x8b, 0x2d, 0x37, 0x43, 0x93, 0x3d, 0x74, 0x3f, 0x63, 0xf7, 0x0b, 0xbd,
0x46, 0xe4, 0x51, 0x67, 0x33, 0x57, 0x15, 0xf5, 0x59, 0x27, 0x66, 0xe8,
0xe2, 0x4b, 0xa3, 0x93, 0x03, 0x8a, 0x9c, 0x05, 0x13, 0xf2, 0xcb, 0xf7,
0x9c, 0x68, 0xe7, 0x16, 0x4b, 0x8e, 0x59, 0x71, 0x2b, 0x73, 0x9b, 0xb9,
0xae, 0x50, 0xfa, 0xd7, 0xd3, 0x34, 0x17, 0x1d, 0x62, 0x88, 0xbd, 0x8c,
0xba, 0x5a, 0x6b, 0x6a, 0x5e, 0xb3, 0xa5, 0x80, 0xca, 0xbb, 0xb9, 0xb5,
0xa8, 0x2e, 0xb1, 0x61, 0x6e, 0xd5, 0xd6, 0x62, 0x98, 0x4a, 0xb0, 0xb8,
0x76, 0xa9, 0x19, 0x5c, 0xe2, 0xbe, 0xb3, 0x9b, 0x4a, 0x39, 0xf5, 0xe6,
0xbb, 0x11, 0x6e, 0x13, 0x13, 0x38, 0xb8, 0x1f, 0x21, 0x19, 0xf5, 0xa7,
0x76, 0x93, 0xb3, 0x56, 0xfa, 0xcc, 0x74, 0xbc, 0x19, 0x02, 0x81, 0xc1,
0x00, 0xd1, 0xd1, 0x72, 0x57, 0xe5, 0xb0, 0x1c, 0x09, 0x05, 0xbb, 0x55,
0x89, 0x3c, 0x4a, 0x81, 0x90, 0x9a, 0xf9, 0x32, 0x63, 0x41, 0xad, 0x6a,
0x5f, 0x65, 0x94, 0x92, 0xcc, 0xf7, 0xc7, 0x53, 0x93, 0xa0, 0xf7, 0xbe,
0x48, 0x82, 0x63, 0x31, 0x7b, 0xd0, 0x82, 0x09, 0xbb, 0x0a, 0xbc, 0x60,
0xc9, 0x4d, 0x83, 0xe4, 0x5d, 0x50, 0xe6, 0x5f, 0x8b, 0x47, 0x07, 0xa3,
0x3a, 0x36, 0x97, 0xaa, 0x21, 0x70, 0x7f, 0xd5, 0x6c, 0xb0, 0x56, 0xf5,
0x5c, 0x48, 0x74, 0x2a, 0xdd, 0xfe, 0x94, 0x83, 0x05, 0xe0, 0x3d, 0x5d,
0xdd, 0x5a, 0x05, 0xcb, 0x47, 0xd7, 0xf9, 0x89, 0x55, 0xaa, 0x0b, 0x21,
0xc0, 0x71, 0x5d, 0xe1, 0x4c, 0x6a, 0x45, 0x86, 0x86, 0xf2, 0xb9, 0x38,
0x6a, 0x56, 0x51, 0x0d, 0x7d, 0xac, 0x30, 0x31, 0xca, 0x2d, 0xaa, 0xaa,
0xba, 0xcc, 0x12, 0x40, 0xc1, 0x0d, 0xa6, 0xc1, 0x7d, 0x22, 0xec, 0xb6,
0x51, 0x45, 0xfe, 0x4e, 0xbb, 0x4a, 0xd2, 0xba, 0x9b, 0xa2, 0xcc, 0x28,
0x2b, 0x01, 0x53, 0x53, 0xf3, 0xa9, 0x5a, 0x8f, 0xeb, 0xb7, 0xb8, 0x62,
0x6b, 0x8a, 0x79, 0x24, 0xcc, 0x86, 0x34, 0x45, 0xe2, 0xad, 0x1d, 0xd0,
0x4c, 0xc9, 0x77, 0x2a, 0xf9, 0x1a, 0xe8, 0x58, 0x78, 0x51, 0x8a, 0xea,
0x3f, 0x90, 0x36, 0x46, 0x2a, 0xc0, 0x71, 0x41, 0x83, 0x2c, 0x48, 0xee,
0xc5, 0x02, 0x81, 0xc1, 0x00, 0xc9, 0xc8, 0xce, 0xc4, 0x50, 0xb2, 0x26,
0xcb, 0x35, 0x78, 0x55, 0x3c, 0xcc, 0xf0, 0x7e, 0xba, 0xad, 0xeb, 0x58,
0xe9, 0xb5, 0x78, 0x2f, 0x43, 0x5f, 0x07, 0x47, 0x56, 0x05, 0x41, 0x38,
0x71, 0xe1, 0x58, 0x62, 0xb1, 0x8e, 0xbc, 0xf9, 0x80, 0x04, 0x22, 0x39,
0x22, 0x24, 0x28, 0x86, 0x9c, 0x00, 0x44, 0x5f, 0xc4, 0x97, 0xe6, 0x71,
0x5f, 0x1f, 0x58, 0xea, 0x75, 0x18, 0x0c, 0x23, 0x63, 0x09, 0xc5, 0x98,
0xc4, 0x6d, 0x23, 0xc2, 0x2c, 0x93, 0x6a, 0x26, 0xe4, 0x3d, 0x8d, 0xa1,
0x39, 0x70, 0x34, 0x25, 0xcd, 0xbc, 0x82, 0x78, 0x2b, 0xf3, 0x7e, 0x81,
0xb6, 0x5f, 0xc5, 0x69, 0xd0, 0x81, 0x69, 0x50, 0x2f, 0x17, 0x0c, 0x17,
0x3c, 0x0b, 0x45, 0x38, 0xce, 0xe3, 0xbf, 0x8a, 0x50, 0x0a, 0x00, 0x74,
0x7e, 0x7a, 0xd8, 0x55, 0x52, 0x6b, 0x82, 0xfb, 0x34, 0x15, 0x73, 0x6a,
0xf4, 0x51, 0x9b, 0x9f, 0xa0, 0x45, 0xb9, 0x76, 0xe5, 0xd3, 0xd5, 0xf4,
0xa9, 0xa4, 0xcd, 0x42, 0x2f, 0x29, 0x89, 0xec, 0x28, 0x5f, 0x03, 0x45,
0x27, 0xaf, 0x8c, 0x39, 0x3e, 0x59, 0x9d, 0xaf, 0x27, 0x5d, 0x17, 0x53,
0x17, 0xeb, 0x8d, 0x7f, 0x3d, 0xb8, 0x2a, 0x50, 0x1e, 0xb5, 0xc5, 0x04,
0xab, 0x9c, 0xa7, 0xaa, 0x86, 0x41, 0xb9, 0x36, 0x29, 0x9e, 0xd2, 0xd8,
0xde, 0x5f, 0xde, 0x80, 0xdb, 0x02, 0x81, 0xc0, 0x03, 0xf3, 0x5f, 0xa5,
0xcc, 0x0b, 0x5e, 0xdb, 0xc4, 0xa1, 0xdc, 0x60, 0x73, 0x24, 0x2c, 0x00,
0x5f, 0x0a, 0xa6, 0x2a, 0x3c, 0x48, 0x59, 0xa2, 0x66, 0x35, 0x3f, 0xf6,
0x60, 0x0b, 0xfe, 0xc4, 0xde, 0xd9, 0x0b, 0x5a, 0x2e, 0x2a, 0x53, 0xfa,
0x32, 0xd8, 0xdf, 0xfa, 0x07, 0x9f, 0xb8, 0x6a, 0xd1, 0xec, 0xd3, 0xd5,
0xf5, 0xfa, 0x00, 0x7e, 0x8c, 0xdd, 0xd5, 0xf2, 0xf8, 0xa8, 0x2e, 0x69,
0xe6, 0xc6, 0x61, 0x6c, 0x64, 0x7d, 0x9e, 0xad, 0x18, 0x28, 0x27, 0xce,
0x7a, 0x46, 0xad, 0x98, 0xe4, 0xba, 0x03, 0x14, 0x71, 0xe7, 0x7e, 0x06,
0x62, 0x48, 0xae, 0x8f, 0x50, 0x5e, 0x59, 0x4a, 0x58, 0x58, 0x1e, 0x2f,
0xe4, 0x28, 0x5e, 0xfa, 0x17, 0x83, 0xe9, 0x4e, 0x07, 0x46, 0x0b, 0x6c,
0xfc, 0x5b, 0x03, 0xf4, 0xfc, 0x9b, 0x24, 0x0f, 0xd4, 0x5b, 0xdb, 0xa0,
0x46, 0xf3, 0x86, 0xdd, 0x26, 0x55, 0x32, 0xb1, 0xa1, 0x11, 0xc2, 0xc5,
0xc0, 0x08, 0xeb, 0xbe, 0x96, 0x78, 0x25, 0xa1, 0x79, 0xaa, 0xe9, 0xff,
0xc2, 0x86, 0x94, 0x03, 0x2a, 0x38, 0x6c, 0x91, 0xfd, 0xcf, 0x7e, 0x23,
0xe3, 0xbb, 0x04, 0x3d, 0xda, 0x68, 0x9f, 0x4d, 0x72, 0xd5, 0xad, 0x97,
0x77, 0x2c, 0x3c, 0xce, 0x37, 0x2a, 0xd8, 0x72, 0x4d, 0xf2, 0xd7, 0xab,
0x62, 0x68, 0x3f, 0x85, 0x8a, 0xc5, 0xec, 0xc9, 0x02, 0x81, 0xc1, 0x00,
0x92, 0x43, 0x0c, 0x1d, 0x20, 0xa1, 0x01, 0x9d, 0xaa, 0x54, 0x5e, 0xf4,
0x83, 0x58, 0x8f, 0x83, 0xa1, 0x2d, 0x46, 0x75, 0xa1, 0x24, 0x4c, 0x9d,
0xf8, 0xf3, 0xbd, 0xb1, 0x8c, 0x7d, 0x89, 0xfc, 0x81, 0xeb, 0x1f, 0x1e,
0xb4, 0xe8, 0x25, 0xb1, 0xb5, 0x4d, 0x59, 0x3c, 0x76, 0x19, 0x29, 0xf9,
0x49, 0xf8, 0x45, 0xb2, 0xaa, 0xa8, 0x4e, 0xe5, 0x34, 0x43, 0xaf, 0x2e,
0xd1, 0x0f, 0x7b, 0x56, 0xfe, 0x6e, 0x4c, 0x1d, 0x95, 0x3e, 0xa6, 0x30,
0xc9, 0x69, 0xd8, 0x66, 0xf8, 0x77, 0x00, 0xb6, 0x31, 0xae, 0x9a, 0xf8,
0x55, 0xfb, 0xfc, 0x3f, 0x5f, 0x70, 0x03, 0x75, 0xbe, 0x55, 0xca, 0x2d,
0x68, 0xa0, 0x7d, 0x8e, 0xa4, 0x96, 0x0f, 0x01, 0x66, 0xe9, 0xf6, 0x13,
0x80, 0xe2, 0x05, 0xcf, 0x9e, 0x70, 0x56, 0x00, 0x97, 0xea, 0xd7, 0x6d,
0xb6, 0xa0, 0x6a, 0x95, 0x86, 0x36, 0xf2, 0xff, 0xc5, 0x67, 0x98, 0x7d,
0x04, 0x0d, 0x3b, 0x31, 0xbc, 0x2b, 0x09, 0xfd, 0x2d, 0x87, 0xda, 0xc1,
0x74, 0xca, 0x94, 0x73, 0x6e, 0xeb, 0x5f, 0xe5, 0x34, 0x49, 0xdf, 0xf4,
0x61, 0xe0, 0xfa, 0x64, 0xfe, 0x05, 0x3a, 0x25, 0xcc, 0x87, 0xf4, 0x03,
0x38, 0xca, 0xf2, 0xe8, 0x4f, 0xb9, 0x4f, 0x79, 0x55, 0x43, 0xf3, 0x46,
0xfd, 0xbc, 0xd2, 0x95, 0xb8, 0x99, 0xfc, 0xb8, 0xb3, 0xa5, 0x04, 0xa1,
0x02, 0x81, 0xc0, 0x47, 0xc6, 0x9c, 0x18, 0x54, 0xe5, 0xbb, 0xf9, 0xf4,
0x38, 0xd2, 0xc0, 0xd1, 0x1a, 0xcc, 0xdb, 0x06, 0x87, 0x75, 0x1f, 0x13,
0xa2, 0x7f, 0x8b, 0x45, 0x54, 0xcb, 0x43, 0xf8, 0xbb, 0x94, 0xd6, 0x2e,
0x56, 0x5c, 0x69, 0x6d, 0x83, 0xb5, 0x45, 0x46, 0x68, 0x5c, 0x76, 0x1e,
0x6c, 0x0c, 0x53, 0x59, 0xcc, 0x19, 0xc7, 0x81, 0x62, 0x66, 0x92, 0x02,
0x8f, 0xa6, 0xdb, 0x50, 0x1c, 0x67, 0xfc, 0x82, 0x56, 0x2b, 0x4b, 0x1f,
0x97, 0x87, 0xc4, 0x7d, 0x20, 0xda, 0xd3, 0x3f, 0x28, 0xf9, 0x55, 0xfe,
0x84, 0x50, 0xc5, 0x3b, 0xd4, 0xaf, 0xf5, 0x3d, 0x43, 0xce, 0xdc, 0x55,
0x11, 0x87, 0xdb, 0x72, 0x66, 0xcc, 0x83, 0xc4, 0x8b, 0x20, 0xae, 0x59,
0x4d, 0xeb, 0xac, 0xb5, 0x4a, 0xec, 0x66, 0x09, 0x37, 0x55, 0x14, 0x21,
0x57, 0xff, 0x0a, 0xac, 0xda, 0xb1, 0xae, 0x31, 0xab, 0x41, 0x30, 0x65,
0x02, 0x83, 0xd1, 0xdb, 0x65, 0xb7, 0x52, 0xa7, 0x21, 0x9f, 0x1f, 0x8f,
0x69, 0x23, 0x3b, 0xb8, 0xf9, 0x6d, 0xe7, 0xc1, 0x53, 0x9f, 0x8f, 0x67,
0xfc, 0x6e, 0x20, 0x18, 0x31, 0x89, 0xe7, 0xbb, 0xd4, 0xc1, 0x03, 0x67,
0xd6, 0xa5, 0x76, 0xc9, 0xea, 0x97, 0x93, 0x02, 0xca, 0x44, 0x52, 0x55,
0x0f, 0xed, 0x55, 0xb5, 0x49, 0xd6, 0x94, 0x59, 0xee, 0xcc, 0x1b, 0x5a,
0x00, 0x3d, 0xcd};
static const unsigned char kTestRsaPublicKey1_3072[] = {
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xa5, 0x62, 0x07,
0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0, 0x78, 0x76, 0xbe,
0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3, 0x0f, 0xe9, 0x61,
0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2, 0xca, 0xe4, 0xdd,
0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55, 0x1b, 0x83, 0xbe,
0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29, 0x46, 0xc2, 0x65,
0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17, 0x01, 0xb5, 0x11,
0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37, 0x5c, 0xb4, 0x7a,
0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1, 0x14, 0xf1, 0x22,
0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86, 0xcd, 0xa0, 0x0a,
0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3, 0xb6, 0x0e, 0x85,
0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4, 0xde, 0xf2, 0x59,
0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb, 0x31, 0xa0, 0xee,
0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee, 0x3a, 0xae, 0xb2,
0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb, 0x90, 0x97, 0x2c,
0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca, 0x49, 0x94, 0x53,
0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0, 0x5f, 0x07, 0x53,
0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6, 0xda, 0xea, 0x1e,
0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb, 0x17, 0xe8, 0xc9,
0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab, 0x30, 0xb7, 0xf5,
0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26, 0xaf, 0x39, 0xf3,
0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10, 0x16, 0x9c, 0xee,
0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b, 0x42, 0x72, 0x85,
0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21, 0xf9, 0xa6, 0x82,
0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64, 0xe4, 0x3a, 0x3b,
0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05, 0x4a, 0xe9, 0x4c,
0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1, 0x72, 0x71, 0x04,
0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab, 0xde, 0x8f, 0xe1,
0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50, 0x04, 0xb5, 0xd7,
0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85, 0x1b, 0x38, 0xff,
0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0, 0x33, 0x61, 0x53,
0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b, 0x67, 0xd5, 0xf0,
0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87, 0x02, 0x03, 0x01,
0x00, 0x01};
static const unsigned char kTestRsaPrivateKey2_2048[] = {
0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, 0xb4,
0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f,
0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, 0x7e,
0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa,
0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, 0xf7,
0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b,
0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, 0x68,
0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8,
0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, 0xc2,
0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73,
0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, 0x4e,
0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd,
0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, 0x88,
0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88,
0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, 0xc8,
0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2,
0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, 0x2e,
0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f,
0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, 0x29,
0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e,
0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, 0x5f,
0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x5e, 0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05, 0x45, 0x0f,
0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29, 0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8,
0xac, 0x97, 0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7, 0x3b, 0x5c,
0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d, 0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a,
0x7e, 0xdc, 0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c, 0x5e, 0x79,
0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1, 0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e,
0x79, 0xf9, 0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3, 0x68, 0x7b,
0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba, 0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1,
0x71, 0xe7, 0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75, 0xbe, 0x09,
0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22, 0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1,
0xe8, 0x88, 0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78, 0x25, 0x0b,
0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21, 0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0,
0x37, 0x14, 0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47, 0xde, 0x00,
0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa, 0x68, 0x71, 0x17, 0x66, 0x12, 0x1a,
0x87, 0x27, 0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d, 0x6f, 0x35,
0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51, 0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7,
0xb6, 0x64, 0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53, 0x1f, 0x51,
0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77, 0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96,
0x07, 0x5f, 0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29, 0xf6, 0x06,
0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0, 0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e,
0xc9, 0x21, 0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81, 0xb2, 0x51,
0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02, 0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c,
0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, 0x78, 0xcc,
0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85,
0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, 0x84, 0x68,
0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86,
0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, 0x3a, 0x83,
0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7,
0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, 0x18, 0x6c,
0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a,
0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, 0x3c, 0x2d,
0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60, 0x48, 0x16,
0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, 0x15, 0x43,
0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49,
0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, 0xcb, 0x43,
0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17,
0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, 0xa7, 0x5b,
0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d,
0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, 0xc1, 0xee,
0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d,
0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, 0x0d, 0x6c,
0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83, 0x51, 0x67,
0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, 0x53, 0xa8,
0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c, 0x32, 0x83,
0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, 0x0a, 0x2d,
0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b,
0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, 0xeb, 0xdb,
0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25,
0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, 0x37, 0x43,
0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d,
0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, 0xf9, 0xca,
0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71,
0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, 0xb1, 0x31,
0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29, 0x40, 0x19,
0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, 0xcc, 0x3b,
0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94, 0x49, 0x4c,
0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, 0x6a, 0xab,
0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec,
0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, 0x5f, 0xdf,
0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22,
0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, 0x77, 0xe6,
0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a,
0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, 0xd9, 0xbe,
0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96,
0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, 0xac, 0x21,
0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6,
0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, 0x28, 0x66,
0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9,
0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, 0x70, 0xcf,
0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6,
0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, 0x50, 0xcb,
0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7,
0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, 0xa2, 0x0d,
0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae,
0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, 0x72, 0x2c,
0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0,
0xdb, 0x03};
static const unsigned char kTestRsaPublicKey2_2048[] = {
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36,
0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94,
0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0,
0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f,
0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4,
0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9,
0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10,
0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a,
0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8,
0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a,
0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54,
0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82,
0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed,
0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66,
0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18,
0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2,
0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21,
0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce,
0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07,
0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97,
0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39,
0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a,
0x05, 0x02, 0x03, 0x01, 0x00, 0x01};
static const unsigned char kTestRsaPrivateKey3_2048[] = {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40,
0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83, 0xa7,
0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44,
0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a, 0x91,
0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08,
0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74, 0x10,
0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d,
0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47, 0x94,
0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d,
0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03, 0x68,
0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55,
0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c, 0xe8,
0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7,
0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0, 0x35,
0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06,
0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a, 0x21,
0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae,
0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87, 0x3c,
0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84,
0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f, 0x87,
0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b,
0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x43, 0x8f, 0x19, 0x83, 0xb1, 0x27, 0x4e, 0xee, 0x98, 0xba, 0xcb,
0x54, 0xa0, 0x77, 0x11, 0x6d, 0xd4, 0x25, 0x31, 0x8c, 0xb0, 0x01, 0xcf,
0xe6, 0x80, 0x83, 0x14, 0x40, 0x67, 0x39, 0x33, 0x67, 0x03, 0x1e, 0xa0,
0x8b, 0xd1, 0x1d, 0xfd, 0x80, 0xa4, 0xb9, 0xe7, 0x57, 0x5e, 0xc8, 0x8e,
0x79, 0x71, 0xd5, 0x6b, 0x09, 0xe9, 0x2b, 0x41, 0xa0, 0x33, 0x64, 0xc9,
0x66, 0x33, 0xa1, 0xb1, 0x55, 0x07, 0x55, 0x98, 0x53, 0x10, 0xe6, 0xc0,
0x39, 0x6d, 0x61, 0xd9, 0xe8, 0x16, 0x52, 0x28, 0xe4, 0x2b, 0xda, 0x27,
0x01, 0xaf, 0x21, 0x4a, 0xe8, 0x55, 0x1d, 0x0b, 0xd1, 0x1c, 0xdc, 0xfd,
0xb3, 0x0b, 0xa6, 0x5c, 0xcc, 0x6e, 0x77, 0xb8, 0xe0, 0xd1, 0x4e, 0x0a,
0xd7, 0x7a, 0x5e, 0x18, 0xc3, 0xfb, 0xe9, 0xa1, 0x9c, 0xc3, 0x9c, 0xd4,
0x4a, 0x7e, 0x70, 0x72, 0x11, 0x18, 0x24, 0x56, 0x24, 0xdf, 0xf8, 0xba,
0xac, 0x5b, 0x54, 0xd3, 0xc4, 0x65, 0x69, 0xc8, 0x79, 0x94, 0x16, 0x88,
0x9a, 0x68, 0x1c, 0xbc, 0xd4, 0xca, 0xec, 0x5e, 0x07, 0x4a, 0xc9, 0x54,
0x7a, 0x4b, 0xdb, 0x19, 0x88, 0xf6, 0xbe, 0x50, 0x9d, 0x9e, 0x9d, 0x88,
0x5b, 0x4a, 0x23, 0x86, 0x2b, 0xa9, 0xa6, 0x6c, 0x70, 0x7d, 0xe1, 0x11,
0xba, 0xbf, 0x03, 0x2e, 0xf1, 0x46, 0x7e, 0x1b, 0xed, 0x06, 0x11, 0x57,
0xad, 0x4a, 0xcb, 0xe5, 0xb1, 0x11, 0x05, 0x0a, 0x30, 0xb1, 0x73, 0x79,
0xcd, 0x7a, 0x04, 0xcc, 0x70, 0xe9, 0x95, 0xe4, 0x27, 0xc2, 0xd5, 0x2d,
0x92, 0x44, 0xdf, 0xb4, 0x94, 0xa8, 0x73, 0xa1, 0x4a, 0xc3, 0xcc, 0xc4,
0x0e, 0x8d, 0xa1, 0x6a, 0xc2, 0xd8, 0x03, 0x7f, 0xfa, 0xa7, 0x76, 0x0d,
0xad, 0x87, 0x88, 0xa0, 0x77, 0xaf, 0x3b, 0x23, 0xd1, 0x66, 0x0b, 0x31,
0x2b, 0xaf, 0xef, 0xd5, 0x41, 0x02, 0x81, 0x81, 0x00, 0xdb, 0xc1, 0xe7,
0xdd, 0xba, 0x3c, 0x1f, 0x9c, 0x64, 0xca, 0xa0, 0x63, 0xdb, 0xd2, 0x47,
0x5c, 0x6e, 0x8a, 0xa3, 0x16, 0xd5, 0xda, 0xc2, 0x25, 0x64, 0x0a, 0x02,
0xbc, 0x7d, 0x7f, 0x50, 0xab, 0xe0, 0x66, 0x03, 0x53, 0x7d, 0x77, 0x6d,
0x6c, 0x61, 0x58, 0x09, 0x73, 0xcd, 0x18, 0xe9, 0x53, 0x0b, 0x5c, 0xa2,
0x71, 0x14, 0x02, 0xfd, 0x55, 0xda, 0xe9, 0x77, 0x24, 0x7c, 0x2a, 0x4e,
0xb9, 0xd9, 0x5d, 0x58, 0xf6, 0x26, 0xd0, 0xd8, 0x3d, 0xcf, 0x8c, 0x89,
0x65, 0x6c, 0x35, 0x19, 0xb6, 0x63, 0xff, 0xa0, 0x71, 0x49, 0xcd, 0x6d,
0x5b, 0x3d, 0x8f, 0xea, 0x6f, 0xa9, 0xba, 0x43, 0xe5, 0xdd, 0x39, 0x3a,
0x78, 0x8f, 0x07, 0xb8, 0xab, 0x58, 0x07, 0xb7, 0xd2, 0xf8, 0x07, 0x02,
0x9b, 0x79, 0x26, 0x32, 0x22, 0x38, 0x91, 0x01, 0x90, 0x81, 0x29, 0x94,
0xad, 0x77, 0xeb, 0x86, 0xb9, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x29, 0x88,
0xbd, 0x96, 0x31, 0x33, 0x7b, 0x77, 0x5d, 0x32, 0x12, 0x5e, 0xdf, 0x28,
0x0c, 0x96, 0x0d, 0xa8, 0x22, 0xdf, 0xd3, 0x35, 0xd7, 0xb0, 0x41, 0xcb,
0xe7, 0x94, 0x8a, 0xa4, 0xed, 0xd2, 0xfb, 0xd2, 0xf3, 0xf2, 0x95, 0xff,
0xd8, 0x33, 0x3f, 0x8c, 0xd7, 0x65, 0xe4, 0x0c, 0xcc, 0xfe, 0x32, 0x66,
0xfa, 0x50, 0xe2, 0xcf, 0xf0, 0xbe, 0x05, 0xb1, 0xbc, 0xbe, 0x44, 0x09,
0xb4, 0xfe, 0x95, 0x06, 0x18, 0xd7, 0x59, 0xc6, 0xef, 0x2d, 0x22, 0xa0,
0x73, 0x5e, 0x77, 0xdf, 0x8d, 0x09, 0x2c, 0xb8, 0xcc, 0xeb, 0x10, 0x4d,
0xa7, 0xd0, 0x4b, 0x46, 0xba, 0x7d, 0x8b, 0x6a, 0x55, 0x47, 0x55, 0xd3,
0xd7, 0xb1, 0x88, 0xfd, 0x27, 0x3e, 0xf9, 0x5b, 0x7b, 0xae, 0x6d, 0x08,
0x9f, 0x0c, 0x2a, 0xe1, 0xdd, 0xb9, 0xe3, 0x55, 0x13, 0x55, 0xa3, 0x6d,
0x06, 0xbb, 0xe0, 0x1e, 0x55, 0x02, 0x81, 0x80, 0x61, 0x73, 0x3d, 0x64,
0xff, 0xdf, 0x05, 0x8d, 0x8e, 0xcc, 0xa4, 0x0f, 0x64, 0x3d, 0x7d, 0x53,
0xa9, 0xd9, 0x64, 0xb5, 0x0d, 0xa4, 0x72, 0x8f, 0xae, 0x2b, 0x1a, 0x47,
0x87, 0xc7, 0x5b, 0x78, 0xbc, 0x8b, 0xc0, 0x51, 0xd7, 0xc3, 0x8c, 0x0c,
0x91, 0xa6, 0x3e, 0x9a, 0xd1, 0x8a, 0x88, 0x7d, 0x40, 0xfe, 0x95, 0x32,
0x5b, 0xd3, 0x6f, 0x90, 0x11, 0x01, 0x92, 0xc9, 0xe5, 0x1d, 0xc5, 0xc7,
0x78, 0x72, 0x82, 0xae, 0xb5, 0x4b, 0xcb, 0x78, 0xad, 0x7e, 0xfe, 0xb6,
0xb1, 0x23, 0x63, 0x01, 0x94, 0x9a, 0x99, 0x05, 0x63, 0xda, 0xea, 0xf1,
0x98, 0xfd, 0x26, 0xd2, 0xd9, 0x8b, 0x35, 0xec, 0xcb, 0x0b, 0x43, 0xb8,
0x8e, 0x84, 0xb8, 0x09, 0x93, 0x81, 0xe8, 0xac, 0x6f, 0x3c, 0x7c, 0x95,
0x81, 0x45, 0xc4, 0xd9, 0x94, 0x08, 0x09, 0x8f, 0x91, 0x17, 0x65, 0x4c,
0xff, 0x6e, 0xbc, 0x51, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x0d, 0x9d, 0xd8,
0xbd, 0xaf, 0x56, 0xe0, 0xe3, 0x1f, 0x85, 0xd7, 0xce, 0x72, 0x02, 0x38,
0xf2, 0x0f, 0x9c, 0x27, 0x9e, 0xc4, 0x1d, 0x60, 0x00, 0x8d, 0x02, 0x19,
0xe5, 0xdf, 0xdb, 0x8e, 0xc5, 0xfb, 0x61, 0x8e, 0xe6, 0xb8, 0xfc, 0x07,
0x3c, 0xd1, 0x1b, 0x16, 0x7c, 0x83, 0x3c, 0x37, 0xf5, 0x26, 0xb2, 0xbd,
0x22, 0xf2, 0x4d, 0x19, 0x33, 0x11, 0xc5, 0xdd, 0xf9, 0xdb, 0x4e, 0x48,
0x52, 0xd8, 0xe6, 0x4b, 0x15, 0x90, 0x68, 0xbe, 0xca, 0xc1, 0x7c, 0xd3,
0x51, 0x6b, 0x45, 0x46, 0x54, 0x11, 0x1a, 0x71, 0xd3, 0xcd, 0x6b, 0x8f,
0x79, 0x22, 0x83, 0x02, 0x08, 0x4f, 0xba, 0x6a, 0x98, 0xed, 0x32, 0xd8,
0xb4, 0x5b, 0x51, 0x88, 0x53, 0xec, 0x2c, 0x7e, 0xa4, 0x89, 0xdc, 0xbf,
0xf9, 0x0d, 0x32, 0xc8, 0xc3, 0xec, 0x6d, 0x2e, 0xf1, 0xbc, 0x70, 0x4e,
0xf6, 0x9e, 0xbc, 0x31, 0x02, 0x81, 0x81, 0x00, 0xd3, 0x35, 0x1b, 0x19,
0x75, 0x3f, 0x61, 0xf2, 0x55, 0x03, 0xce, 0x25, 0xa9, 0xdf, 0x0c, 0x0a,
0x3b, 0x47, 0x42, 0xdc, 0x38, 0x4b, 0x13, 0x4d, 0x1f, 0x86, 0x58, 0x4f,
0xd8, 0xee, 0xfa, 0x76, 0x15, 0xfb, 0x6e, 0x55, 0x31, 0xf2, 0xd2, 0x62,
0x32, 0xa5, 0xc4, 0x23, 0x5e, 0x08, 0xa9, 0x83, 0x07, 0xac, 0x8c, 0xa3,
0x7e, 0x18, 0xc0, 0x1c, 0x57, 0x63, 0x8d, 0x05, 0x17, 0x47, 0x1b, 0xd3,
0x74, 0x73, 0x20, 0x04, 0xfb, 0xc8, 0x1a, 0x43, 0x04, 0x36, 0xc8, 0x19,
0xbe, 0xdc, 0xa6, 0xe5, 0x0f, 0x25, 0x62, 0x24, 0x96, 0x92, 0xb6, 0xb3,
0x97, 0xad, 0x57, 0x9a, 0x90, 0x37, 0x4e, 0x31, 0x44, 0x74, 0xfa, 0x7c,
0xb4, 0xea, 0xfc, 0x15, 0xa7, 0xb0, 0x51, 0xcc, 0xee, 0x1e, 0xed, 0x5b,
0x98, 0x18, 0x0e, 0x65, 0xb6, 0x4b, 0x69, 0x0b, 0x21, 0xdc, 0x86, 0x17,
0x6e, 0xc8, 0xee, 0x24};
static const unsigned char kTestRsaPublicKey3_2048[] = {
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0xd0, 0xd7,
0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40, 0x1e, 0x2d, 0x89,
0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83, 0xa7, 0xe0, 0xa5, 0x41,
0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44, 0xb3, 0x08, 0x05,
0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a, 0x91, 0x00, 0x50, 0xa8,
0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08, 0x32, 0x8b, 0x10,
0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74, 0x10, 0xc6, 0x24, 0xb1,
0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d, 0xe0, 0x15, 0x6b,
0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47, 0x94, 0x40, 0x70, 0xac,
0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d, 0x04, 0xe7, 0x95,
0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03, 0x68, 0x16, 0x31, 0xaa,
0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55, 0x44, 0xf8, 0xd4,
0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c, 0xe8, 0x49, 0x5d, 0xaf,
0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7, 0x8c, 0x8f, 0x0b,
0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0, 0x35, 0x52, 0x7c, 0x66,
0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06, 0xd9, 0x84, 0x51,
0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a, 0x21, 0xe6, 0x82, 0xfd,
0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae, 0xb8, 0x8e, 0xee,
0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87, 0x3c, 0x37, 0xc5, 0x89,
0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84, 0x7f, 0xfe, 0x9a,
0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f, 0x87, 0x7f, 0xcb, 0xc1,
0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b, 0x6f, 0xdd, 0x69,
0x6d, 0x02, 0x03, 0x01, 0x00, 0x01};
unsigned char kTestRsaPrivateKey2CarmichaelTotient_2048[] = {
0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, 0xb4,
0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f,
0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, 0x7e,
0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa,
0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, 0xf7,
0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b,
0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, 0x68,
0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8,
0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, 0xc2,
0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73,
0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, 0x4e,
0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd,
0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, 0x88,
0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88,
0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, 0xc8,
0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2,
0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, 0x2e,
0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f,
0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, 0x29,
0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e,
0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, 0x5f,
0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x0a, 0xf9, 0x4a, 0x19, 0x72, 0x88, 0x1b, 0x4e, 0xd8, 0x2f, 0xef,
0x99, 0x93, 0x32, 0xda, 0x51, 0x21, 0x2e, 0x14, 0x06, 0xf4, 0xe9, 0x65,
0x1c, 0xf9, 0xd4, 0xcf, 0x1a, 0x51, 0x53, 0xcd, 0x48, 0x33, 0x8c, 0x30,
0xed, 0xdd, 0x53, 0x6f, 0x29, 0x82, 0xf9, 0xe0, 0x74, 0xde, 0xb1, 0x13,
0x01, 0x88, 0x8f, 0xce, 0x14, 0xc1, 0x3b, 0x90, 0xb7, 0xcc, 0x6c, 0xdf,
0x35, 0xa1, 0xf2, 0x1a, 0x3d, 0xbe, 0x19, 0xd7, 0x0a, 0xe4, 0x67, 0x75,
0xbb, 0xfa, 0x87, 0xf4, 0x03, 0xb5, 0x7f, 0x69, 0xe4, 0x0b, 0x6a, 0xdc,
0x92, 0x82, 0x54, 0x64, 0x1a, 0x94, 0x2d, 0xe4, 0x63, 0x40, 0xb2, 0xb4,
0x85, 0x6b, 0xc8, 0x34, 0xba, 0xa2, 0x14, 0x30, 0x47, 0x1a, 0xeb, 0x90,
0x62, 0x30, 0x43, 0x44, 0x02, 0xc7, 0x0c, 0x30, 0xc0, 0x7f, 0xa9, 0x47,
0xae, 0xde, 0x68, 0x27, 0x92, 0xaa, 0x11, 0x95, 0xf5, 0x6f, 0xfc, 0x19,
0x8b, 0x49, 0xa0, 0x77, 0x9d, 0xc6, 0x13, 0x5d, 0x73, 0xff, 0x45, 0xa2,
0x4c, 0x3b, 0xf3, 0xe1, 0x2d, 0xd7, 0xc4, 0x70, 0xe2, 0x6c, 0x37, 0x99,
0x4c, 0x7a, 0xa9, 0x27, 0xf8, 0x3a, 0xd6, 0xfd, 0xc5, 0xd8, 0xfa, 0x2d,
0x0e, 0x71, 0x4b, 0x85, 0x7e, 0xce, 0xcb, 0x1c, 0x79, 0x71, 0xbd, 0xff,
0x63, 0x03, 0x6b, 0x58, 0x68, 0xe0, 0x14, 0xca, 0x5e, 0x85, 0xfd, 0xd0,
0xb7, 0xe0, 0x68, 0x14, 0xff, 0x2c, 0x82, 0x22, 0x26, 0x8a, 0x3f, 0xbf,
0xb0, 0x2a, 0x90, 0xff, 0xc7, 0x72, 0xfc, 0x66, 0x51, 0x3e, 0x51, 0x9f,
0x82, 0x68, 0x0e, 0xf3, 0x65, 0x74, 0x88, 0xab, 0xb7, 0xe5, 0x97, 0x5f,
0x0f, 0x3e, 0xe5, 0x3a, 0xbc, 0xa4, 0xa1, 0x50, 0xdd, 0x5c, 0x94, 0x4b,
0x0c, 0x70, 0x71, 0x48, 0x4e, 0xd0, 0xec, 0x46, 0x8f, 0xdf, 0xa2, 0x9a,
0xfe, 0xd8, 0x35, 0x1a, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c,
0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, 0x78, 0xcc,
0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85,
0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, 0x84, 0x68,
0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86,
0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, 0x3a, 0x83,
0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7,
0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, 0x18, 0x6c,
0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a,
0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, 0x3c, 0x2d,
0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60, 0x48, 0x16,
0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, 0x15, 0x43,
0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49,
0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, 0xcb, 0x43,
0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17,
0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, 0xa7, 0x5b,
0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d,
0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, 0xc1, 0xee,
0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d,
0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, 0x0d, 0x6c,
0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83, 0x51, 0x67,
0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, 0x53, 0xa8,
0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c, 0x32, 0x83,
0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, 0x0a, 0x2d,
0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b,
0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, 0xeb, 0xdb,
0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25,
0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, 0x37, 0x43,
0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d,
0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, 0xf9, 0xca,
0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71,
0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, 0xb1, 0x31,
0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29, 0x40, 0x19,
0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, 0xcc, 0x3b,
0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94, 0x49, 0x4c,
0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, 0x6a, 0xab,
0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec,
0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, 0x5f, 0xdf,
0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22,
0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, 0x77, 0xe6,
0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a,
0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, 0xd9, 0xbe,
0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96,
0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, 0xac, 0x21,
0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6,
0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, 0x28, 0x66,
0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9,
0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, 0x70, 0xcf,
0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6,
0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, 0x50, 0xcb,
0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7,
0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, 0xa2, 0x0d,
0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae,
0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, 0x72, 0x2c,
0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0,
0xdb, 0x03};
static const unsigned char kTestRsaPrivateKey3CarmichaelTotient_2048[] = {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40,
0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83, 0xa7,
0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44,
0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a, 0x91,
0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08,
0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74, 0x10,
0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d,
0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47, 0x94,
0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d,
0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03, 0x68,
0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55,
0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c, 0xe8,
0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7,
0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0, 0x35,
0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06,
0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a, 0x21,
0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae,
0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87, 0x3c,
0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84,
0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f, 0x87,
0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b,
0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x1a, 0x1a, 0xe3, 0xb4, 0x2d, 0x9b, 0xd0, 0x1d, 0xc4, 0x54, 0x50,
0xc4, 0x98, 0xeb, 0xae, 0xf4, 0xab, 0x95, 0x72, 0x78, 0x60, 0xbe, 0x2e,
0xfc, 0x88, 0x59, 0xc3, 0xff, 0x5f, 0xb4, 0x01, 0xfd, 0x2c, 0x06, 0x52,
0xfa, 0xa4, 0x5b, 0xfc, 0x29, 0xdf, 0x82, 0x67, 0x14, 0x52, 0x39, 0x67,
0xd5, 0x31, 0xc1, 0x41, 0x02, 0x76, 0x03, 0x5d, 0xd2, 0xc5, 0x74, 0x2c,
0x24, 0x26, 0xfe, 0xed, 0x46, 0x65, 0x97, 0x22, 0x74, 0xe7, 0xff, 0x63,
0x35, 0x3b, 0xd8, 0xad, 0x88, 0x2c, 0xe2, 0x50, 0xf3, 0x76, 0x14, 0xbe,
0x3a, 0x37, 0x1b, 0xf0, 0x21, 0x91, 0x8e, 0xdd, 0x43, 0xed, 0xb7, 0xab,
0xcd, 0xfb, 0x8a, 0x31, 0xa6, 0x26, 0xb4, 0xd5, 0x4b, 0x2c, 0x80, 0x7f,
0xfc, 0x39, 0x24, 0x33, 0x7d, 0x6d, 0xf3, 0x1c, 0x06, 0xdd, 0x21, 0x53,
0x70, 0x78, 0xe4, 0x07, 0x60, 0x2a, 0x3f, 0xb8, 0xd0, 0x47, 0xf6, 0x0e,
0xbd, 0xde, 0x31, 0xf3, 0x66, 0xfe, 0x6e, 0x4b, 0x50, 0x75, 0x0b, 0x49,
0x3a, 0x96, 0xeb, 0x63, 0xb9, 0x24, 0xbb, 0xfc, 0xcd, 0xf5, 0x49, 0x12,
0xa9, 0x6d, 0x39, 0xd4, 0x18, 0x15, 0x14, 0x50, 0x82, 0xa9, 0x75, 0xeb,
0x9f, 0x1a, 0xaa, 0x52, 0x1d, 0x0d, 0x55, 0x74, 0x30, 0x45, 0x3b, 0xd2,
0xd3, 0xe1, 0xdb, 0x8d, 0xec, 0x38, 0x2b, 0xb0, 0xdd, 0xda, 0x10, 0xe3,
0x40, 0x87, 0x27, 0xbe, 0x0b, 0xbf, 0x08, 0x9e, 0x25, 0x95, 0x14, 0xf4,
0xd7, 0xfe, 0x8c, 0x4f, 0x23, 0xfd, 0x1b, 0xad, 0x83, 0x6b, 0x05, 0x3a,
0x83, 0xfa, 0x65, 0x1e, 0x65, 0x12, 0xe3, 0x9f, 0xea, 0x52, 0xd7, 0xed,
0x01, 0x7d, 0xc5, 0xf1, 0x96, 0x2d, 0xf5, 0x4a, 0xa3, 0xcb, 0x69, 0x6c,
0x9a, 0x48, 0xe9, 0xf5, 0x01, 0xef, 0x1d, 0x2e, 0x90, 0x64, 0x6c, 0x0b,
0x79, 0xe0, 0xeb, 0x64, 0x29, 0x02, 0x81, 0x81, 0x00, 0xdb, 0xc1, 0xe7,
0xdd, 0xba, 0x3c, 0x1f, 0x9c, 0x64, 0xca, 0xa0, 0x63, 0xdb, 0xd2, 0x47,
0x5c, 0x6e, 0x8a, 0xa3, 0x16, 0xd5, 0xda, 0xc2, 0x25, 0x64, 0x0a, 0x02,
0xbc, 0x7d, 0x7f, 0x50, 0xab, 0xe0, 0x66, 0x03, 0x53, 0x7d, 0x77, 0x6d,
0x6c, 0x61, 0x58, 0x09, 0x73, 0xcd, 0x18, 0xe9, 0x53, 0x0b, 0x5c, 0xa2,
0x71, 0x14, 0x02, 0xfd, 0x55, 0xda, 0xe9, 0x77, 0x24, 0x7c, 0x2a, 0x4e,
0xb9, 0xd9, 0x5d, 0x58, 0xf6, 0x26, 0xd0, 0xd8, 0x3d, 0xcf, 0x8c, 0x89,
0x65, 0x6c, 0x35, 0x19, 0xb6, 0x63, 0xff, 0xa0, 0x71, 0x49, 0xcd, 0x6d,
0x5b, 0x3d, 0x8f, 0xea, 0x6f, 0xa9, 0xba, 0x43, 0xe5, 0xdd, 0x39, 0x3a,
0x78, 0x8f, 0x07, 0xb8, 0xab, 0x58, 0x07, 0xb7, 0xd2, 0xf8, 0x07, 0x02,
0x9b, 0x79, 0x26, 0x32, 0x22, 0x38, 0x91, 0x01, 0x90, 0x81, 0x29, 0x94,
0xad, 0x77, 0xeb, 0x86, 0xb9, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x29, 0x88,
0xbd, 0x96, 0x31, 0x33, 0x7b, 0x77, 0x5d, 0x32, 0x12, 0x5e, 0xdf, 0x28,
0x0c, 0x96, 0x0d, 0xa8, 0x22, 0xdf, 0xd3, 0x35, 0xd7, 0xb0, 0x41, 0xcb,
0xe7, 0x94, 0x8a, 0xa4, 0xed, 0xd2, 0xfb, 0xd2, 0xf3, 0xf2, 0x95, 0xff,
0xd8, 0x33, 0x3f, 0x8c, 0xd7, 0x65, 0xe4, 0x0c, 0xcc, 0xfe, 0x32, 0x66,
0xfa, 0x50, 0xe2, 0xcf, 0xf0, 0xbe, 0x05, 0xb1, 0xbc, 0xbe, 0x44, 0x09,
0xb4, 0xfe, 0x95, 0x06, 0x18, 0xd7, 0x59, 0xc6, 0xef, 0x2d, 0x22, 0xa0,
0x73, 0x5e, 0x77, 0xdf, 0x8d, 0x09, 0x2c, 0xb8, 0xcc, 0xeb, 0x10, 0x4d,
0xa7, 0xd0, 0x4b, 0x46, 0xba, 0x7d, 0x8b, 0x6a, 0x55, 0x47, 0x55, 0xd3,
0xd7, 0xb1, 0x88, 0xfd, 0x27, 0x3e, 0xf9, 0x5b, 0x7b, 0xae, 0x6d, 0x08,
0x9f, 0x0c, 0x2a, 0xe1, 0xdd, 0xb9, 0xe3, 0x55, 0x13, 0x55, 0xa3, 0x6d,
0x06, 0xbb, 0xe0, 0x1e, 0x55, 0x02, 0x81, 0x80, 0x61, 0x73, 0x3d, 0x64,
0xff, 0xdf, 0x05, 0x8d, 0x8e, 0xcc, 0xa4, 0x0f, 0x64, 0x3d, 0x7d, 0x53,
0xa9, 0xd9, 0x64, 0xb5, 0x0d, 0xa4, 0x72, 0x8f, 0xae, 0x2b, 0x1a, 0x47,
0x87, 0xc7, 0x5b, 0x78, 0xbc, 0x8b, 0xc0, 0x51, 0xd7, 0xc3, 0x8c, 0x0c,
0x91, 0xa6, 0x3e, 0x9a, 0xd1, 0x8a, 0x88, 0x7d, 0x40, 0xfe, 0x95, 0x32,
0x5b, 0xd3, 0x6f, 0x90, 0x11, 0x01, 0x92, 0xc9, 0xe5, 0x1d, 0xc5, 0xc7,
0x78, 0x72, 0x82, 0xae, 0xb5, 0x4b, 0xcb, 0x78, 0xad, 0x7e, 0xfe, 0xb6,
0xb1, 0x23, 0x63, 0x01, 0x94, 0x9a, 0x99, 0x05, 0x63, 0xda, 0xea, 0xf1,
0x98, 0xfd, 0x26, 0xd2, 0xd9, 0x8b, 0x35, 0xec, 0xcb, 0x0b, 0x43, 0xb8,
0x8e, 0x84, 0xb8, 0x09, 0x93, 0x81, 0xe8, 0xac, 0x6f, 0x3c, 0x7c, 0x95,
0x81, 0x45, 0xc4, 0xd9, 0x94, 0x08, 0x09, 0x8f, 0x91, 0x17, 0x65, 0x4c,
0xff, 0x6e, 0xbc, 0x51, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x0d, 0x9d, 0xd8,
0xbd, 0xaf, 0x56, 0xe0, 0xe3, 0x1f, 0x85, 0xd7, 0xce, 0x72, 0x02, 0x38,
0xf2, 0x0f, 0x9c, 0x27, 0x9e, 0xc4, 0x1d, 0x60, 0x00, 0x8d, 0x02, 0x19,
0xe5, 0xdf, 0xdb, 0x8e, 0xc5, 0xfb, 0x61, 0x8e, 0xe6, 0xb8, 0xfc, 0x07,
0x3c, 0xd1, 0x1b, 0x16, 0x7c, 0x83, 0x3c, 0x37, 0xf5, 0x26, 0xb2, 0xbd,
0x22, 0xf2, 0x4d, 0x19, 0x33, 0x11, 0xc5, 0xdd, 0xf9, 0xdb, 0x4e, 0x48,
0x52, 0xd8, 0xe6, 0x4b, 0x15, 0x90, 0x68, 0xbe, 0xca, 0xc1, 0x7c, 0xd3,
0x51, 0x6b, 0x45, 0x46, 0x54, 0x11, 0x1a, 0x71, 0xd3, 0xcd, 0x6b, 0x8f,
0x79, 0x22, 0x83, 0x02, 0x08, 0x4f, 0xba, 0x6a, 0x98, 0xed, 0x32, 0xd8,
0xb4, 0x5b, 0x51, 0x88, 0x53, 0xec, 0x2c, 0x7e, 0xa4, 0x89, 0xdc, 0xbf,
0xf9, 0x0d, 0x32, 0xc8, 0xc3, 0xec, 0x6d, 0x2e, 0xf1, 0xbc, 0x70, 0x4e,
0xf6, 0x9e, 0xbc, 0x31, 0x02, 0x81, 0x81, 0x00, 0xd3, 0x35, 0x1b, 0x19,
0x75, 0x3f, 0x61, 0xf2, 0x55, 0x03, 0xce, 0x25, 0xa9, 0xdf, 0x0c, 0x0a,
0x3b, 0x47, 0x42, 0xdc, 0x38, 0x4b, 0x13, 0x4d, 0x1f, 0x86, 0x58, 0x4f,
0xd8, 0xee, 0xfa, 0x76, 0x15, 0xfb, 0x6e, 0x55, 0x31, 0xf2, 0xd2, 0x62,
0x32, 0xa5, 0xc4, 0x23, 0x5e, 0x08, 0xa9, 0x83, 0x07, 0xac, 0x8c, 0xa3,
0x7e, 0x18, 0xc0, 0x1c, 0x57, 0x63, 0x8d, 0x05, 0x17, 0x47, 0x1b, 0xd3,
0x74, 0x73, 0x20, 0x04, 0xfb, 0xc8, 0x1a, 0x43, 0x04, 0x36, 0xc8, 0x19,
0xbe, 0xdc, 0xa6, 0xe5, 0x0f, 0x25, 0x62, 0x24, 0x96, 0x92, 0xb6, 0xb3,
0x97, 0xad, 0x57, 0x9a, 0x90, 0x37, 0x4e, 0x31, 0x44, 0x74, 0xfa, 0x7c,
0xb4, 0xea, 0xfc, 0x15, 0xa7, 0xb0, 0x51, 0xcc, 0xee, 0x1e, 0xed, 0x5b,
0x98, 0x18, 0x0e, 0x65, 0xb6, 0x4b, 0x69, 0x0b, 0x21, 0xdc, 0x86, 0x17,
0x6e, 0xc8, 0xee, 0x24};
static const unsigned char kTestRsaPrivateKey4CarmichaelTotient_2048[] = {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xb5, 0xed, 0x90, 0x77, 0xfe, 0xb4, 0xac, 0x2c, 0x7a, 0x53, 0x0a, 0xe0,
0x94, 0x87, 0xfe, 0xc7, 0xc4, 0xa8, 0x3f, 0x09, 0x5b, 0xdd, 0xa7, 0x6e,
0x70, 0xc9, 0xf0, 0xef, 0x9e, 0x47, 0xad, 0xcf, 0xbe, 0xdc, 0x9b, 0x89,
0xc7, 0xbd, 0xb5, 0x2f, 0xa9, 0x43, 0x97, 0xd5, 0x5b, 0xae, 0x73, 0x46,
0xa9, 0x10, 0x47, 0x67, 0x35, 0xa0, 0x6e, 0xfc, 0xfb, 0x45, 0xf8, 0x85,
0xb0, 0xf1, 0xd3, 0x67, 0x84, 0x91, 0x03, 0x1b, 0x90, 0xb1, 0x18, 0x12,
0xa4, 0x15, 0x7a, 0x65, 0xfa, 0x74, 0x4f, 0x73, 0x34, 0x70, 0x9b, 0x64,
0x91, 0x1f, 0x89, 0x4f, 0x40, 0x2d, 0x37, 0x2f, 0xbf, 0x2b, 0x1e, 0x54,
0x95, 0x7c, 0x16, 0x14, 0xd3, 0x60, 0xf4, 0xd7, 0x86, 0xf7, 0x0c, 0x2c,
0xbb, 0x3f, 0xe7, 0x49, 0xdf, 0x74, 0x8b, 0xc9, 0x8f, 0x7c, 0x22, 0x23,
0xd9, 0xbd, 0x2a, 0x57, 0xfe, 0xfb, 0x7a, 0x77, 0x91, 0xce, 0xa9, 0xd8,
0xa7, 0xfb, 0xf5, 0xe7, 0x39, 0xbe, 0xfb, 0xf5, 0x47, 0x57, 0x48, 0xe7,
0x71, 0x37, 0xda, 0x53, 0xe7, 0x89, 0xd3, 0x37, 0x31, 0x98, 0xba, 0xd8,
0xd0, 0xd9, 0x74, 0xb2, 0xda, 0x06, 0x99, 0x3b, 0x97, 0x87, 0xc4, 0x22,
0x3c, 0xf7, 0xa3, 0x13, 0x84, 0x49, 0x27, 0x74, 0x50, 0x03, 0x51, 0xea,
0xc9, 0x57, 0xeb, 0x16, 0xa9, 0x7a, 0xea, 0x3c, 0x26, 0xda, 0xcb, 0xc6,
0x86, 0x85, 0xfc, 0xd0, 0x73, 0x26, 0xce, 0xe8, 0xd9, 0x92, 0x09, 0xaf,
0x68, 0x0c, 0x01, 0x8d, 0x95, 0xfd, 0x8d, 0x01, 0xde, 0x26, 0x0f, 0x25,
0xb9, 0xd5, 0x80, 0x99, 0x62, 0xb1, 0x71, 0xcd, 0xa1, 0x5f, 0x52, 0xab,
0x97, 0x97, 0x3f, 0xa7, 0x93, 0x40, 0x89, 0x4f, 0xbc, 0x7d, 0x99, 0x7a,
0x7e, 0x35, 0xa5, 0xfc, 0x74, 0xfb, 0xe4, 0x5a, 0x0b, 0xed, 0xf0, 0xef,
0x65, 0xed, 0x22, 0x95, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x35, 0x4a, 0x9d, 0x36, 0xa1, 0x3c, 0x50, 0x71, 0x08, 0xf6, 0x19,
0x6a, 0x16, 0xe8, 0x4d, 0x68, 0x3c, 0x41, 0xa2, 0x91, 0x7d, 0xc1, 0x0c,
0xa2, 0x2b, 0xd4, 0xe3, 0xc8, 0x75, 0x3f, 0x7e, 0xf9, 0x2b, 0x6a, 0x18,
0xff, 0xbf, 0xac, 0x61, 0x0e, 0x50, 0x91, 0x55, 0xc1, 0x30, 0x85, 0x86,
0x0c, 0x0d, 0x4b, 0x10, 0xf7, 0x79, 0x3c, 0x81, 0x36, 0x86, 0xee, 0x84,
0xb1, 0xb8, 0xd6, 0xe5, 0xbb, 0xdd, 0x97, 0xd2, 0xe6, 0xb8, 0xb8, 0x3f,
0x9a, 0x7a, 0x49, 0x36, 0x5c, 0xf8, 0x04, 0x29, 0x1f, 0xd0, 0x9d, 0x29,
0xcf, 0xc8, 0x39, 0x0a, 0x32, 0x56, 0x54, 0xc8, 0x65, 0x2a, 0xa5, 0x19,
0x51, 0xe2, 0xa6, 0x02, 0x1b, 0xe0, 0x9d, 0x76, 0xab, 0x49, 0xc4, 0x45,
0x63, 0x37, 0x08, 0xad, 0x9a, 0x34, 0xa4, 0x41, 0xac, 0x6d, 0xe5, 0x09,
0x65, 0x22, 0x0b, 0xa9, 0x03, 0x34, 0xd4, 0x7a, 0x97, 0x5c, 0x5d, 0xdc,
0xa3, 0xae, 0xfd, 0xe8, 0xd6, 0xe8, 0xf8, 0x52, 0x44, 0x9c, 0xf6, 0x00,
0xe3, 0x8e, 0xad, 0xee, 0xa3, 0x82, 0x8a, 0x85, 0x07, 0x8b, 0x46, 0x12,
0x0f, 0xa1, 0xca, 0x07, 0x0d, 0x50, 0x02, 0x96, 0x71, 0x2f, 0x1b, 0x2b,
0x59, 0x17, 0x95, 0xec, 0x90, 0xa6, 0xb9, 0x05, 0xff, 0xa2, 0x25, 0x75,
0xc5, 0x57, 0x42, 0x37, 0x12, 0xa0, 0xb6, 0x09, 0xa1, 0xe0, 0xef, 0x70,
0x85, 0xa7, 0x39, 0x47, 0xb1, 0x72, 0x78, 0x0d, 0xf4, 0x4a, 0xa7, 0xca,
0x92, 0x68, 0x2c, 0xe8, 0x53, 0x54, 0x52, 0xe2, 0x21, 0xce, 0xaf, 0x7e,
0x56, 0x05, 0x74, 0xe1, 0xb7, 0x18, 0xed, 0x7f, 0x83, 0xf6, 0x7d, 0x99,
0x33, 0xf9, 0x60, 0x24, 0xae, 0x59, 0x09, 0xc0, 0x95, 0x90, 0x5a, 0x19,
0x25, 0xb0, 0x79, 0xfd, 0x0b, 0x2c, 0x73, 0x85, 0xc5, 0xa0, 0xe5, 0x7b,
0x3a, 0x47, 0xce, 0x8d, 0x03, 0x02, 0x81, 0x81, 0x00, 0xe2, 0xd7, 0xeb,
0x7f, 0xc1, 0x1f, 0x13, 0x8f, 0x52, 0x49, 0xa2, 0x83, 0x22, 0xb7, 0x3d,
0x93, 0xfe, 0xe7, 0x20, 0x03, 0xf6, 0x6c, 0xd8, 0x95, 0x25, 0xef, 0x5f,
0xa4, 0xd4, 0x8f, 0xb1, 0x38, 0x39, 0x7c, 0xe0, 0xdd, 0xff, 0x56, 0xa7,
0xdf, 0x59, 0xe1, 0x26, 0x36, 0x72, 0x78, 0xdf, 0xd4, 0x19, 0xc0, 0x37,
0x58, 0x75, 0x85, 0xdd, 0x8b, 0x2e, 0x73, 0xfa, 0xf5, 0x65, 0x93, 0xc7,
0x36, 0x3d, 0xb7, 0x8e, 0xa9, 0x5e, 0x41, 0x71, 0x55, 0x1d, 0x22, 0x83,
0x13, 0x91, 0x76, 0xa4, 0x80, 0xa0, 0xac, 0xf6, 0xd5, 0xbb, 0x6a, 0xf3,
0x47, 0x01, 0x81, 0x3d, 0x34, 0xd6, 0x32, 0x49, 0xb2, 0xc9, 0xa7, 0xb3,
0x93, 0x64, 0x47, 0x6d, 0x30, 0x8b, 0x23, 0xbd, 0xf0, 0xe8, 0x3c, 0xb5,
0x4e, 0x33, 0x74, 0x4b, 0x60, 0x38, 0x25, 0x89, 0xaf, 0xf8, 0x86, 0x53,
0x73, 0x62, 0x74, 0x35, 0xb7, 0x02, 0x81, 0x81, 0x00, 0xcd, 0x4f, 0xbd,
0xe1, 0x43, 0xb4, 0xfe, 0x9a, 0x50, 0xb8, 0xeb, 0xf3, 0xd6, 0x3f, 0x2a,
0xbe, 0x19, 0x7a, 0x2c, 0xf4, 0x63, 0x35, 0x29, 0x47, 0x39, 0x17, 0xb4,
0xc7, 0x58, 0xc0, 0x5a, 0xbf, 0x5c, 0xa4, 0xcf, 0x9e, 0x4b, 0xad, 0x5a,
0x95, 0xfd, 0xfa, 0x50, 0xbe, 0x54, 0x12, 0xbe, 0xd8, 0x8e, 0xaf, 0x8b,
0xb2, 0x15, 0xa1, 0xb5, 0x78, 0x03, 0xa6, 0x3b, 0x18, 0x13, 0x1d, 0xfe,
0x38, 0xb7, 0x65, 0x1e, 0x20, 0x39, 0xa9, 0x25, 0x37, 0xed, 0xe8, 0x5b,
0xc7, 0xd0, 0x60, 0xe2, 0x1f, 0xf2, 0x06, 0x5d, 0x3c, 0x5c, 0x36, 0xe0,
0xc6, 0x83, 0x52, 0xd3, 0xd3, 0x3f, 0x7c, 0x43, 0x82, 0x4a, 0x13, 0xf8,
0x8d, 0x48, 0x03, 0x4f, 0xb8, 0xad, 0x64, 0x85, 0xa9, 0xee, 0xde, 0x3d,
0x0c, 0x23, 0xb6, 0xe9, 0x8d, 0xad, 0x02, 0x62, 0x32, 0x58, 0x39, 0xbf,
0x5f, 0x3c, 0x6c, 0x0a, 0x13, 0x02, 0x81, 0x80, 0x7f, 0x87, 0x3c, 0x12,
0x3a, 0x94, 0x29, 0xfe, 0xed, 0x18, 0x10, 0x91, 0x00, 0xb7, 0x5b, 0x9b,
0x14, 0x37, 0x03, 0xbc, 0xb6, 0x91, 0x42, 0xc1, 0xb6, 0xed, 0xf8, 0x2b,
0x46, 0x84, 0xf1, 0xf0, 0xd6, 0x00, 0xea, 0xba, 0x63, 0x8e, 0x68, 0x1a,
0x1d, 0x01, 0x82, 0xe6, 0x21, 0x3c, 0xeb, 0x38, 0xe6, 0xb1, 0x35, 0x6c,
0x39, 0xc5, 0xe4, 0x63, 0x16, 0xde, 0x85, 0x3b, 0xe8, 0xbb, 0x47, 0xc7,
0xaa, 0xb2, 0xc3, 0x35, 0x5c, 0x94, 0x16, 0x0e, 0xef, 0xae, 0x33, 0x5a,
0x90, 0xf0, 0xce, 0x52, 0xb2, 0x02, 0x0b, 0x52, 0xe5, 0x66, 0x9f, 0x16,
0x50, 0x36, 0x44, 0x1e, 0xac, 0x3c, 0xe1, 0x49, 0xee, 0x2c, 0xa5, 0xbc,
0x3b, 0x28, 0x1c, 0xae, 0xa9, 0xca, 0x92, 0x42, 0x19, 0x8d, 0xe7, 0xaf,
0xeb, 0x25, 0x7a, 0x2a, 0xc1, 0xe5, 0xf8, 0x9e, 0x41, 0x6d, 0xe3, 0x04,
0x7f, 0x59, 0x2d, 0xc9, 0x02, 0x81, 0x81, 0x00, 0xbe, 0xc3, 0x51, 0xdd,
0x25, 0x48, 0xdd, 0xab, 0xca, 0x47, 0x17, 0xcd, 0x57, 0x0b, 0x18, 0x0e,
0xcb, 0xa3, 0x4e, 0x73, 0xc0, 0x5e, 0x1b, 0xbd, 0x76, 0x99, 0xc5, 0x39,
0xd8, 0x07, 0xda, 0x09, 0xa5, 0xed, 0xe8, 0x8e, 0xdf, 0x27, 0xf2, 0x5c,
0x1d, 0x40, 0xe0, 0x97, 0x07, 0x8c, 0xe7, 0x50, 0x55, 0xbb, 0x5c, 0x24,
0x1a, 0x9f, 0x46, 0xfa, 0x7d, 0x01, 0x8e, 0x34, 0xbf, 0x46, 0x85, 0xf8,
0x72, 0xc6, 0x7c, 0x68, 0x5a, 0xcb, 0x03, 0xae, 0xe4, 0xd9, 0x99, 0xb5,
0x9d, 0xb2, 0xf7, 0x47, 0xd1, 0x5c, 0x02, 0x73, 0x5c, 0x07, 0x0d, 0x70,
0xc5, 0x82, 0x47, 0x19, 0x28, 0x0a, 0xb0, 0xbb, 0x35, 0x53, 0x3b, 0x05,
0x22, 0x9d, 0x19, 0x0c, 0xb1, 0xe7, 0x0d, 0x9e, 0xa8, 0x38, 0x4c, 0x26,
0xa4, 0x64, 0x86, 0xbb, 0x41, 0xbe, 0x4e, 0x39, 0x12, 0xea, 0x8d, 0x1a,
0xd3, 0x0c, 0x5b, 0x8b, 0x02, 0x81, 0x81, 0x00, 0xa9, 0x2d, 0x4b, 0x43,
0x55, 0x7f, 0x90, 0xb4, 0xea, 0xf9, 0xc2, 0x4c, 0x8c, 0x4d, 0xee, 0x62,
0x85, 0xd2, 0x58, 0x71, 0xc7, 0xb3, 0xfb, 0x80, 0x37, 0xd9, 0xc5, 0x20,
0x61, 0xeb, 0x39, 0x7f, 0x4d, 0x09, 0x7c, 0x32, 0x46, 0x8b, 0x49, 0xa4,
0xd6, 0x99, 0xb4, 0xdc, 0xb6, 0xe3, 0x2a, 0x77, 0x53, 0xa3, 0xee, 0xdb,
0x4d, 0xf9, 0x59, 0x20, 0x8a, 0x83, 0x94, 0x29, 0x72, 0x96, 0x76, 0x36,
0x63, 0xbe, 0xa1, 0xe8, 0x94, 0xf9, 0x50, 0x71, 0x56, 0xaa, 0xeb, 0x90,
0x06, 0xf2, 0x05, 0xb1, 0x19, 0xf0, 0x13, 0x89, 0x2d, 0x7b, 0x94, 0xb7,
0xf2, 0x18, 0xfa, 0x52, 0x09, 0x82, 0x99, 0x20, 0xe9, 0x7a, 0x1c, 0x68,
0xfe, 0x44, 0xe5, 0xf8, 0xc5, 0xd3, 0xc6, 0x66, 0x3d, 0xe3, 0x43, 0xc3,
0x63, 0x81, 0xff, 0x78, 0x91, 0x5c, 0x48, 0x16, 0xbe, 0x92, 0x90, 0x2f,
0x10, 0x9f, 0x2d, 0x17};
RsaTestKeys::RsaTestKeys()
: private_key_1_3072_bits_(std::begin(kTestRsaPrivateKey1_3072),
std::end(kTestRsaPrivateKey1_3072)),
public_key_1_3072_bits_(std::begin(kTestRsaPublicKey1_3072),
std::end(kTestRsaPublicKey1_3072)),
private_key_2_2048_bits_(std::begin(kTestRsaPrivateKey2_2048),
std::end(kTestRsaPrivateKey2_2048)),
public_key_2_2048_bits_(std::begin(kTestRsaPublicKey2_2048),
std::end(kTestRsaPublicKey2_2048)),
private_key_3_2048_bits_(std::begin(kTestRsaPrivateKey3_2048),
std::end(kTestRsaPrivateKey3_2048)),
public_key_3_2048_bits_(std::begin(kTestRsaPublicKey3_2048),
std::end(kTestRsaPublicKey3_2048)),
private_key_2_carmichael_totient_2048_bits_(
std::begin(kTestRsaPrivateKey2CarmichaelTotient_2048),
std::end(kTestRsaPrivateKey2CarmichaelTotient_2048)),
private_key_3_carmichael_totient_2048_bits_(
std::begin(kTestRsaPrivateKey3CarmichaelTotient_2048),
std::end(kTestRsaPrivateKey3CarmichaelTotient_2048)),
private_key_4_carmichael_totient_2048_bits_(
std::begin(kTestRsaPrivateKey4CarmichaelTotient_2048),
std::end(kTestRsaPrivateKey4CarmichaelTotient_2048)) {}
} // namespace widevine

View File

@@ -0,0 +1,92 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA keys generated using fake_prng for purposes of testing.
#ifndef WHITEBOX_CRYPTO_UTILS_RSA_TEST_KEYS_H_
#define WHITEBOX_CRYPTO_UTILS_RSA_TEST_KEYS_H_
#include <string>
namespace widevine {
// Container for test RSA keys
//
// Except for the keys noted below, these keys were generated using Euler's
// Totient.
//
class RsaTestKeys {
public:
RsaTestKeys();
// Returns 3072-bit private RSA test key 1
const std::string& private_test_key_1_3072_bits() const {
return private_key_1_3072_bits_;
}
// Returns 3072-bit public RSA test key 1
const std::string& public_test_key_1_3072_bits() const {
return public_key_1_3072_bits_;
}
// Returns 2048-bit private RSA test key 2
const std::string& private_test_key_2_2048_bits() const {
return private_key_2_2048_bits_;
}
// Returns 2048-bit public RSA test key 2
const std::string& public_test_key_2_2048_bits() const {
return public_key_2_2048_bits_;
}
// Returns 2048-bit private RSA test key 3
const std::string& private_test_key_3_2048_bits() const {
return private_key_3_2048_bits_;
}
// Returns 2048-bit public RSA test key 3
const std::string& public_test_key_3_2048_bits() const {
return public_key_3_2048_bits_;
}
// This key was converted to a Carmichael totient version from the original
// private_key_2_2048_bits_.
const std::string& private_test_key_2_carmichael_totient_2048_bits() const {
return private_key_2_carmichael_totient_2048_bits_;
}
// This key was converted to a Carmichael totient version from the original
// private_key_3_2048_bits_.
const std::string& private_test_key_3_carmichael_totient_2048_bits() const {
return private_key_3_carmichael_totient_2048_bits_;
}
// This key has been created using the Carmichael totient. This is
// useful for testing with some RSA implementations that had challenges
// with keys generated this way.
const std::string& private_test_key_4_carmichael_totient_2048_bits() const {
return private_key_4_carmichael_totient_2048_bits_;
}
private:
RsaTestKeys(const RsaTestKeys&) = delete;
RsaTestKeys& operator=(const RsaTestKeys&) = delete;
std::string private_key_1_3072_bits_;
std::string public_key_1_3072_bits_;
std::string private_key_2_2048_bits_;
std::string public_key_2_2048_bits_;
std::string private_key_3_2048_bits_;
std::string public_key_3_2048_bits_;
// Tests keys that use the Carmichael totient to calculate d.
std::string private_key_2_carmichael_totient_2048_bits_;
std::string private_key_3_carmichael_totient_2048_bits_;
std::string private_key_4_carmichael_totient_2048_bits_;
};
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_RSA_TEST_KEYS_H_

454
crypto_utils/rsa_util.cc Normal file
View File

@@ -0,0 +1,454 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA utility functions for serializing and deserializing RSA keys,
// encryption, and signing.
#include "crypto_utils/rsa_util.h"
#include <limits.h>
#include <cstring>
#include <memory>
#include "base/logging.h"
#include "third_party/boringssl/src/include/openssl/pem.h"
#include "third_party/boringssl/src/include/openssl/x509.h"
#include "crypto_utils/private_key_util.h"
namespace {
int BigNumGreaterThanPow2(const BIGNUM* b, int n) {
if (BN_is_negative(b) || n == INT_MAX) {
return 0;
}
int b_bits = BN_num_bits(b);
return b_bits > n + 1 || (b_bits == n + 1 && !BN_is_pow2(b));
}
} // anonymous namespace
namespace widevine {
namespace rsa_util {
bool SerializeRsaPrivateKey(const RSA* private_key,
std::string* serialized_private_key) {
return private_key_util::SerializeKey<RSA>(private_key, i2d_RSAPrivateKey_bio,
serialized_private_key);
}
bool DeserializeRsaPrivateKey(const std::string& serialized_private_key,
RSA** private_key) {
return private_key_util::DeserializeKey<RSA>(
serialized_private_key, d2i_RSAPrivateKey_bio, private_key);
}
bool SerializeRsaPublicKey(const RSA* public_key,
std::string* serialized_public_key) {
return private_key_util::SerializeKey<RSA>(public_key, i2d_RSAPublicKey_bio,
serialized_public_key);
}
bool DeserializeRsaPublicKey(const std::string& serialized_public_key,
RSA** public_key) {
return private_key_util::DeserializeKey<RSA>(
serialized_public_key, d2i_RSAPublicKey_bio, public_key);
}
bool SerializePrivateKeyInfo(const RSA* private_key,
std::string* serialized_private_key) {
if (private_key == nullptr) {
LOG(ERROR) << "Private RSA key is nullptr.";
return false;
}
if (serialized_private_key == nullptr) {
LOG(ERROR) << "Pointer to hold serialized PrivateKeyInfo is nullptr.";
return false;
}
// The following method of serializing a PKCS#8 PrivateKeyInfo object
// was obtained from analyzing the openssl utility code, as the official
// mechanism via i2d_PKCS8PrivateKey_bio is broken in the current openssl
// version (1.0.0c). Please refer to b/8560683.
EVP_PKEY* evp = EVP_PKEY_new();
if (evp == nullptr) {
LOG(ERROR) << "EVP_PKEY_new returned nullptr.";
return false;
}
bool success = false;
PKCS8_PRIV_KEY_INFO* pkcs8_pki = nullptr;
BIO* bio = nullptr;
if (EVP_PKEY_set1_RSA(evp, const_cast<RSA*>(private_key)) == 0) {
LOG(ERROR) << "EVP_PKEY_set1_RSA failed.";
goto cleanup;
}
pkcs8_pki = EVP_PKEY2PKCS8(evp);
if (pkcs8_pki == nullptr) {
LOG(ERROR) << "EVP_PKEY2PKCS8 returned nullptr.";
goto cleanup;
}
bio = BIO_new(BIO_s_mem());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new returned nullptr.";
goto cleanup;
}
if (i2d_PKCS8_PRIV_KEY_INFO_bio(bio, pkcs8_pki) == 0) {
LOG(ERROR) << "i2d_PKCS8_PRIV_KEY_INFO_bio failed.";
goto cleanup;
}
{
int serialized_size = BIO_pending(bio);
serialized_private_key->assign(serialized_size, 0);
if (BIO_read(bio, &(*serialized_private_key)[0], serialized_size) !=
serialized_size) {
LOG(ERROR) << "BIO_read failed.";
goto cleanup;
}
}
success = true;
cleanup:
if (bio != nullptr) {
BIO_free(bio);
}
if (pkcs8_pki != nullptr) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
EVP_PKEY_free(evp);
return success;
}
bool DeserializePrivateKeyInfo(const std::string& serialized_private_key,
RSA** private_key) {
if (serialized_private_key.empty()) {
LOG(ERROR) << "Serialized PrivateKeyInfo is empty.";
return false;
}
if (private_key == nullptr) {
LOG(ERROR) << "Pointer to hold new RSA private key is nullptr.";
return false;
}
// The following method of deserializing a PKCS#8 PrivateKeyInfo object
// was obtained from analyzing the openssl utility code, as the official
// mechanism via d2i_PKCS8PrivateKey_bio is broken in the current openssl
// version (1.0.0c). Please refer to b/8560683.
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_private_key.data()),
serialized_private_key.size());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new_mem_buf returned nullptr";
return false;
}
bool success = false;
EVP_PKEY* evp = nullptr;
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr);
if (pkcs8_pki == nullptr) {
LOG(ERROR) << "d2i_PKCS8_PRIV_KEY_INFO_bio returned nullptr.";
goto cleanup;
}
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == nullptr) {
LOG(ERROR) << "EVP_PKCS82PKEY returned nullptr.";
goto cleanup;
}
*private_key = EVP_PKEY_get1_RSA(evp);
if (*private_key == nullptr) {
LOG(ERROR) << "PrivateKeyInfo did not contain an RSA key.";
goto cleanup;
}
success = true;
cleanup:
if (evp != nullptr) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != nullptr) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
return success;
}
bool RsaPrivateKeyToPrivateKeyInfo(const std::string& rsa_private_key,
std::string* private_key_info) {
RSA* key = nullptr;
if (DeserializeRsaPrivateKey(rsa_private_key, &key)) {
bool success = SerializePrivateKeyInfo(key, private_key_info);
RSA_free(key);
return success;
}
return false;
}
bool PrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
std::string* rsa_private_key) {
RSA* key = nullptr;
if (DeserializePrivateKeyInfo(private_key_info, &key)) {
bool success = SerializeRsaPrivateKey(key, rsa_private_key);
RSA_free(key);
return success;
}
return false;
}
bool SerializeEncryptedPrivateKeyInfo(const RSA* private_key,
const std::string& passphrase,
std::string* serialized_private_key) {
if (private_key == nullptr) {
LOG(ERROR) << "Private RSA key is nullptr.";
return false;
}
if (passphrase.empty()) {
LOG(ERROR) << "Passphrase for RSA key encryption is empty.";
return false;
}
if (serialized_private_key == nullptr) {
LOG(ERROR)
<< "Pointer to hold serialized EncryptedPrivateKeyInfo is nullptr.";
return false;
}
EVP_PKEY* evp = EVP_PKEY_new();
if (evp == nullptr) {
LOG(ERROR) << "EVP_PKEY_new returned nullptr.";
return false;
}
bool success = false;
BIO* bio = nullptr;
if (EVP_PKEY_set1_RSA(evp, const_cast<RSA*>(private_key)) == 0) {
LOG(ERROR) << "EVP_PKEY_set1_RSA failed.";
goto cleanup;
}
bio = BIO_new(BIO_s_mem());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new returned nullptr.";
goto cleanup;
}
if (i2d_PKCS8PrivateKey_bio(bio, evp, EVP_aes_256_cbc(),
const_cast<char*>(passphrase.data()),
passphrase.size(), nullptr, nullptr) == 0) {
LOG(ERROR) << "i2d_PKCS8PrivateKey_bio failed.";
goto cleanup;
}
{
int serialized_size = BIO_pending(bio);
serialized_private_key->assign(serialized_size, 0);
if (BIO_read(bio, &(*serialized_private_key)[0], serialized_size) !=
serialized_size) {
LOG(ERROR) << "BIO_read failed.";
goto cleanup;
}
}
success = true;
cleanup:
if (bio != nullptr) {
BIO_free(bio);
}
EVP_PKEY_free(evp);
return success;
}
namespace {
// Password retrieval function used by DeserializeEncryptedPrivateKeyInfo below.
int get_password(char* buf, int size, int rwflag, void* u) {
CHECK(buf);
CHECK(u);
const std::string* pass(static_cast<const std::string*>(u));
if (!pass->empty() && size >= static_cast<int>(pass->size())) {
memcpy(buf, pass->data(), pass->size());
return pass->size();
}
return 0;
}
} // namespace
bool DeserializeEncryptedPrivateKeyInfo(
const std::string& serialized_private_key,
const std::string& passphrase,
RSA** private_key) {
if (serialized_private_key.empty()) {
LOG(ERROR) << "Serialized RSAEncryptedPrivateKeyInfo is empty.";
return false;
}
if (passphrase.empty()) {
LOG(ERROR) << "Passphrase for RSA key decryption is empty.";
return false;
}
if (private_key == nullptr) {
LOG(ERROR) << "Pointer to hold new RSA private key is nullptr.";
return false;
}
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_private_key.data()),
serialized_private_key.size());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new_mem_buf returned nullptr";
return false;
}
bool success = false;
EVP_PKEY* evp = d2i_PKCS8PrivateKey_bio(
bio, nullptr, get_password, const_cast<std::string*>(&passphrase));
if (evp == nullptr) {
LOG(ERROR) << "d2i_PKCS8PrivateKey_bio returned nullptr.";
goto cleanup;
}
*private_key = EVP_PKEY_get1_RSA(evp);
if (*private_key == nullptr) {
LOG(ERROR) << "EncryptedPrivateKeyInfo did not contain an RSA key.";
goto cleanup;
}
success = true;
cleanup:
if (evp != nullptr) {
EVP_PKEY_free(evp);
}
BIO_free(bio);
return success;
}
bool RsaPrivateKeyToEncryptedPrivateKeyInfo(const std::string& rsa_private_key,
const std::string& passphrase,
std::string* private_key_info) {
RSA* key = nullptr;
if (DeserializeRsaPrivateKey(rsa_private_key, &key)) {
bool success =
SerializeEncryptedPrivateKeyInfo(key, passphrase, private_key_info);
RSA_free(key);
return success;
}
return false;
}
bool EncryptedPrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
const std::string& passphrase,
std::string* rsa_private_key) {
RSA* key = nullptr;
if (DeserializeEncryptedPrivateKeyInfo(private_key_info, passphrase, &key)) {
bool success = SerializeRsaPrivateKey(key, rsa_private_key);
RSA_free(key);
return success;
}
return false;
}
bool ConvertToEulerTotient(RSA* rsa) {
// RSA key generation requires computing e (public exponent) and d (private
// exponent), such that m^(e * d) = 1 (mod n) for all m coprime to n.
// BoringSSL previously computed this by taking the inverse of e modulo the
// Euler totient, (p - 1) * (q - 1). However, it now uses the Carmichael
// totient, lcm(p - 1, q - 1). These two methods produce equivalent RSA keys.
//
// This breaks some vendors' RSA code which use a custom RSA format (rather
// than the standard one in RFC 8017) which omits most of the required
// parameters. They then attempt to recover those parameters, but their
// recovery algorithm breaks when using the Carmichael totient. To work around
// this bug, re-compute the private exponent against the Euler totient.
const BIGNUM *e, *p, *q;
RSA_get0_key(rsa, nullptr /* n */, &e, nullptr /* d */);
RSA_get0_factors(rsa, &p, &q);
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
bssl::UniquePtr<BIGNUM> pm1(BN_new());
bssl::UniquePtr<BIGNUM> qm1(BN_new());
bssl::UniquePtr<BIGNUM> totient(BN_new());
bssl::UniquePtr<BIGNUM> d(BN_new());
if (!ctx || !pm1 || !qm1 || !totient || !d ||
!BN_sub(pm1.get(), p, BN_value_one()) ||
!BN_sub(qm1.get(), q, BN_value_one()) ||
!BN_mul(totient.get(), pm1.get(), qm1.get(), ctx.get()) ||
!BN_mod_inverse(d.get(), e, totient.get(), ctx.get())) {
return false;
}
// Perform a sanity check that d is still valid after conversion.
// d > 2 ^ (nlen / 2) per Appendix B 3.1 in FIPS 186/4.
int prime_bits = (8 * RSA_size(rsa)) / 2;
if (!BigNumGreaterThanPow2(d.get(), prime_bits)) {
return false;
}
if (!RSA_set0_key(rsa, nullptr /* n */, nullptr /* e */, d.get())) {
return false;
}
d.release(); // RSA_set0_key takes ownership on success.
if (!RSA_check_key(rsa)) {
return false;
}
return true;
}
bool ConvertToEulerTotient(const std::string& private_key,
std::string* euler_private_key) {
CHECK(euler_private_key);
RSA* rsa_ptr;
if (!rsa_util::DeserializeRsaPrivateKey(private_key, &rsa_ptr)) {
return false;
}
bssl::UniquePtr<RSA> rsa(rsa_ptr);
if (!rsa_util::ConvertToEulerTotient(rsa.get()) ||
!rsa_util::SerializeRsaPrivateKey(rsa.get(), euler_private_key)) {
return false;
}
return true;
}
bool ConvertToCarmichaelTotient(RSA* rsa) {
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
bssl::UniquePtr<BIGNUM> pm1(BN_new());
bssl::UniquePtr<BIGNUM> qm1(BN_new());
bssl::UniquePtr<BIGNUM> gcd(BN_new());
bssl::UniquePtr<BIGNUM> totient(BN_new());
bssl::UniquePtr<BIGNUM> d(BN_new());
// This calculates d = e^-1 (mod lcm(p-1, q-1)).
// This is equivalent to what is used in RSA_generate_key in BoringSSL.
if (!BN_sub(pm1.get(), rsa->p, BN_value_one()) ||
!BN_sub(qm1.get(), rsa->q, BN_value_one()) ||
!BN_mul(totient.get(), pm1.get(), qm1.get(), ctx.get()) ||
!BN_gcd(gcd.get(), pm1.get(), qm1.get(), ctx.get()) ||
!BN_div(totient.get(), nullptr, totient.get(), gcd.get(), ctx.get()) ||
!BN_mod_inverse(d.get(), rsa->e, totient.get(), ctx.get())) {
return false;
}
// Perform a sanity check that d is still valid after conversion.
// d > 2 ^ (nlen / 2) per Appendix B 3.1 in FIPS 186/4.
int prime_bits = (8 * RSA_size(rsa)) / 2;
if (!BigNumGreaterThanPow2(d.get(), prime_bits)) {
return false;
}
// TODO(user): Replace this with |RSA_set0_key| once BoringSSL has
// finished transitioning to the OpenSSL 1.1.0 API.
BN_free(rsa->d);
rsa->d = d.release();
if (!RSA_check_key(rsa)) {
return false;
}
return true;
}
bool ConvertToCarmichaelTotient(const std::string& private_key,
std::string* carmichael_private_key) {
CHECK(carmichael_private_key);
RSA* rsa_ptr;
if (!rsa_util::DeserializeRsaPrivateKey(private_key, &rsa_ptr)) {
return false;
}
bssl::UniquePtr<RSA> rsa(rsa_ptr);
if (!rsa_util::ConvertToCarmichaelTotient(rsa.get()) ||
!rsa_util::SerializeRsaPrivateKey(rsa.get(), carmichael_private_key)) {
return false;
}
return true;
}
} // namespace rsa_util
} // namespace widevine

210
crypto_utils/rsa_util.h Normal file
View File

@@ -0,0 +1,210 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA utility functions for serializing and deserializing RSA keys,
// encryption, and signing.
#ifndef WHITEBOX_CRYPTO_UTILS_RSA_UTIL_H_
#define WHITEBOX_CRYPTO_UTILS_RSA_UTIL_H_
#include <string>
#include "third_party/boringssl/src/include/openssl/rsa.h"
namespace widevine {
namespace rsa_util {
// Serialize RSA private key into DER encoded PKCS#1 RSAPrivateKey.
// - private_key is the RSA key to be serialized, which must not be NULL.
// - serialized_private_key is a pointer to the std::string to hold the
// serialized
// PKCS#1 RSAPrivateKey object. Caller retains ownership of the string. This
// parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializeRsaPrivateKey(const RSA* private_key,
std::string* serialized_private_key);
// Deserialize RSA private key from DER encoded PKCS#1 RSAPrivateKey.
// - serialized_private_key is the DER-encoded PKCS#1 RSAPrivateKey to be
// deserialized.
// - private_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializeRsaPrivateKey(const std::string& serialized_private_key,
RSA** private_key);
// Serialize RSA key into DER encoded PKCS#1 RSAPublicKey.
// - public_key is the RSA key to be serialized, which must not be NULL.
// - serialized_public_key is a pointer to the std::string to hold the
// serialized
// PKCS#1 RSAPublicKey object. Caller retains ownership of the string. This
// parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializeRsaPublicKey(const RSA* public_key,
std::string* serialized_public_key);
// Deserialize RSA public key from DER encoded PKCS#1 RSAPublicKey.
// - serialized_public_key is the DER-encoded PKCS#1 RSAPublicKey to be
// deserialized.
// - public_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializeRsaPublicKey(const std::string& serialized_public_key,
RSA** public_key);
// Serialize RSA private key into DER encoded PKCS#8 PrivateKeyInfo.
// - private_key is the RSA key to be serialized, which must not be NULL.
// - serialized_private_key is a pointer to the std::string to hold the
// serialized
// PKCS#8 PrivateKeyInfo object. Caller retains ownership of the string. This
// parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializePrivateKeyInfo(const RSA* private_key,
std::string* serialized_private_key);
// Deserialize RSA private key from DER encoded PKCS#8 PrivateKeyInfo.
// - serialized_private_key is the DER-encoded PKCS#8 PrivateKeyInfo to be
// deserialized.
// - private_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializePrivateKeyInfo(const std::string& serialized_private_key,
RSA** private_key);
// Convert DER-encoded PKCS#1 RSAPrivateKey to DER-encoded PKCS#8
// PrivateKeyInfo.
// - rsa_private_key is the PKCS#1 RSAPrivateKey to be converted.
// - private_key_info is a pointer to std::string to hold the PKCS#8
// PrivateKeyInfo.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool RsaPrivateKeyToPrivateKeyInfo(const std::string& rsa_private_key,
std::string* private_key_info);
// Convert DER-encoded PKCS#8 PrivateKeyInfo to DER-encoded PKCS#1
// RSAPrivateKey.
// - private_key_info is the PKCS#8 PrivateKeyInfo to be converted.
// - rsa_private_key is a pointer to std::string to hold the PKCS#1
// RSAPrivateKey.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool PrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
std::string* rsa_private_key);
// Serialize RSA private key into DER encoded PKCS#8 EncryptedPrivateKeyInfo.
// - private_key is the RSA key to be serialized, which must not be NULL.
// - passphrase is the password to use for PKCS#5 v2.0 3DES encryption.
// - serialized_private_key is a pointer to the std::string to hold the
// serialized
// PKCS#8 EncryptedPrivateKeyInfo object. Caller retains ownership of the
// string. This parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializeEncryptedPrivateKeyInfo(const RSA* private_key,
const std::string& passphrase,
std::string* serialized_private_key);
// Deserialize RSA private key from DER encoded PKCS#8 EncryptedPrivateKeyInfo.
// - serialized_private_key is the DER-encoded PKCS#8 EncryptedPrivateKeyInfo to
// be deserialized.
// - passphrase is the password to use for key decryption.
// - private_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializeEncryptedPrivateKeyInfo(
const std::string& serialized_private_key,
const std::string& passphrase,
RSA** private_key);
// Convert DER-encoded PKCS#1 RSAPrivateKey to DER-encoded PKCS#8
// EncryptedPrivateKeyInfo.
// - rsa_private_key is the PKCS#1 RSAPrivateKey to be converted.
// - passphrase is the password to use for PKCS#5 v2.1 AES-256-CBC encryption.
// - private_key_info is a pointer to std::string to hold the PKCS#8
// EncryptedPrivateKeyInfo.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool RsaPrivateKeyToEncryptedPrivateKeyInfo(const std::string& rsa_private_key,
const std::string& passphrase,
std::string* private_key_info);
// Convert DER-encoded PKCS#8 EncryptedPrivateKeyInfo to DER-encoded PKCS#1
// RSAPrivateKey.
// - private_key_info is the PKCS#8 EncryptedPrivateKeyInfo to be converted.
// - passphrase is the password to use for key decryption.
// - rsa_private_key is a pointer to std::string to hold the PKCS#1
// RSAPrivateKey.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool EncryptedPrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
const std::string& passphrase,
std::string* rsa_private_key);
// This method changes |rsa| to use the more common, but not FIPS 186-4
// compliant, computation for the RSA private exponent (d). This used to be the
// form produced by the BoringSSL method RSA_generate_key. This changed in this
// CL: https://boringssl-review.googlesource.com/c/boringssl/+/15944
//
// This method is used to produce a "backward-compatible" version. Some vendor
// RSA implementations do not handle the new computation properly.
//
// - rsa is the openssl RSA structure. Must not be null. Caller retains
// ownership.
//
// Returns true if the key was successfully updated, false otherwise.
bool ConvertToEulerTotient(RSA* rsa);
// This is wrapper to the other SwitchToEulerTotient that supports deserializing
// and serializing from and to a DER encoded PKCS#1 RSAPrivateKey.
//
// - private_key is the DER-encoded PKCS#1 RSAPrivateKey to be
// deserialized and converted.
// - euler_private_key is a pointer to the std::string to hold the converted and
// serialized PKCS#1 RSAPrivateKey object. Caller retains ownership of the
// string. This parameter must not be NULL.
// Returns true if the key was successfully updated, false otherwise.
bool ConvertToEulerTotient(const std::string& private_key,
std::string* euler_private_key);
// This method changes |rsa| to use the FIPS 186-4 compliant computation for d.
// This uses the Carmichael totient. This is equivalent to the way the key
// is generated in BoringSSL as of this change:
// https://boringssl-review.googlesource.com/c/boringssl/+/15944
//
// This method is mostly used for testing. It allows tests to convert back and
// forth between forms and verify the output.
//
// Returns true if the key can be successfully updated, false otherwise.
bool ConvertToCarmichaelTotient(RSA* rsa);
// This is wrapper to the other SwitchToCarmichaelTotient that supports
// deserializing and serializing from and to a DER encoded PKCS#1 RSAPrivateKey.
//
// - private_key is the DER-encoded PKCS#1 RSAPrivateKey to be
// deserialized and converted.
// - carmichael_private_key is a pointer to the std::string to hold the
// converted and
// serialized PKCS#1 RSAPrivateKey object. Caller retains ownership of the
// string. This parameter must not be NULL.
// Returns true if the key was successfully updated, false otherwise.
bool ConvertToCarmichaelTotient(const std::string& private_key,
std::string* carmichael_private_key);
} // namespace rsa_util
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_RSA_UTIL_H_

View File

@@ -0,0 +1,352 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit test for rsa_util RSA utilties library.
#include "crypto_utils/rsa_util.h"
#include <stddef.h>
#include <cstdint>
#include <memory>
#include "base/logging.h"
#include "testing/include/gmock/gmock.h"
#include "testing/include/gtest/gtest.h"
#include "third_party/boringssl/src/include/openssl/bn.h"
#include "crypto_utils/rsa_test_keys.h"
using ::testing::NotNull;
namespace {
const uint32_t kRsaPublicExponent = 65537;
const int kTestRsaBits = 2048;
} // anonymous namespace
namespace widevine {
namespace rsa_util {
class RsaUtilTest : public ::testing::Test {
protected:
RsaTestKeys test_keys_;
};
TEST_F(RsaUtilTest, SerializeDeserializePrivateKey) {
RSA* private_key;
std::string serialized_private_key;
// Key 1
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_1_3072_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key));
EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_1_3072_bits());
EXPECT_EQ(RSA_check_key(private_key), 1);
RSA_free(private_key);
// Key 2
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key));
EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_2_2048_bits());
EXPECT_EQ(RSA_check_key(private_key), 1);
RSA_free(private_key);
// Key 3
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_3_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key));
EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_3_2048_bits());
EXPECT_EQ(RSA_check_key(private_key), 1);
RSA_free(private_key);
// Invalid key
EXPECT_FALSE(DeserializeRsaPrivateKey("this is a bad key", &private_key));
}
TEST_F(RsaUtilTest, SerializeDeserializePublicKey) {
RSA* public_key;
std::string serialized_public_key;
// Key 1
EXPECT_TRUE(DeserializeRsaPublicKey(test_keys_.public_test_key_1_3072_bits(),
&public_key));
ASSERT_TRUE(public_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_3072_bits());
RSA_free(public_key);
// Key 2
EXPECT_TRUE(DeserializeRsaPublicKey(test_keys_.public_test_key_2_2048_bits(),
&public_key));
ASSERT_TRUE(public_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_2_2048_bits());
RSA_free(public_key);
// Key 3
EXPECT_TRUE(DeserializeRsaPublicKey(test_keys_.public_test_key_3_2048_bits(),
&public_key));
ASSERT_TRUE(public_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_3_2048_bits());
RSA_free(public_key);
// Invalid key
EXPECT_FALSE(DeserializeRsaPublicKey("this is a bad key", &public_key));
}
TEST_F(RsaUtilTest, PublicKeyExtraction) {
RSA* private_key;
std::string serialized_public_key;
// Key 1
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_1_3072_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_3072_bits());
RSA_free(private_key);
// Key 2
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_2_2048_bits());
RSA_free(private_key);
// Key 3
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_3_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_3_2048_bits());
RSA_free(private_key);
}
TEST_F(RsaUtilTest, Pkcs8PrivateKeyInfo) {
// The PKCS#1 <-> PKCS#8 conversion routines exercise all the PKCS#8
// serialization/deserialization functionality , so we test those.
std::string serialized_pkcs8;
std::string serialized_pkcs1;
// Key 1
EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo(
test_keys_.private_test_key_1_3072_bits(), &serialized_pkcs8));
EXPECT_TRUE(
PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8, &serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_1_3072_bits(), serialized_pkcs1);
// Key 2
EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), &serialized_pkcs8));
EXPECT_TRUE(
PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8, &serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), serialized_pkcs1);
// Key 3
EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo(
test_keys_.private_test_key_3_2048_bits(), &serialized_pkcs8));
EXPECT_TRUE(
PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8, &serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_3_2048_bits(), serialized_pkcs1);
}
TEST_F(RsaUtilTest, Pkcs8EncryptedPrivateKeyInfo) {
// The PKCS#1 <-> PKCS#8 conversion routines exercise all the PKCS#8
// serialization/deserialization functionality , so we test those.
std::string serialized_pkcs8;
std::string serialized_pkcs1;
std::string passphrase("passphrase");
// Key 1
EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_1_3072_bits(), passphrase,
&serialized_pkcs8));
EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(
serialized_pkcs8, passphrase, &serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_1_3072_bits(), serialized_pkcs1);
// Key 2
EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), passphrase,
&serialized_pkcs8));
EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(
serialized_pkcs8, passphrase, &serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), serialized_pkcs1);
// Key 3
EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_3_2048_bits(), passphrase,
&serialized_pkcs8));
EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(
serialized_pkcs8, passphrase, &serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_3_2048_bits(), serialized_pkcs1);
}
TEST_F(RsaUtilTest, FailOnInvalidParams) {
RSA* test_input_key = NULL;
RSA* test_output_key = NULL;
std::string test_string;
std::string pass("password");
ASSERT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &test_input_key));
ASSERT_TRUE(test_input_key != NULL);
EXPECT_FALSE(SerializeRsaPrivateKey(NULL, &test_string));
EXPECT_FALSE(SerializeRsaPrivateKey(test_input_key, NULL));
EXPECT_FALSE(SerializeRsaPublicKey(NULL, &test_string));
EXPECT_FALSE(SerializeRsaPublicKey(test_input_key, NULL));
EXPECT_FALSE(SerializePrivateKeyInfo(NULL, &test_string));
EXPECT_FALSE(SerializePrivateKeyInfo(test_input_key, NULL));
EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(NULL, pass, &test_string));
EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(test_input_key, pass, NULL));
EXPECT_FALSE(DeserializeRsaPrivateKey("", &test_output_key));
EXPECT_FALSE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), NULL));
EXPECT_FALSE(DeserializeRsaPublicKey("", &test_output_key));
EXPECT_FALSE(
DeserializeRsaPublicKey(test_keys_.public_test_key_2_2048_bits(), NULL));
EXPECT_FALSE(DeserializePrivateKeyInfo("", &test_output_key));
EXPECT_FALSE(DeserializePrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), NULL));
EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo("", pass, &test_output_key));
EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), pass, NULL));
RSA_free(test_input_key);
}
TEST_F(RsaUtilTest, Pkcs8FailOnInvalidPassword) {
RSA* test_input_key = NULL;
RSA* test_output_key = NULL;
std::string serialized_pkcs8;
std::string pass("password");
ASSERT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &test_input_key));
EXPECT_FALSE(
SerializeEncryptedPrivateKeyInfo(test_input_key, "", &serialized_pkcs8));
ASSERT_TRUE(SerializeEncryptedPrivateKeyInfo(test_input_key, pass,
&serialized_pkcs8));
EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo(serialized_pkcs8, pass + "a",
&test_output_key));
EXPECT_TRUE(DeserializeEncryptedPrivateKeyInfo(serialized_pkcs8, pass,
&test_output_key));
RSA_free(test_input_key);
RSA_free(test_output_key);
}
TEST_F(RsaUtilTest, ConvertToCarmichaelTotient_ExistingKey_Success) {
bssl::UniquePtr<RSA> original_private_key;
RSA* original_key_ptr = nullptr;
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &original_key_ptr));
original_private_key.reset(original_key_ptr);
ASSERT_THAT(original_private_key, NotNull());
bssl::UniquePtr<RSA> private_key(
RSAPrivateKey_dup(original_private_key.get()));
ASSERT_THAT(private_key, NotNull());
EXPECT_TRUE(ConvertToCarmichaelTotient(private_key.get()));
// Confirm that the key is valid and has changed from the original.
EXPECT_EQ(1, RSA_check_key(private_key.get()));
std::string serialized_carmichael_private_key;
EXPECT_TRUE(SerializeRsaPrivateKey(private_key.get(),
&serialized_carmichael_private_key));
EXPECT_NE(serialized_carmichael_private_key,
test_keys_.private_test_key_2_2048_bits());
// Convert back and make sure the serialized key matches the original.
EXPECT_TRUE(ConvertToEulerTotient(private_key.get()));
EXPECT_EQ(1, RSA_check_key(private_key.get()));
std::string serialized_euler_private_key;
EXPECT_TRUE(
SerializeRsaPrivateKey(private_key.get(), &serialized_euler_private_key));
EXPECT_EQ(serialized_euler_private_key,
test_keys_.private_test_key_2_2048_bits());
}
TEST_F(RsaUtilTest, ConvertToEulerTotient_NewKey_Success) {
bssl::UniquePtr<RSA> rsa;
bssl::UniquePtr<RSA> private_key;
bssl::UniquePtr<BIGNUM> exponent(BN_new());
ASSERT_TRUE(BN_set_word(exponent.get(), kRsaPublicExponent));
// It is possible that sometimes, the d value generated using carmichael
// and euler is the same. For this test, find a key where they are not the
// same (max 100 tries).
bool found_distinct_keys = false;
for (int i = 0; i < 100; i++) {
rsa.reset(RSA_new());
ASSERT_TRUE(
RSA_generate_key_ex(rsa.get(), kTestRsaBits, exponent.get(), nullptr));
private_key.reset(RSAPrivateKey_dup(rsa.get()));
EXPECT_TRUE(ConvertToEulerTotient(private_key.get()));
EXPECT_EQ(1, RSA_check_key(private_key.get()));
// If the values are different, break.
if (BN_cmp(private_key->d, rsa->d) != 0) {
found_distinct_keys = true;
break;
}
LOG(INFO) << "Euler and Carmichael d values are the same. Count: " << i;
}
ASSERT_TRUE(found_distinct_keys)
<< "Reached maximum attempts, but did not generate distinct keys";
EXPECT_EQ(1, RSA_check_key(private_key.get()));
// Sanity check that the serialized keys are distinct.
std::string serialized_carmichael_private_key;
std::string serialized_private_key;
EXPECT_TRUE(
SerializeRsaPrivateKey(rsa.get(), &serialized_carmichael_private_key));
EXPECT_TRUE(
SerializeRsaPrivateKey(private_key.get(), &serialized_private_key));
EXPECT_NE(serialized_carmichael_private_key, serialized_private_key);
// Convert back to Carmichael, validate, and confirm that the keys are the
// same.
EXPECT_TRUE(ConvertToCarmichaelTotient(private_key.get()));
EXPECT_EQ(1, RSA_check_key(private_key.get()));
EXPECT_TRUE(
SerializeRsaPrivateKey(private_key.get(), &serialized_private_key));
EXPECT_EQ(serialized_carmichael_private_key, serialized_private_key);
}
TEST_F(RsaUtilTest, ConvertToSerializedCarmichaelTotient_Success) {
std::string private_key;
EXPECT_TRUE(ConvertToCarmichaelTotient(
test_keys_.private_test_key_2_2048_bits(), &private_key));
EXPECT_EQ(test_keys_.private_test_key_2_carmichael_totient_2048_bits(),
private_key);
}
TEST_F(RsaUtilTest, ConvertToSerializedEulerTotient_Success) {
std::string private_key;
EXPECT_TRUE(ConvertToEulerTotient(
test_keys_.private_test_key_2_carmichael_totient_2048_bits(),
&private_key));
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), private_key);
}
TEST_F(RsaUtilTest, ConvertToEulerTotient_Idempotent_Success) {
std::string private_key;
EXPECT_TRUE(ConvertToEulerTotient(test_keys_.private_test_key_2_2048_bits(),
&private_key));
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), private_key);
}
TEST_F(RsaUtilTest, ConvertToCarmichaelTotient_Idempotent_Success) {
std::string private_key;
EXPECT_TRUE(ConvertToCarmichaelTotient(
test_keys_.private_test_key_2_carmichael_totient_2048_bits(),
&private_key));
EXPECT_EQ(test_keys_.private_test_key_2_carmichael_totient_2048_bits(),
private_key);
}
} // namespace rsa_util
} // namespace widevine

73
crypto_utils/sha_util.cc Normal file
View File

@@ -0,0 +1,73 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "crypto_utils/sha_util.h"
#include <cstdint>
#include "third_party/boringssl/src/include/openssl/sha.h"
namespace widevine {
std::string Sha1_Hash(const std::string& message) {
std::string digest;
digest.resize(SHA_DIGEST_LENGTH);
SHA1(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
reinterpret_cast<uint8_t*>(&digest[0]));
return digest;
}
std::string Sha256_Hash(const std::string& message) {
std::string digest;
digest.resize(SHA256_DIGEST_LENGTH);
SHA256(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
reinterpret_cast<uint8_t*>(&digest[0]));
return digest;
}
std::string Sha512_Hash(const std::string& message) {
std::string digest;
digest.resize(SHA512_DIGEST_LENGTH);
SHA512(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
reinterpret_cast<uint8_t*>(&digest[0]));
return digest;
}
std::string GenerateSha1Uuid(const std::string& name_space,
const std::string& name) {
// X.667 14 Setting the fields of a name-based UUID.
// - Allocate a UUID to use as a "name space identifier" for all UUIDs
// generated from names in that name space.
// - Compute the 16-octet hash value of the name space identifier concatenated
// with the name.
SHA_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx, name_space.data(), name_space.length());
SHA1_Update(&ctx, name.data(), name.length());
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1_Final(hash, &ctx);
std::string hash_str =
std::string(reinterpret_cast<const char*>(hash), SHA_DIGEST_LENGTH);
// - For a SHA-1 hash function, the "hash value" referenced in 14.1 shall be
// octets zero to 15.
std::string uuid = hash_str.substr(0, 16);
// - Overwrite the four most significant bits (bits 15 through 12) of the
// "VersionAndTimeHigh" field with the four-bit version number from Table 3
// of 12.2 for the hash function that was used. [Name-based SHA-1 is 5]
(uuid[6] &= 0xF) |= 0x50;
// - Overwrite the two most significant bits (bits 7 and 6) of the
// "VariantAndClockSeqHigh" field with 1 and 0, respectively.
(uuid[8] &= 0x3F) |= 0x80;
return uuid;
}
} // namespace widevine

34
crypto_utils/sha_util.h Normal file
View File

@@ -0,0 +1,34 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef WHITEBOX_CRYPTO_UTILS_SHA_UTIL_H_
#define WHITEBOX_CRYPTO_UTILS_SHA_UTIL_H_
#include <cstdint>
#include <string>
namespace widevine {
// Calculates SHA1 hash.
std::string Sha1_Hash(const std::string& message);
// Calculates SHA256 hash.
std::string Sha256_Hash(const std::string& message);
// Calculate SHA512 hash.
std::string Sha512_Hash(const std::string& message);
// Generates a UUID as specified in ITU-T X.667 ch. 14, SHA-1 name-based,
// 16-byte binary representation. Name_space is a GUID prefix; name is a unique
// name in the namespace.
std::string GenerateSha1Uuid(const std::string& name_space,
const std::string& name);
} // namespace widevine
#endif // WHITEBOX_CRYPTO_UTILS_SHA_UTIL_H_

View File

@@ -0,0 +1,74 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "crypto_utils/sha_util.h"
#include "absl/strings/escaping.h"
#include "testing/include/gtest/gtest.h"
namespace widevine {
TEST(ShaUtilTest, Sha1Empty) {
const uint8_t kExpected[] = {
0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha1_Hash(""));
}
TEST(ShaUtilTest, Sha256Empty) {
const uint8_t kExpected[] = {
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha256_Hash(""));
}
TEST(ShaUtilTest, Sha1) {
const uint8_t kExpected[] = {
0x6b, 0x63, 0xa5, 0xe3, 0x6b, 0xfe, 0x54, 0x19, 0x4e, 0xfe,
0x9f, 0xe0, 0x29, 0x7e, 0xd8, 0x11, 0x0f, 0x10, 0x0d, 0x1d,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha1_Hash("random data"));
}
TEST(ShaUtilTest, Sha256) {
const uint8_t kExpected[] = {
0x62, 0x4b, 0x56, 0xb3, 0x38, 0x1b, 0xbc, 0xe0, 0x4f, 0x58, 0x88,
0x83, 0xb4, 0x2f, 0x4e, 0x27, 0xfe, 0xc0, 0x95, 0x56, 0xf8, 0x61,
0xcf, 0x94, 0x49, 0xe6, 0x5f, 0x26, 0xea, 0x70, 0xad, 0x88,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha256_Hash("random data"));
}
TEST(ShaUtilTest, Sha512) {
const uint8_t kExpected[] = {
0x8f, 0x49, 0x93, 0x1f, 0x4d, 0x4a, 0x67, 0x6f, 0x9a, 0x7e, 0x62,
0x60, 0xea, 0xe1, 0x54, 0xfe, 0xe2, 0x75, 0x3c, 0xec, 0x3b, 0xb2,
0x2e, 0xd7, 0x51, 0xcc, 0x39, 0xf9, 0x89, 0x69, 0xad, 0xd0, 0x14,
0xaa, 0xbe, 0x40, 0xce, 0xe3, 0xab, 0xef, 0x10, 0x2f, 0x24, 0x0e,
0xd8, 0x26, 0x7b, 0xb5, 0x7d, 0x86, 0xce, 0xbd, 0xd7, 0x32, 0x86,
0x3a, 0x5e, 0x9e, 0x8d, 0x23, 0x77, 0x10, 0x80, 0x0c};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha512_Hash("random data"));
}
TEST(ShaUtilTest, GenerateSha1Uuid) {
std::string name_space =
absl::HexStringToBytes("4d20ad7dd95bc4b250fae56fb143e774");
std::string name = "some seed value";
EXPECT_EQ("730621a55c675c4086be38e72aefa03e",
absl::BytesToHexString(GenerateSha1Uuid(name_space, name)));
}
} // namespace widevine