In this update we have:
- Added the verified platform tests. These tests show how some
platforms, when verified are allowed to by pass the normal policy
restrictions. This is done with ChromeOS, thus the name of the
tests use "chrome_os".
- Removed WB_RESULT_INVALID_PADDING. This error was when we the
non-license APIs exposed a AES function with padding. However,
those functions have been removed from the API and this error is
no longer used by the API.
- Tests have been updated to avoid signed-vs-unsigned comparison
and to use the Chromium path to gTest (which is mocked in this
library).
- Tests have been updated to use a new test base and golden data
system to make them easier to read.
308 lines
13 KiB
C++
308 lines
13 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// 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/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/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(
|
|
255u * 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(), 32u);
|
|
|
|
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(), 32u);
|
|
|
|
// 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(20u, 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(20u, 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
|