Fix build break

Remove the clear key drm engine as it is no longer needed and
would need to be reworked to be compatible with the new MediaDrm APIs.

Change-Id: Ie33c00345876fcd75f7c9cb0c65bd12bb4152f20
This commit is contained in:
Jeff Tinker
2013-03-20 12:37:06 -07:00
parent ba14f26d7b
commit 38334efbe7
25 changed files with 0 additions and 3293 deletions

View File

@@ -1,34 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
src/WVCreateDrmPluginFactory.cpp \
src/WVDrmPluginFactory.cpp \
LOCAL_C_INCLUDES := \
frameworks/native/include \
frameworks/av/include \
vendor/widevine/libclearkeydrmengine/include \
vendor/widevine/libclearkeydrmengine/crypto/include \
vendor/widevine/libclearkeydrmengine/oemcrypto/include \
LOCAL_STATIC_LIBRARIES := \
libwvclearkeycryptoplugin \
libmockoemcrypto \
LOCAL_SHARED_LIBRARIES := \
liblog \
libutils \
libdl \
libcrypto \
LOCAL_MODULE := libclearkeydrmengine
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
# Sublibraries Needed:
include vendor/widevine/libclearkeydrmengine/crypto/Android.mk
include vendor/widevine/libclearkeydrmengine/oemcrypto/mock/Android.mk

View File

@@ -1,15 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
src/WVCryptoPlugin.cpp \
LOCAL_C_INCLUDES := \
vendor/widevine/libclearkeydrmengine/crypto/include \
vendor/widevine/libclearkeydrmengine/oemcrypto/include \
LOCAL_MODULE := libwvclearkeycryptoplugin
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
#ifndef WV_CRYPTO_PLUGIN_H_
#define WV_CRYPTO_PLUGIN_H_
#include "media/stagefright/foundation/ABase.h"
#include "media/hardware/CryptoAPI.h"
#include "OEMCryptoDASH.h"
namespace wvclearkey {
class WVCryptoPlugin : public android::CryptoPlugin {
public:
WVCryptoPlugin();
virtual ~WVCryptoPlugin();
virtual bool requiresSecureDecoderComponent(const char *mime) const {
return false;
}
virtual ssize_t decrypt(
bool secure,
const uint8_t key[16],
const uint8_t iv[16],
Mode mode,
const void *srcPtr,
const SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
android::AString *errorDetailMsg);
private:
DISALLOW_EVIL_CONSTRUCTORS(WVCryptoPlugin);
OEMCrypto_SESSION mSession;
};
} // namespace wvclearkey
#endif // WV_CRYPTO_PLUGIN_H_

View File

@@ -1,124 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "wv_clear_key"
#include <utils/Log.h>
#include "WVCryptoPlugin.h"
namespace wvclearkey {
WVCryptoPlugin::WVCryptoPlugin() {
OEMCryptoResult res = OEMCrypto_OpenSession(&mSession);
if (res != OEMCrypto_SUCCESS) {
ALOGE("OEMCrypto_OpenSession error result: %d", res);
}
}
WVCryptoPlugin::~WVCryptoPlugin() {
OEMCryptoResult res = OEMCrypto_CloseSession(mSession);
if (res != OEMCrypto_SUCCESS) {
ALOGE("OEMCrypto_OpenSession error result: %d", res);
}
}
// Returns negative values for error codes and positive values for the size of
// the decrypted data.
ssize_t WVCryptoPlugin::decrypt(
bool secure,
const uint8_t key[16],
const uint8_t iv[16],
Mode mode,
const void *srcPtr,
const SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
android::AString *errorDetailMsg) {
if (mode != kMode_Unencrypted && mode != kMode_AES_CTR) {
return android::BAD_TYPE;
}
const uint8_t *const source = static_cast<const uint8_t*>(srcPtr);
uint8_t *const dest = static_cast<uint8_t*>(dstPtr);
if (secure) {
// Can't do secure on this implementation
return -EPERM;
}
// For this special clear-key version of OEMCrypto ONLY, SelectKey actually
// has the meaning "use this key, passed in the clear." This is only the
// case for libclearkeydrmengine and not any other OEMCrypto.
OEMCryptoResult res = OEMCrypto_SelectKey(mSession, key, 16);
if (res != OEMCrypto_SUCCESS) {
ALOGE("Key selection error in session %d: %d", mSession, res);
return -EINVAL;
}
size_t offset = 0;
for (size_t i = 0; i < numSubSamples; ++i) {
const SubSample &subSample = subSamples[i];
if (mode == kMode_Unencrypted &&
subSample.mNumBytesOfEncryptedData != 0) {
return -EINVAL;
}
// "Decrypt" any unencrypted data. By convention,
// (see frameworks/av/include/media/stagefright/MetaData.h)
// clear data comes before encrypted data.
if (subSample.mNumBytesOfClearData != 0) {
OEMCrypto_DestBufferDesc output;
output.type = OEMCrypto_BufferType_Clear;
output.buffer.clear.address = dest + offset;
output.buffer.clear.max_length = subSample.mNumBytesOfClearData;
res = OEMCrypto_DecryptCTR(
mSession,
source + offset, subSample.mNumBytesOfClearData,
false,
iv,
offset % 16,
&output);
if (res != OEMCrypto_SUCCESS) {
ALOGE("Decrypt error result in session %d: %d", mSession, res);
return -EINVAL;
}
offset += subSample.mNumBytesOfClearData;
}
// Decrypt any encrypted data.
if (subSample.mNumBytesOfEncryptedData != 0) {
OEMCrypto_DestBufferDesc output;
output.type = OEMCrypto_BufferType_Clear;
output.buffer.clear.address = dest + offset;
output.buffer.clear.max_length = subSample.mNumBytesOfEncryptedData;
res = OEMCrypto_DecryptCTR(
mSession,
source + offset, subSample.mNumBytesOfEncryptedData,
true,
iv,
offset % 16,
&output);
if (res != OEMCrypto_SUCCESS) {
ALOGE("Decrypt error result in session %d: %d", mSession, res);
return -EINVAL;
}
offset += subSample.mNumBytesOfEncryptedData;
}
}
return static_cast<ssize_t>(offset);
}
} // namespace wvclearkey

View File

@@ -1,28 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
WVCryptoPlugin_test.cpp \
LOCAL_C_INCLUDES := \
bionic \
external/gtest/include \
external/stlport/stlport \
vendor/widevine/libclearkeydrmengine/crypto/include \
vendor/widevine/libclearkeydrmengine/oemcrypto/include \
LOCAL_STATIC_LIBRARIES := \
libgtest \
libgtest_main \
libwvclearkeycryptoplugin \
LOCAL_SHARED_LIBRARIES := \
libstlport \
liblog \
libutils \
LOCAL_MODULE := libwvclearkeycryptoplugin_test
LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)

View File

@@ -1,192 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
#include "media/stagefright/foundation/ABase.h"
#include "utils/UniquePtr.h"
#include "WVCryptoPlugin.h"
#include "OEMCryptoDASH.h"
#include "gtest/gtest.h"
using namespace wvclearkey;
using android::status_t;
bool oemCryptoSessionOpened = false;
OEMCrypto_SESSION openedCryptoSession = 0;
bool oemCryptoSessionClosed = false;
OEMCrypto_SESSION closedCryptoSession = 0;
extern "C" {
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION *session) {
oemCryptoSessionOpened = true;
openedCryptoSession = 5;
*session = openedCryptoSession;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session) {
oemCryptoSessionClosed = true;
closedCryptoSession = session;
return OEMCrypto_SUCCESS;
}
}
TEST(WVCryptoPluginTest, ManagesASession) {
oemCryptoSessionOpened = false;
openedCryptoSession = 0;
oemCryptoSessionClosed = false;
closedCryptoSession = 0;
UniquePtr<WVCryptoPlugin> plugin(new WVCryptoPlugin());
EXPECT_TRUE(oemCryptoSessionOpened) <<
"WVCryptoPlugin did not call OEMCrypto_OpenSession()";
plugin.reset();
EXPECT_TRUE(oemCryptoSessionClosed) <<
"WVCryptoPlugin did not call OEMCrypto_CloseSession()";
EXPECT_EQ(openedCryptoSession, closedCryptoSession) <<
"WVCryptoPlugin closed the wrong session";
}
TEST(WVCryptoPluginTest, CorrectlyReportsSecureBuffers) {
UniquePtr<WVCryptoPlugin> plugin(new WVCryptoPlugin());
EXPECT_FALSE(plugin->requiresSecureDecoderComponent("video/mp4")) <<
"WVCryptoPlugin incorrectly expects a secure video decoder";
EXPECT_FALSE(plugin->requiresSecureDecoderComponent("audio/aac")) <<
"WVCryptoPlugin incorrectly expects a secure audio decoder";
}
typedef const uint8_t* constChars;
bool selectKeyCalled;
constChars selectedKey;
size_t selectedKeyLength;
uint32_t decryptCallCount;
constChars decryptInPointers[3];
size_t decryptInLengths[3];
bool decryptIsEncryptedValues[3];
constChars decryptIvs[3];
size_t decryptOffsets[3];
OEMCrypto_DestBufferDesc decryptOutBuffers[3];
extern "C" {
OEMCryptoResult OEMCrypto_SelectKey(
const OEMCrypto_SESSION session,
const uint8_t* key_id,
const size_t key_id_length) {
selectKeyCalled = true;
selectedKey = key_id;
selectedKeyLength = key_id_length;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OEMCrypto_DecryptCTR(
OEMCrypto_SESSION session,
const uint8_t *data_addr,
size_t data_length,
bool is_encrypted,
const uint8_t *iv,
size_t offset,
const OEMCrypto_DestBufferDesc* out_buffer) {
if (decryptCallCount < 3) {
decryptInPointers[decryptCallCount] = data_addr;
decryptInLengths[decryptCallCount] = data_length;
decryptIsEncryptedValues[decryptCallCount] = is_encrypted;
decryptIvs[decryptCallCount] = iv;
decryptOffsets[decryptCallCount] = offset;
decryptOutBuffers[decryptCallCount] = *out_buffer;
}
decryptCallCount++;
return OEMCrypto_SUCCESS;
}
}
TEST(WVCryptoPluginTest, AttemptsToDecrypt) {
selectKeyCalled = false;
selectedKey = NULL;
selectedKeyLength = 0;
decryptCallCount = 0;
memset(decryptInPointers, 0, sizeof(decryptInPointers));
memset(decryptInLengths, 0, sizeof(decryptInLengths));
memset(decryptIsEncryptedValues, 0, sizeof(decryptIsEncryptedValues));
memset(decryptIvs, 0, sizeof(decryptIvs));
memset(decryptOffsets, 0, sizeof(decryptOffsets));
memset(decryptOutBuffers, 0, sizeof(decryptOutBuffers));
UniquePtr<WVCryptoPlugin> plugin(new WVCryptoPlugin());
android::CryptoPlugin::SubSample subSamples[3];
subSamples[0].mNumBytesOfEncryptedData = 16;
subSamples[1].mNumBytesOfEncryptedData = 24;
subSamples[2].mNumBytesOfEncryptedData = 8;
uint8_t key[16] = {};
uint8_t iv[16] = {};
uint8_t in[48] = {};
uint8_t out[48] = {};
ssize_t decrypted = plugin->decrypt(
false,
key,
iv,
android::CryptoPlugin::kMode_AES_CTR,
in,
subSamples, 3,
out,
NULL);
EXPECT_EQ(48, decrypted) <<
"WVCryptoPlugin decrypted the wrong number of bytes";
ASSERT_EQ(3u, decryptCallCount) <<
"WVCryptoPlugin called OEMCrypto_DecryptCTR the wrong number of times";
// Test the 1st call
EXPECT_EQ(in, decryptInPointers[0]) <<
"1st OEMCrypto_DecryptCTR call targetted the wrong input location";
EXPECT_EQ(16u, decryptInLengths[0]) <<
"1st OEMCrypto_DecryptCTR call targetted the wrong input length";
EXPECT_TRUE(decryptIsEncryptedValues[0]) <<
"1st OEMCrypto_DecryptCTR call thought data was unencrypted";
EXPECT_EQ(iv, decryptIvs[0]) <<
"1st OEMCrypto_DecryptCTR call had the wrong iv";
EXPECT_EQ(0u, decryptOffsets[0]) <<
"1st OEMCrypto_DecryptCTR call had the wrong offset";
EXPECT_EQ(out, decryptOutBuffers[0].buffer.clear.address) <<
"1st OEMCrypto_DecryptCTR call targetted the wrong output location";
// Test the 2nd call
EXPECT_EQ(in + 16, decryptInPointers[0]) <<
"2nd OEMCrypto_DecryptCTR call targetted the wrong input location";
EXPECT_EQ(24u, decryptInLengths[0]) <<
"2nd OEMCrypto_DecryptCTR call targetted the wrong input length";
EXPECT_TRUE(decryptIsEncryptedValues[0]) <<
"2nd OEMCrypto_DecryptCTR call thought data was unencrypted";
EXPECT_EQ(iv, decryptIvs[0]) <<
"2nd OEMCrypto_DecryptCTR call had the wrong iv";
EXPECT_EQ(0u, decryptOffsets[0]) <<
"2nd OEMCrypto_DecryptCTR call had the wrong offset";
EXPECT_EQ(out + 16, decryptOutBuffers[0].buffer.clear.address) <<
"2nd OEMCrypto_DecryptCTR call targetted the wrong output location";
// Test the 3rd call
EXPECT_EQ(in + 40, decryptInPointers[0]) <<
"3rd OEMCrypto_DecryptCTR call targetted the wrong input location";
EXPECT_EQ(8u, decryptInLengths[0]) <<
"3rd OEMCrypto_DecryptCTR call targetted the wrong input length";
EXPECT_TRUE(decryptIsEncryptedValues[0]) <<
"3rd OEMCrypto_DecryptCTR call thought data was unencrypted";
EXPECT_EQ(iv, decryptIvs[0]) <<
"3rd OEMCrypto_DecryptCTR call had the wrong iv";
EXPECT_EQ(8u, decryptOffsets[0]) <<
"3rd OEMCrypto_DecryptCTR call had the wrong offset";
EXPECT_EQ(out + 40, decryptOutBuffers[0].buffer.clear.address) <<
"3rd OEMCrypto_DecryptCTR call targetted the wrong output location";
}

View File

@@ -1,17 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
#ifndef WV_CREATE_DRM_PLUGIN_FACTORY_H_
#define WV_CREATE_DRM_PLUGIN_FACTORY_H_
#include "media/stagefright/foundation/ABase.h"
#include "media/drm/DrmEngineAPI.h"
#include "media/hardware/CryptoAPI.h"
extern "C" {
android::DrmPluginFactory* createDrmPluginFactory();
android::CryptoFactory *createCryptoFactory();
}
#endif // WV_CREATE_DRM_PLUGIN_FACTORY_H_

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
#ifndef WV_DRM_PLUGIN_FACTORY_H_
#define WV_DRM_PLUGIN_FACTORY_H_
#include "media/stagefright/foundation/ABase.h"
#include "media/drm/DrmEngineAPI.h"
#include "media/hardware/CryptoAPI.h"
namespace wvclearkey {
using android::status_t;
class WVDrmPluginFactory : public android::DrmPluginFactory, public android::CryptoFactory {
public:
WVDrmPluginFactory();
virtual ~WVDrmPluginFactory();
// Implement DrmPluginFactory
virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const;
virtual status_t createCryptoPlugin(
const uint8_t uuid[16], const void *data, size_t size,
android::CryptoPlugin **plugin);
virtual status_t createDrmClientPlugin(
const uint8_t uuid[16], const void *data, size_t size,
android::DrmClientPlugin **plugin);
// Implement CryptoFactory
virtual status_t createPlugin(
const uint8_t uuid[16], const void *data, size_t size,
android::CryptoPlugin **plugin) {
return createCryptoPlugin(uuid, data, size, plugin);
}
private:
DISALLOW_EVIL_CONSTRUCTORS(WVDrmPluginFactory);
void *mLegacyLibraryHandle;
android::CryptoFactory *mLegacyFactory;
};
} // namespace wvclearkey
#endif // WV_DRM_PLUGIN_FACTORY_H_

View File

@@ -1,34 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
ClearKey_test.cpp \
LOCAL_C_INCLUDES := \
bionic \
external/gtest/include \
external/openssl/include \
external/stlport/stlport \
vendor/widevine/libclearkeydrmengine/include \
vendor/widevine/libclearkeydrmengine/oemcrypto/mock \
vendor/widevine/libclearkeydrmengine/oemcrypto/include \
LOCAL_STATIC_LIBRARIES := \
libgtest \
libgtest_main \
LOCAL_SHARED_LIBRARIES := \
libstlport \
liblog \
libutils \
libcrypto \
libclearkeydrmengine \
LOCAL_MODULE := libclearkey_integration_test
LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)
include $(LOCAL_PATH)/../Android.mk

View File

@@ -1,87 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
* These are one level up from unit tests -- they test the shared
* clearkey DRM library and all of its components.
* These are similar to the
*/
#include "WVCreateDrmPluginFactory.h"
#include "MockOEMCrypto.h"
#include "media/hardware/CryptoAPI.h"
#include "media/drm/DrmClientAPI.h"
#include "gtest/gtest.h"
#include "stdio.h"
using android::sp;
using android::status_t;
TEST(WVClearIntegrationTest, CreatesObject) {
android::DrmPluginFactory* factory = createDrmPluginFactory();
EXPECT_NE(static_cast<android::DrmPluginFactory*>(NULL), factory)
<< "createDrmPluginFactory() returned null";
}
static const uint8_t kWidevineUUID[16] = {
0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
};
static const uint8_t kOldNetflixWidevineUUID[16] = {
0x29,0x70,0x1F,0xE4,0x3C,0xC7,0x4A,0x34,
0x8C,0x5B,0xAE,0x90,0xC7,0x43,0x9A,0x47
};
static const uint8_t kUnknownUUID[16] = {
0x6A,0x7F,0xAA,0xB0,0x83,0xC7,0x9E,0x20,
0x08,0xBC,0xEF,0x32,0x34,0x1A,0x9A,0x26
};
TEST(WVClearIntegrationTest, DecryptsBuffer) {
android::DrmPluginFactory* factory = createDrmPluginFactory();
android::CryptoPlugin *plugin;
const char *sessionId = "fake-session-id";
status_t result = factory->createCryptoPlugin(kWidevineUUID, sessionId,
strlen(sessionId), &plugin);
EXPECT_EQ(android::OK, result)
<< "WVDrmPluginFactory returned error from createCryptoPlugin()";
const size_t count = 751; // a nice big number, but not too round.
bool secure = false;
uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
uint8_t iv[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
uint8_t ecount[16];
uint8_t ivec[16];
unsigned int num = 0;
unsigned char indata[count];
memset(ecount, 0, 16);
memcpy(ivec, iv, 16);
memset(indata, 0xAA, count);
uint8_t srcPtr[count];
AES_KEY aes_key;
AES_set_encrypt_key(key, 128, &aes_key);
AES_ctr128_encrypt(indata, srcPtr, count, &aes_key, ivec, ecount, &num);
android::CryptoPlugin::SubSample subSamples;
subSamples.mNumBytesOfClearData = 0;
subSamples.mNumBytesOfEncryptedData = count;
size_t numSubSamples = 1;
uint8_t dstPtr[count];
memset(dstPtr, 0, count);
android::AString *errorDetailMsg=NULL;
android::CryptoPlugin::Mode mode = android::CryptoPlugin::kMode_AES_CTR;
plugin->decrypt( secure, key, iv, mode, srcPtr, &subSamples,
numSubSamples, dstPtr, errorDetailMsg);
EXPECT_EQ(0, memcmp(indata, dstPtr, count))
<< "End-to-End decrypt did not work.";
}

View File

@@ -1,827 +0,0 @@
/*********************************************************************
* OEMCryptoDASH.h
*
* (c) Copyright 2011-2012 Google, Inc.
*
* Reference APIs needed to support Widevine's crypto algorithms.
*********************************************************************/
#ifndef OEMCRYPTO_DASH_H_
#define OEMCRYPTO_DASH_H_
#include<stdint.h>
// 12/20/2012 - changes from 4.3 to 4.4:
// 1. Added key id length.
// 2. Renamed fields in DestBufferDesc.
// 12/11/2012 - changes from 4.2 to 4.3:
// 1. Include stdint.h. Change base types.
// 2. Allow NULL for mac_key in OEMCrypto_LoadKeys() (doc-only change).
// 3. Allow NULL for key_control_block in OEMCrypto_RefreshKeys() (doc-only
// change).
// 12/05/2012 - changes from 4.1 to 4.2:
// 1. Change OEMCrypto_GenerateDerivedkeys() to pass in two context strings
// for the derived key computation - one for the mac key and one for the
// encryption key.
// 12/04/2012 - changes from 4.0 to 4.1:
// 1. Change 'unsigned long' back to 'unsigned int'.
// 2. Add struct OEMCrypto_DestBufferDesc for OEMCrypto_DecryptCTR()
// output param.
// 3. Change OEMCrypto_KeyObject to use 'const OEMCrypto_UINT8*'
// 4. Change OEMCrypto_KeyRefreshObject to use 'const OEMCrypto_UINT8*'
// 5. Change enc_mac params of OEMCrypto_LoadKeys() to
// to use const OEMCrypto_UINT8*'.
// 6. Add OEMCrypto_SelectKey().
// 7. Add OEMCrypto_DestBufferDesc param to OEMCrypto_DecryptCTR().
#ifdef __cplusplus
extern "C" {
#endif
#define OEMCRYPTO_VERSION "4.4"
static const char oec_version[] = OEMCRYPTO_VERSION;
typedef uint32_t OEMCrypto_SESSION;
typedef enum OEMCryptoResult {
OEMCrypto_SUCCESS = 0,
OEMCrypto_ERROR_INIT_FAILED = 1,
OEMCrypto_ERROR_TERMINATE_FAILED = 2,
OEMCrypto_ERROR_OPEN_FAILURE = 3,
OEMCrypto_ERROR_CLOSE_FAILURE = 4,
OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED = 5,
OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED = 6,
OEMCrypto_ERROR_SHORT_BUFFER = 7,
OEMCrypto_ERROR_NO_DEVICE_KEY = 8,
OEMCrypto_ERROR_NO_ASSET_KEY = 9,
OEMCrypto_ERROR_KEYBOX_INVALID = 10,
OEMCrypto_ERROR_NO_KEYDATA = 11,
OEMCrypto_ERROR_NO_CW = 12,
OEMCrypto_ERROR_DECRYPT_FAILED = 13,
OEMCrypto_ERROR_WRITE_KEYBOX = 14,
OEMCrypto_ERROR_WRAP_KEYBOX = 15,
OEMCrypto_ERROR_BAD_MAGIC = 16,
OEMCrypto_ERROR_BAD_CRC = 17,
OEMCrypto_ERROR_NO_DEVICEID = 18,
OEMCrypto_ERROR_RNG_FAILED = 19,
OEMCrypto_ERROR_RNG_NOT_SUPPORTED = 20,
OEMCrypto_ERROR_SETUP = 21,
OEMCrypto_ERROR_OPEN_SESSION_FAILED = 22,
OEMCrypto_ERROR_CLOSE_SESSION_FAILED = 23,
OEMCrypto_ERROR_INVALID_SESSION = 24,
OEMCrypto_ERROR_NOT_IMPLEMENTED = 25,
OEMCrypto_ERROR_NO_CONTENT_KEY = 26,
OEMCrypto_ERROR_CONTROL_INVALID = 27,
OEMCrypto_ERROR_UNKNOWN_FAILURE = 28,
OEMCrypto_ERROR_INVALID_CONTEXT = 29,
OEMCrypto_ERROR_SIGNATURE_FAILURE = 30,
OEMCrypto_ERROR_TOO_MANY_SESSIONS = 31,
OEMCrypto_ERROR_INVALID_NONCE = 32,
OEMCrypto_ERROR_TOO_MANY_KEYS = 33
} OEMCryptoResult;
/*
* OEMCrypto_DestBufferDesc
* Describes the type and access information for the memory to receive
* decrypted data.
*
* The OEMCrypto API supports a range of client device architectures.
* Different architectures have different methods for acquiring and securing
* buffers that will hold portions of the audio or video stream after
* decryption. Three basic strategies are recognized for handling decrypted
* stream data:
* 1. Return the decrypted data in the clear into normal user memory
* (ClearBuffer). The caller uses normal memory allocation methods to
* acquire a buffer, and supplies the memory address of the buffer in the
* descriptor.
* 2. Place the decrypted data into protected memory (SecureBuffer). The
* caller uses a platform-specific method to acquire the protected buffer
* and a user-memory handle that references it. The handle is supplied
* to the decrypt call in the descriptor.
* 3. Place the decrypted data directly into the audio or video decoder fifo
* (Direct). The caller will use platform-specific methods to initialize
* the fifo and the decoders. The decrypted stream data is not accessible
* to the caller.
*
* Specific fields are as follows:
*
* (type == OEMCrypto_BufferType_Clear)
* address - Address of start of user memory buffer.
* max_length - Size of user memory buffer.
* (type == OEMCrypto_BufferType_Secure)
* buffer - handle to a platform-specific secure buffer.
* max_length - Size of platform-specific secure buffer.
* (type == OEMCrypto_BufferType_Direct)
* is_video - If true, decrypted bytes are routed to the video
* decoder. If false, decrypted bytes are routed to the
* audio decoder.
*/
typedef enum OEMCryptoBufferType {
OEMCrypto_BufferType_Clear,
OEMCrypto_BufferType_Secure,
OEMCrypto_BufferType_Direct
} OEMCrytoBufferType;
typedef struct {
OEMCryptoBufferType type;
union {
struct { // type == OEMCrypto_BufferType_Clear
uint8_t* address;
size_t max_length;
} clear;
struct { // type == OEMCrypto_BufferType_Secure
void* handle;
size_t max_length;
} secure;
struct { // type == OEMCrypto_BufferType_Direct
bool is_video;
} direct;
} buffer;
} OEMCrypto_DestBufferDesc;
/*
* OEMCrypto_KeyObject
* Points to the relevant fields for a content key. The fields are extracted
* from the License Response message offered to OEMCrypto_LoadKeys(). Each
* field points to one of the components of the key. All fields are 128 bits
* (16 bytes):
* key_id - the unique id of this key.
* key_data_iv - the IV for performing AES-128-CBC decryption of the
* key_data field.
* key_data - the key data. It is encrypted (AES-128-CBC) with the
* session's derived encrypt key and the key_data_iv.
* key_control_iv - the IV for performing AES-128-CBC decryption of the
* key_control field.
* key_control - the key control block. It is encrypted (AES-128-CBC) with
* the content key from the key_data field.
*
* The memory for the OEMCrypto_KeyObject fields is allocated and freed
* by the caller of OEMCrypto_LoadKeys().
*/
typedef struct {
const uint8_t* key_id;
size_t key_id_length;
const uint8_t* key_data_iv;
const uint8_t* key_data;
const uint8_t* key_control_iv;
const uint8_t* key_control;
} OEMCrypto_KeyObject;
/*
* OEMCrypto_KeyRefreshObject
* Points to the relevant fields for renewing a content key. The fields are
* extracted from the License Renewal Response message offered to
* OEMCrypto_RefreshKeys(). Each field points to one of the components of
* the key. All fields are 128 bits (16 bytes):
* key_id - the unique id of this key.
* key_control_iv - the IV for performing AES-128-CBC decryption of the
* key_control field.
* key_control - the key control block. It is encrypted (AES-128-CBC) with
* the content key from the key_data field.
*
* The key_data is unchanged from the original OEMCrypto_LoadKeys() call. Some
* Key Control Block fields, especially those related to key lifetime, may
* change.
*
* The memory for the OEMCrypto_KeyRefreshObject fields is allocated and freed
* by the caller of OEMCrypto_RefreshKeys().
*/
typedef struct {
const uint8_t* key_id;
size_t key_id_length;
const uint8_t* key_control_iv;
const uint8_t* key_control;
} OEMCrypto_KeyRefreshObject;
#define OEMCrypto_Initialize _oec01
#define OEMCrypto_Terminate _oec02
#define OEMCrypto_SetEntitlementKey _oec03
#define OEMCrypto_DeriveControlWord _oec04
#define OEMCrypto_DecryptVideo _oec05
#define OEMCrypto_DecryptAudio _oec06
#define OEMCrypto_InstallKeybox _oec07
#define OEMCrypto_GetKeyData _oec08
#define OEMCrypto_IsKeyboxValid _oec09
#define OEMCrypto_GetRandom _oec10
#define OEMCrypto_GetDeviceID _oec11
#define OEMCrypto_EnterSecurePlayback _oec12
#define OEMCrypto_ExitSecurePlayback _oec13
#define OEMCrypto_WrapKeybox _oec14
#define OEMCrypto_OpenSession _oec15
#define OEMCrypto_CloseSession _oec16
#define OEMCrypto_SetContentKey _oec17
#define OEMCrypto_DecryptCTR _oec18
#define OEMCrypto_DecryptCTS _oec19
#define OEMCrypto_GenerateDerivedKeys _oec20
#define OEMCrypto_GenerateSignature _oec21
#define OEMCrypto_GenerateNonce _oec22
#define OEMCrypto_LoadKeys _oec23
#define OEMCrypto_RefreshKeys _oec24
#define OEMCrypto_SelectKey _oec25
/*
* OEMCrypto_Initialize
*
* Description:
* Initialize the crypto firmware/hardware.
*
* Parameters:
* N/A
*
* Threading:
* No other function calls will be made while this function is running. This
* function will not be called again before OEMCrypto_Terminate.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_INIT_FAILED failed to initialize crypto hardware
*/
OEMCryptoResult OEMCrypto_Initialize(void);
/*
* OEMCrypto_Terminate
*
* Description:
* The API closes the crypto operation and releases all resources used.
*
* Parameters:
* N/A
*
* Threading:
* No other OEMCrypto calls are made while this function is running. After
* this function is called, no other OEMCrypto calls will be made until another
* call to OEMCrypto_Initialize is made.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_TERMINATE_FAILED failed to de-initialize crypto hardware
*/
OEMCryptoResult OEMCrypto_Terminate(void);
/*
* OEMCrypto_OpenSession
*
* Description:
* The API provides for session based crypto initialization for AES CTR mode.
*
* Parameters:
* session (out) - pointer to crypto session identifier.
*
* Threading:
* No other Open/Close session calls will be made while this function is
* running. Functions on existing sessions may be called while this function
* is active.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_TOO_MANY_SESSIONS failed because too many sessions are open
* OEMCrypto_ERROR_OPEN_SESSION_FAILED failed to initialize the crypto session
*/
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION *session);
/*
* OEMCrypto_CloseSession
*
* Description:
* The API provides for session based crypto termination for AES CTR mode.
*
* Parameters:
* session (in) - crypto session identifier.
*
* Threading:
* No other Open/Close session calls will be made while this function is
* running. Functions on existing sessions may be called while this function
* is active.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_INVALID_SESSION no open session with that id.
* OEMCrypto_ERROR_CLOSE_SESSION_FAILED failed to terminate the crypto session
*/
OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session);
/*
* OEMCrypto_GenerateDerivedKeys
*
* Description:
* Generates a pair of secondary keys, mac_key and encrypt_key, for handling
* signing and content key decryption under the license server protocol
* for AES CTR mode.
*
* Refer to document "OEMCrypto Changes for V2 License Protocol" for details.
* This function computes the AES-128-CMAC of the enc_key_context and stores
* it in secure memory as the encrypt_key.
* It then computes two cycles of AES-128-CMAC of the mac_key_context and
* stores it in the mac_key. These two keys will be stored until the next
* call to LoadKeys.
*
* Parameters:
* session (in) - crypto session identifier.
* mac_key_context (in) - pointer to memory containing context data for
* computing the HMAC generation key.
* mac_key_context_length (in) - length of the HMAC key context data.
* enc_key_context (in) - pointer to memory containing context data for
* computing the encryption key.
* enc_key_context_length (in) - length of the encryption key context data.
*
* Results:
* mac_key: the 256 bit mac key is generated and stored in secure memory.
* enc_key: the 128 bit encryption key is generated and stored in secure memory.
*
* Threading:
* This function may be called simultaneously with functions on other sessions,
* but not with other functions on this session.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_NO_DEVICE_KEY
* OEMCrypto_ERROR_INVALID_SESSION
* OEMCrypto_ERROR_UNKNOWN_FAILURE
* OEMCrypto_ERROR_INVALID_CONTEXT
*/
OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
OEMCrypto_SESSION session,
const uint8_t *mac_key_context,
uint32_t mac_key_context_length,
const uint8_t *enc_key_context,
uint32_t enc_key_context_length);
/*
* OEMCrypto_GenerateNonce
*
* Description:
* Generates a 32-bit nonce to detect possible replay attack on the key
* control block. The nonce is stored in secure memory and will be used
* for the next call to LoadKeys.
*
* Refer to documents "OEMCrypto Changes for V2 License Protocol" and "Key
* Control Block Definition" for details.
*
* Parameters:
* session (in) - crypto session identifier.
* nonce (out) - pointer to memory to received the computed nonce.
*
* Results:
* nonce: the nonce is also stored in secure memory.
*
* Threading:
* This function may be called simultaneously with functions on other sessions,
* but not with other functions on this session.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_NO_DEVICE_KEY
* OEMCrypto_ERROR_INVALID_SESSION
* OEMCrypto_ERROR_UNKNOWN_FAILURE
* OEMCrypto_ERROR_INVALID_CONTEXT
*/
OEMCryptoResult OEMCrypto_GenerateNonce(
OEMCrypto_SESSION session,
uint32_t* nonce);
/*
* OEMCrypto_GenerateSignature
*
* Description:
* Generates a HMAC-SHA256 signature for license request signing under the
* license server protocol for AES CTR mode.
*
* NOTE: OEMCrypto_GenerateDerivedKeys() must be called first to establish the
* mac_key
*
* Refer to document "OEMCrypto Changes for V2 License Protocol" for details.
*
* Parameters:
* session (in) - crypto session identifier.
* message (in) - pointer to memory containing message to be signed.
* message_length (in) - length of the message.
* signature (out) - pointer to memory to received the computed signature.
* signature_length (in/out) - (in) length of the signature buffer.
* (out) actual length of the signature
*
* Threading:
* This function may be called simultaneously with functions on other sessions,
* but not with other functions on this session.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_NO_DEVICE_KEY
* OEMCrypto_ERROR_INVALID_SESSION
* OEMCrypto_ERROR_UNKNOWN_FAILURE
* OEMCrypto_ERROR_INVALID_CONTEXT
*/
OEMCryptoResult OEMCrypto_GenerateSignature(
OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
/*
* OEMCrypto_LoadKeys
*
* Description:
* Installs a set of keys for performing decryption in the current session.
*
* The relevant fields have been extracted from the License Response protocol
* message, but the entire message and associated signature are provided so
* the message can be verified (using HMAC-SHA256 with the derived mac_key).
* If the signature verification fails, ignore all other arguments and return
* OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add the keys to the session
* context.
*
* The keys will be decrypted using the current encrypt_key (AES-128-CBC) and
* the IV given in the KeyObject. Each key control block will be decrypted
* using the corresponding content key (AES-128-CBC) and the IV given in the
* KeyObject.
*
* If any key's control block does not have valid verification fields, return
* OEMCrypto_ERROR_INVALID_CONTEXT and do not install any keys.
*
* If any key's control block requires a nonce, and the nonce in the control
* block is different from the current nonce, return
* OEMCrypto_ERROR_INVALID_NONCE. In that case, do not install any keys.
*
* The new mac_key is decrypted with the current encrypt_key and the offered
* IV. It replaces the current mac_key.
*
* The mac_key and encrypt_key were generated and stored by the previous call
* to OEMCrypto_GenerateDerivedKeys(). The nonce was generated and stored by
* the previous call to OEMCrypto_GenerateNonce().
*
* NOTE: OEMCrypto_GenerateDerivedKeys() must be called first to establish the
* mac_key and encrypt_key.
*
* Refer to document "OEMCrypto Changes for V2 License Protocol" for details.
*
* Parameters:
* session (in) - crypto session identifier.
* message (in) - pointer to memory containing message to be verified.
* message_length (in) - length of the message.
* signature (in) - pointer to memory containing the signature.
* signature_length (in) - length of the signature.
* enc_mac_key_iv (in) - IV for decrypting new mac_key. Size is 128 bits.
* enc_mac_key (in) - encrypted mac_key for generating new mac_key. Size is
* 256 bits.
* num_keys (in) - number of keys present.
* key_array (in) - set of keys to be installed.
*
* Threading:
* This function may be called simultaneously with functions on other sessions,
* but not with other functions on this session.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_NO_DEVICE_KEY
* OEMCrypto_ERROR_INVALID_SESSION
* OEMCrypto_ERROR_UNKNOWN_FAILURE
* OEMCrypto_ERROR_INVALID_CONTEXT
* OEMCrypto_ERROR_SIGNATURE_FAILURE
* OEMCrypto_ERROR_INVALID_NONCE
* OEMCrypto_ERROR_TOO_MANY_KEYS
*/
OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
const uint8_t* enc_mac_key_iv,
const uint8_t* enc_mac_key,
size_t num_keys,
const OEMCrypto_KeyObject* key_array);
/*
* OEMCrypto_RefreshKeys
*
* Description:
* Updates an existing set of keys for continuing decryption in the
* current session.
*
* The relevant fields have been extracted from the Renewal Response protocol
* message, but the entire message and associated signature are provided so
* the message can be verified (using HMAC-SHA256 with the current mac_key).
* If the signature verification fails, ignore all other arguments and return
* OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add the keys to the session
* context.
*
* NOTE: OEMCrypto_GenerateDerivedKeys() or OEMCrypto_LoadKeys() must be called
* first to establish the mac_key
*
* Refer to document OEMCrypto Changes for V2 License Protocol for details.
*
* Parameters:
* session (in) - crypto session identifier.
* message (in) - pointer to memory containing message to be verified.
* message_length (in) - length of the message.
* signature (in) - pointer to memory containing the signature.
* signature_length (in) - length of the signature.
* num_keys (in) - number of keys present.
* key_array (in) - set of keys to be installed.
*
* Threading:
* This function may be called simultaneously with functions on other sessions,
* but not with other functions on this session.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_NO_DEVICE_KEY
* OEMCrypto_ERROR_INVALID_SESSION
* OEMCrypto_ERROR_UNKNOWN_FAILURE
* OEMCrypto_ERROR_INVALID_CONTEXT
* OEMCrypto_ERROR_SIGNATURE_FAILURE
*/
OEMCryptoResult
OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
size_t num_keys,
const OEMCrypto_KeyRefreshObject* key_array);
/*
* OEMCrypto_SelectKey
*
* Description:
* Select a content key and install it in the hardware key ladder for
* subsequent decryption operations (OEMCrypto_DecryptCTR()) for this session.
* The specified key must have been previously "installed" via
* OEMCrypto_LoadKeys() or OEMCrypto_RefreshKeys().
*
* A key control block is associated with the key and the session, and is used
* to configure the session context. The Key Control data is documented in
* "Key Control Block Definition".
*
* Step 1: Lookup the content key data via the offered key_id. The key data
* includes the key value, the content key IV, the key control
* block, and the key control block IV.
*
* Step 2: Latch the content key into the hardware key ladder. Set
* permission flags and timers based on the key's control block.
*
* Step 3: use the latched content key to decrypt (AES-128-CTR)
* to decrypt buffers passed in via OEMCrypto_DecryptCTR(). Continue
* to use this key until OEMCrypto_SelectKey() is called again, or
* until OEMCrypto_CloseSession() is called.
*
* Parameters:
* session (in) - crypto session identifier
* key_id (in) - pointer to the Key ID
* key_id_length (in) - length of the Key ID in bytes
*
* Threading:
* This function may be called simultaneously with functions on other sessions,
* but not with other functions on this session.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_INVALID_SESSION crypto session ID invalid or not open
* OEMCrypto_ERROR_NO_DEVICE_KEY failed to decrypt device key
* OEMCrypto_ERROR_NO_CONTENT_KEY failed to decrypt content key
* OEMCrypto_ERROR_CONTROL_INVALID invalid or unsupported control input
* OEMCrypto_ERROR_KEYBOX_INVALID cannot decrypt and read from Keybox
*/
OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
const uint8_t* key_id,
size_t key_id_length);
/*
* OEMCrypto_DecryptCTR
*
* Description:
*
* The API decrypts (AES-CTR) the payload in the buffer referenced by
* the buffer_addr parameter into an internal buffer, using the key
* identified by key_id.
*
* Parameters:
* session (in) - crypto session identifier.
* data_addr (in) - An unaligned pointer to this segment of the stream.
* data_length (in) - The length of this segment of the stream.
* is_encrypted (in) - True if the buffer described by data_addr,
* data_length is encrypted. If is_encrypted is false, only the
* data_addr and data_length parameters are used. The iv and offset
* arguments are ignored.
* iv (in) - The initial value block to be used for content decryption.
* This is discussed further below.
* offset (in) - If non-zero, the decryption block boundary is different
* from the start of the data. offset should be subtracted from
* data_addr to compute the starting address of the first decrypted
* block. The bytes between the decryption block start address and
* data_addr are discarded after decryption.
* out_buffer (in) - A caller-owned descriptor that specifies the
* handling of the decrypted byte stream. See OEMCrypto_DestbufferDesc
* for details.
*
* AES CTR is a stream cipher. The stream may be composed of arbitrary-
* length clear and encrypted segments. The encrypted portions of a sample
* are collectively treated as a continuous sequence of decryption
* block-sized blocks even though the sequence is interrupted by clear blocks.
* This means a given encrypted segment may not start or end on a decryption
* block boundary.
*
* If data_addr is not aligned with a decryption block boundary (offset != 0),
* the additional offset bytes before data_addr (pre-padding) are included in
* the decrypt operation, and they are dropped after decryption. If
* data_length + offset is not a multiple of the decryption block size, the
* extra bytes in the final decryption block (post-padding) are also dropped
* after decryption. The caller is responsible for guaranteeing that all
* memory addresses from (data-addr - pre-padding) to (data-addr +
* data-length + post-padding) are valid memory addresses.
*
* After decrypting the entire buffer including any pre-padding and
* post-padding, send data_length bytes starting at data_addr to the decoder.
*
* NOTES:
* IV points to the counter value to be used for the initial
* encrypted block of the input buffer. The IV length is the AES
* block size. For subsequent encrypted AES blocks the IV is
* calculated by incrementing the lower 64 bits (byte 8-15) of the
* IV value used for the previous block. The counter rolls over to
* zero when it reaches its maximum value (0xFFFFFFFFFFFFFFFF).
* The upper 64 bits (byte 0-7) of the IV do not change.
*
* Threading:
* This function may be called simultaneously with functions on other sessions,
* but not with other functions on this session.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_NO_DEVICE_KEY
* OEMCrypto_ERROR_INVALID_SESSION
* OEMCrypto_ERROR_UNKNOWN_FAILURE
* OEMCrypto_ERROR_INVALID_CONTEXT
* OEMCrypto_ERROR_DECRYPT_FAILED
*/
OEMCryptoResult
OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
const uint8_t *data_addr,
size_t data_length,
bool is_encrypted,
const uint8_t *iv,
size_t offset,
const OEMCrypto_DestBufferDesc* out_buffer);
/*
* OEMCrypto_InstallKeybox
*
* Description:
* Unwrap and store the keybox to persistent memory.
* The device key must be stored securely. The device key will be decrypted
* and latched into hardware key ladder by OEMCrypto_SetEntitlementKey.
*
* This function is used once to load the keybox onto the device at
* provisioning time.
*
* Parameters:
* keybox (in) - Pointer to clear keybox data. Must have been originally
* wrapped with OEMCrypto_WrapKeybox.
* keyboxLength (in) - Length of the keybox data in bytes.
*
* Threading:
* This function is not called simultaneously with any other functions.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_WRITE_KEYBOX failed to handle and store Keybox
*/
OEMCryptoResult OEMCrypto_InstallKeybox(uint8_t *keybox,
size_t keyBoxLength);
/*
* OEMCrypto_IsKeyboxValid
*
* Description:
* Validate the Widevine Keybox stored on the device.
*
* The API performs two verification steps on the Keybox. It first verifies
* the MAGIC field contains a valid signature (must be 'kbox'). The API then
* computes the CRC using CRC-32 (Posix 1003.2 standard) and compares the
* checksum to the CRC stored in the Keybox. The CRC is computed over the
* entire Keybox excluding the 4 CRC bytes (i.e. Keybox[0..123]).
*
* Parameters:
* none
*
* Threading:
* This function may be called simultaneously with any session functions.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_BAD_MAGIC
* OEMCrypto_ERROR_BAD_CRC
*/
OEMCryptoResult OEMCrypto_IsKeyboxValid(void);
/*
* OEMCrypto_GetDeviceID
*
* Description:
* Retrieve the device's unique identifier from the Keybox.
*
* Parameters:
* deviceId (out) - pointer to the buffer that receives the Device ID
* idLength (in/out) - on input, size of the caller's device ID buffer.
* On output, the number of bytes written into the buffer.
*
* Threading:
* This function may be called simultaneously with any session functions.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_SHORT_BUFFER buffer is too small to return the device ID
* OEMCrypto_ERROR_NO_DEVICEID failed to return Device Id
*/
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
size_t *idLength);
/*
* OEMCrypto_GetKeyData
*
* Description:
* Returns the Key Data field from the Keybox. The Key Data field does not
* need to be encrypted by an OEM root key, but may be if desired.
*
* If the Key Data field was encrypted with an OEM root key when the Keybox
* was stored on the device, then this function should decrypt it and return
* the clear Key Data. If the Key Data was not encrypted, then this function
* should just access and return the clear Key data.
*
* Parameters:
* keyData (out) - pointer to a caller-managed buffer to hold the Key Data
* field from the Keybox
* dataLength (in/out) - on input, the allocated buffer size. On output,
* the number of bytes in KeyData.
*
* Threading:
* This function may be called simultaneously with any session functions.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_SHORT_BUFFER the buffer is too small to return the KeyData
* OEMCrypto_ERROR_NO_KEYDATA failed to return KeyData
*/
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,
size_t *keyDataLength);
/*
* OEMCrypto_GetRandom
*
* Description:
* Return a buffer filled with hardware-generated random bytes. If the
* hardware feature does not exist, return OEMCrypto_ERROR_RNG_NOT_SUPPORTED.
*
* Parameters:
* randomData (out) - Pointer to caller-manager buffer that will receive the
* random data.
* dataLength (in) - Length of the random data buffer in bytes.
*
* Threading:
* This function may be called simultaneously with any session functions.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_RNG_FAILED failed to generate random number
* OEMCrypto_ERROR_RNG_NOT_SUPPORTED function not supported
*/
OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData,
size_t dataLength);
/*
* OEMCrypto_WrapKeybox
*
* Description:
* Wrap the Keybox with a key derived for the device key. If transportKey
* is not NULL, the input keybox is encrypted with transportKey. If so,
* decrypt the input keybox before wrapping it, using transportKey in AES-CBC
* mode with an IV of all zeroes. This function is only needed if the
* provisioning method involves saving the keybox to the file system.
*
* Parameters:
* keybox (in) - Pointer to keybox data.
* keyboxLength - Length of the Keybox data in bytes
* wrappedKeybox (out) - Pointer to wrapped keybox
* wrappedKeyboxLength (out) - Pointer to the length of the wrapped keybox in
* bytes
* transportKey (in) - An optional AES transport key. If provided, the input
* keybox is encrypted with this transport key with AES-CBC
* and a null IV.
* transportKeyLength - number of bytes in the transportKey
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_WRAP_KEYBOX failed to wrap Keybox
* OEMCrypto_ERROR_NOT_IMPLEMENTED
*/
OEMCryptoResult OEMCrypto_WrapKeybox(uint8_t *keybox,
size_t keyBoxLength,
uint8_t *wrappedKeybox,
size_t *wrappedKeyBoxLength,
uint8_t *transportKey,
size_t transportKeyLength);
#ifdef __cplusplus
}
#endif
#endif // OEMCRYPTO_DASH_H_

View File

@@ -1,28 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := MockOEMCrypto.cpp \
OEMCryptoWrapper.cpp \
wvcrc.cpp \
LOCAL_C_INCLUDES += vendor/widevine/libclearkeydrmengine/oemcrypto/include \
external/openssl/include \
external/openssh
LOCAL_MODULE := libmockoemcrypto
LOCAL_MODULE_TAGS := tests
LOCAL_SHARED_LIBRARIES := \
libstlport \
liblog \
libcorkscrew \
libutils \
libz \
libcutils \
libcrypto \
libdl
include $(BUILD_STATIC_LIBRARY)

View File

@@ -1,419 +0,0 @@
/*********************************************************************
* MockOEMCrypto.cpp
*
* (c) Copyright 2011-2012 Google, Inc.
*
* Mock implementation of OEMCryptoDASH.h used for testing.
*********************************************************************/
#define LOG_TAG "WV.MockOEMCrypto"
#include <utils/Log.h>
#include <utils/String8.h>
#include "OEMCryptoDASH.h"
#include "MockOEMCrypto.h"
#include "openssl/rand.h"
#include "openssl/aes.h"
#include "openssl/cmac.h"
#include "openssl/hmac.h"
#include "wvcrc32.h"
#include "arpa/inet.h"
#include <stdio.h>
using namespace android;
namespace wvdrm {
MockOEMCrypto* MockOEMCrypto::sSingleton = NULL;
static struct BinaryKeybox kDefaultKeybox = {
// Sample keybox used for test vectors
{
// deviceID
0x74, 0x65, 0x73, 0x74, 0x69, 0x64, 0x00, 0x00, // testid..
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
}, {
// key
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}, {
// data
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78
}, {
// Crc
0x00, 0x00, 0x00, 0x00
}
};
MockOEMCrypto::MockOEMCrypto(BinaryKeybox *keybox) {
if (keybox == NULL) keybox = &kDefaultKeybox;
memcpy(&mKeybox, keybox, sizeof(BinaryKeybox));
mInitialized = false;
mClearKeys = true; // XXX -- default to clear keys for initial demo.
mMaxId = 0;
}
MockOEMCrypto::~MockOEMCrypto() {
}
OEMCryptoResult MockOEMCrypto::initialize(void) {
if (mInitialized) {
ALOGE( "[OEMCrypto_Initialize(): failed -- already initialized]\n" );
return OEMCrypto_ERROR_INIT_FAILED;
}
mInitialized = true;
ALOGV( "[OEMCrypto_Initialize(): success]\n" );
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockOEMCrypto::terminate(void) {
if (!mInitialized) {
ALOGE( "[OEMCrypto_Terminate(): failed - not initialized]\n" );
return OEMCrypto_ERROR_TERMINATE_FAILED;
}
mInitialized = false;
ALOGV( "[OEMCrypto_Terminate(): success]\n" );
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockOEMCrypto::openSession(OEMCrypto_SESSION *session) {
mMaxId++;
MockSession *s = new MockSession(mMaxId);
Mutex::Autolock lock(mSessionListMutex);
mSessions.add(mMaxId, s);
*session = mMaxId;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockOEMCrypto::closeSession(OEMCrypto_SESSION session) {
Mutex::Autolock lock(mSessionListMutex);
ssize_t index = mSessions.indexOfKey(session);
if (index < 0) return OEMCrypto_ERROR_INVALID_SESSION;
mSessions.removeItem(session);
return OEMCrypto_SUCCESS;
}
MockSession *MockOEMCrypto::findSession(OEMCrypto_SESSION session) {
Mutex::Autolock lock(mSessionListMutex);
ssize_t index = mSessions.indexOfKey(session);
if (index < 0) return NULL;
return mSessions.valueAt(index).get();
}
MockSession::MockSession(OEMCrypto_SESSION id) {
mId = id;
mCurrentKey = NULL;
mNoKeyLoaded = true;
}
MockSession::~MockSession() {
}
static void aes_128_cmac(const uint8_t key[16], const uint8_t *data, size_t len, uint8_t *dest) {
// Quote from openssl tutorial:
// "Check out the function print_cmac_gen in the file fips/cmac/fips_cmactest.c"
CMAC_CTX *cmac_ctx = CMAC_CTX_new();
CMAC_Init(cmac_ctx, key, 16, EVP_aes_128_cbc(), 0);
CMAC_Update(cmac_ctx, data, len);
size_t reslen;
unsigned char res[128];
if (!CMAC_Final(cmac_ctx, res, &reslen)) {
ALOGE("Error calculating CMAC\n");
} else if (16 != reslen) {
ALOGE("Parameter error, CMAC length = %d\n", reslen);
} else {
memcpy(dest, res, 16);
}
CMAC_CTX_free(cmac_ctx);
}
OEMCryptoResult MockSession::generateDerivedKeys(const uint8_t *mac_key_context,
uint32_t mac_key_context_length,
const uint8_t *enc_key_context,
uint32_t enc_key_context_length) {
uint8_t enc_buffer[enc_key_context_length + 1];
memcpy( enc_buffer+1, enc_key_context, enc_key_context_length);
enc_buffer[0] = 0x01;
aes_128_cmac(MockOEMCrypto::sSingleton->mKeybox.mKey,
enc_buffer, enc_key_context_length+1, mEncryptKey);
uint8_t mac_buffer[mac_key_context_length + 1];
memcpy( mac_buffer+1, mac_key_context, mac_key_context_length);
mac_buffer[0] = 0x01;
aes_128_cmac(MockOEMCrypto::sSingleton->mKeybox.mKey,
mac_buffer, mac_key_context_length+1, mMacKey);
mac_buffer[0] = 0x02;
aes_128_cmac(MockOEMCrypto::sSingleton->mKeybox.mKey,
mac_buffer, mac_key_context_length+1, mMacKey+16);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockSession::generateNonce(uint32_t* nonce) {
RAND_bytes((uint8_t *)nonce, 4);
mNonce = *nonce;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockSession::generateSignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length) {
if (*signature_length < 32) {
*signature_length = 32;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if ( HMAC( EVP_sha256(), mMacKey, 32, message, message_length,
signature, signature_length) ) {
return OEMCrypto_SUCCESS;
}
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult MockSession::loadKeys(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
const uint8_t* enc_mac_key_iv,
const uint8_t* enc_mac_key,
size_t num_keys,
const OEMCrypto_KeyObject* key_array) {
uint8_t computed_signature[32];
if ( ! HMAC( EVP_sha256(), mMacKey, 32, message, message_length,
computed_signature, &signature_length) ) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (signature_length != 32 || memcmp(signature, computed_signature, 32)) {
ALOGE("Computed signature does not match.");
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
mKeys.clear();
mKeys.setCapacity(num_keys);
AES_KEY aes_encrypt_key;
AES_set_decrypt_key( mEncryptKey, 128, &aes_encrypt_key);
OEMCryptoResult result = OEMCrypto_SUCCESS;
uint8_t iv[16]; // read/write temporary buffer.
for(size_t i=0; i < num_keys; i++) {
mKeys.add();
mKeys.editItemAt(i).mKeyId.insertArrayAt( key_array[i].key_id, 0, key_array[i].key_id_length);
memcpy( iv, key_array[i].key_data_iv, 16);
AES_cbc_encrypt(key_array[i].key_data, mKeys.editItemAt(i).mKeyData, 16,
&aes_encrypt_key, iv, AES_DECRYPT);
AES_KEY aes_content_key;
AES_set_decrypt_key( mKeys.editItemAt(i).mKeyData, 128, &aes_content_key);
memcpy( iv, key_array[i].key_control_iv, 16);
AES_cbc_encrypt(key_array[i].key_control, (uint8_t *) &(mKeys.editItemAt(i).mControl), 16,
&aes_content_key, iv, AES_DECRYPT);
mKeys.editItemAt(i).mControl.mDuration = ntohl(mKeys[i].mControl.mDuration);
mKeys.editItemAt(i).mControl.mControl = ntohl(mKeys[i].mControl.mControl);
ALOGV("Control Flags are 0x%08x", mKeys[i].mControl.mControl);
ALOGV("Duration is %d", mKeys[i].mControl.mDuration);
if (memcmp( mKeys[i].mControl.mVerification, "kctl", 4)) {
ALOGE("Key Control block %d verification = 0x%08X, expected kctl=0x%08X", i,
*((uint32_t *)(mKeys[i].mControl.mVerification)),
*((uint32_t *)("kctl")));
result = OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (mKeys[i].mControl.mControl & (1<<3)) { // Nonce enabled.
if (mKeys[i].mControl.mNonce != mNonce) {
ALOGE("NONCE ERROR for key %d: got: %08X, expected: %08X", i,
mKeys[i].mControl.mNonce, mNonce);
result = OEMCrypto_ERROR_INVALID_NONCE;
}
}
}
if (result != OEMCrypto_SUCCESS) {
mKeys.clear();
return result;
}
memcpy( iv, enc_mac_key_iv, 16);
AES_cbc_encrypt(enc_mac_key, mMacKey, 32,
&aes_encrypt_key, iv, AES_DECRYPT);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockSession::refreshKeys(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
size_t num_keys,
const OEMCrypto_KeyRefreshObject* key_array) {
// XXX
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
OEMCryptoResult MockSession::selectKey(const uint8_t* key_id,
size_t key_id_length) {
// TODO: handle key_id=0 case. Does that mean following data is not encrypted?
// This is the demo version:
if (MockOEMCrypto::sSingleton->mClearKeys) {
mCurrentKey = &mClearKey;
if (mNoKeyLoaded
|| mClearKey.mKeyId.size() != 16
|| (memcmp(mClearKey.mKeyId.array(), key_id, 16) != 0)) { // Copy it once.
mClearKey.mKeyId.clear();
mClearKey.mKeyId.insertArrayAt( key_id, 0, key_id_length);
memcpy(mClearKey.mKeyData, key_id, 16);
memcpy(mClearKey.mControl.mVerification, "kctl",4);
mClearKey.mControl.mDuration = 0;
mClearKey.mControl.mNonce = 0XABACAB00;
mClearKey.mControl.mDuration = 0;
if (AES_set_encrypt_key(mClearKey.mKeyData, 128, &mClearKey.mKey) < 0) {
ALOGE("Could not set encryption key.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
mNoKeyLoaded = false;
}
return OEMCrypto_SUCCESS;
} else {
for(size_t i=0; i< mKeys.size(); i++) {
if (key_id_length == mKeys[i].mKeyId.size()
&& memcmp(key_id, mKeys[i].mKeyId.array(), key_id_length)) {
mCurrentKey = &mKeys.editItemAt(i);
return OEMCrypto_SUCCESS;
}
}
return OEMCrypto_ERROR_NO_CONTENT_KEY;
}
}
OEMCryptoResult MockSession::decryptCTR(const uint8_t *data_addr,
size_t data_length,
bool is_encrypted,
const uint8_t *iv,
size_t offset,
const OEMCrypto_DestBufferDesc* out_buffer) {
if (mCurrentKey == NULL) {
ALOGE("SelectKey was not called.");
return OEMCrypto_ERROR_NO_CONTENT_KEY;
}
if (mCurrentKey->mControl.mControl & (1<<4)) { // secure only
if (out_buffer->type == OEMCrypto_BufferType_Clear) {
ALOGE("Key type is secure only, but buffer is not secure.");
return OEMCrypto_ERROR_CONTROL_INVALID;
}
}
uint8_t *dest;
if (out_buffer->type == OEMCrypto_BufferType_Direct) {
ALOGV("Buffer type is direct. No work to do.");
return OEMCrypto_SUCCESS; // XXX -- send directdly to video.
} else if (out_buffer->type == OEMCrypto_BufferType_Direct) {
dest = (uint8_t *)out_buffer->buffer.secure.handle;
if (data_length > out_buffer->buffer.secure.max_length) {
ALOGE("Secure Buffer is %d long, but wanted %d.",
out_buffer->buffer.secure.max_length, data_length);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
} else {
dest = out_buffer->buffer.clear.address;
if (data_length > out_buffer->buffer.clear.max_length) {
ALOGE("Buffer is %d long, but wanted %d.",
out_buffer->buffer.clear.max_length, data_length);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
}
if (! is_encrypted) {
memcpy(dest, data_addr, data_length);
return OEMCrypto_SUCCESS;
}
uint8_t buffer[offset + data_length];
unsigned int num = 0;
uint8_t ivec[AES_BLOCK_SIZE];
uint8_t ecount[AES_BLOCK_SIZE];
memset(ecount, 0, AES_BLOCK_SIZE);
memcpy(ivec, iv, AES_BLOCK_SIZE);
AES_ctr128_encrypt(data_addr+(-offset), buffer, data_length+offset,
&(mCurrentKey->mKey), ivec, ecount, &num);
memcpy(dest, buffer+offset, data_length);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockOEMCrypto::installKeybox(uint8_t *keybox,
size_t keyBoxLength) {
ALOGV("OEMCryptoResult OEMCrypto_InstallKeybox\n");
if (keyBoxLength != 128) { /* 128 = sizeof(struct Debug_Keybox). */
ALOGE("The keybox has the wrong length = %d.\n", keyBoxLength);
return OEMCrypto_ERROR_WRITE_KEYBOX;
}
memcpy( & mKeybox, keybox, keyBoxLength);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockOEMCrypto::isKeyboxValid(void) {
ALOGV("OEMCryptoResult OEMCrypto_IsKeyboxValid\n");
if (strncmp((char*)mKeybox.mMagic, "kbox", 4) != 0) {
ALOGE("Magic is not 'kbox'=0x%08x, it is '%4.4s'=0x%08x\n",
*((uint32_t *)("kbox")),
mKeybox.mMagic, *((uint32_t *)(mKeybox.mMagic)));
return OEMCrypto_ERROR_BAD_MAGIC;
}
uint32_t crc_computed;
uint32_t *crc_stored = (uint32_t *)mKeybox.mCrc;
// XXX -------------------------------------------------------------------
// XXX TODO: verify that CRC in keybox is in network byte order.
// XXX -------------------------------------------------------------------
crc_computed = ntohl(wvcrc32( mKeybox.mDeviceId, 124));
if (crc_computed != *crc_stored) {
ALOGE("CRC problem: computed = %08x, stored = %08x.\n", crc_computed, *crc_stored);
return OEMCrypto_ERROR_BAD_CRC;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockOEMCrypto::getDeviceID(uint8_t* deviceID,
size_t *idLength) {
ALOGV("OEMCryptoResult OEMCrypto_GetDeviceID -> %s\n", mKeybox.mDeviceId);
size_t size = strnlen( (char *)mKeybox.mDeviceId, 31) + 1;
if (*idLength < size) {
*idLength = size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*idLength = size;
memcpy( deviceID, mKeybox.mDeviceId, size );
return OEMCrypto_SUCCESS;
}
OEMCryptoResult MockOEMCrypto::getKeyData(uint8_t* keyData,
size_t *keyDataLength) {
ALOGV("OEMCryptoResult OEMCrypto_GetKeyData\n");
if (*keyDataLength < sizeof(mKeybox.mData)) {
*keyDataLength = sizeof(mKeybox.mData);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*keyDataLength = sizeof(mKeybox.mData);
memcpy( keyData, mKeybox.mData, sizeof(mKeybox.mData));
return OEMCrypto_SUCCESS;
}
}; // namespace wvdrm

View File

@@ -1,146 +0,0 @@
/*********************************************************************
* MockOEMCrypto.h
*
* (c) Copyright 2011-2012 Google, Inc.
*
* Mock implementation of OEMCrypto.h used for testing.
*********************************************************************/
#ifndef WV_MOCK_OEMCRYPTO_H_
#define WV_MOCK_OEMCRYPTO_H_
#include "OEMCryptoDASH.h"
#include <openssl/aes.h>
#include <stdint.h>
#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <media/stagefright/foundation/ABase.h>
namespace wvdrm {
// Widevine keybox.
struct BinaryKeybox { // 128 bytes total.
uint8_t mDeviceId[32]; // C character string identifying the device. Null terminated.
uint8_t mKey[16]; // 128 bit AES key assigned to device. Generated by Widevine.
uint8_t mData[72]; // Key Data. Encrypted data.
uint8_t mMagic[4]; // Constant code used to recognize a valid keybox "kbox" = 0x6b626f78.
uint8_t mCrc[4]; // The CRC checksum of the first 124 bytes of the keybox.
};
struct OEMCrypto_KeyControl {
uint8_t mVerification[4]; // Known pattern to verify decryption is
// successful = kctl
uint32_t mDuration; // Maximum number of seconds during which the key
// can be used after being set. Interpret 0 as
// unlimited. (Network Byte Order)
uint32_t mNonce;
uint32_t mControl; // Bit field. (Network Byte Order)
// bit 4: data path type: 0 normal, 1 = secure only.
// bit 3: nonce enabled. 0 = ignore, 1 = requre nonce.
// bit 2: HDCP: 0 = not required, 1 = required.
// bit 1:0 CGMS control: 0 = copy freely, 2= copy once. 3= copy never.
};
enum KeyType {
SIGNING = 1,
CONTENT_ANY = 2,
CONTENT_AUDIO = 3,
CONTENT_VIDEO = 4
};
struct ControlledKey {
android::Vector<uint8_t> mKeyId;
OEMCrypto_KeyControl mControl;
uint8_t mKeyData[16];
AES_KEY mKey;
};
class MockSession : public android::RefBase {
public:
OEMCrypto_SESSION mId;
android::Vector<ControlledKey> mKeys;
ControlledKey *mCurrentKey;
bool mNoKeyLoaded;
ControlledKey mClearKey; // Stores a single key, for clear key demo.
uint8_t mMacKey[32];
uint8_t mEncryptKey[16];
uint32_t mNonce;
MockSession(OEMCrypto_SESSION id);
~MockSession();
OEMCryptoResult generateDerivedKeys(const uint8_t *mac_key_context,
uint32_t mac_key_context_length,
const uint8_t *enc_key_context,
uint32_t enc_key_context_length);
OEMCryptoResult generateNonce(uint32_t* nonce);
OEMCryptoResult generateSignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
OEMCryptoResult loadKeys(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
const uint8_t* enc_mac_key_iv,
const uint8_t* enc_mac_key,
size_t num_keys,
const OEMCrypto_KeyObject* key_array);
OEMCryptoResult refreshKeys(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
size_t num_keys,
const OEMCrypto_KeyRefreshObject* key_array);
OEMCryptoResult selectKey(const uint8_t* key_id,
size_t key_id_length);
OEMCryptoResult decryptCTR(const uint8_t *data_addr,
size_t data_length,
bool is_encrypted,
const uint8_t *iv,
size_t offset,
const OEMCrypto_DestBufferDesc* out_buffer);
DISALLOW_EVIL_CONSTRUCTORS(MockSession);
};
class MockOEMCrypto : public android::RefBase {
public:
static MockOEMCrypto *sSingleton;
bool mInitialized;
BinaryKeybox mKeybox;
OEMCrypto_SESSION mMaxId;
android::KeyedVector<OEMCrypto_SESSION, android::sp<MockSession> > mSessions;
android::Mutex mSessionListMutex; // This locks list access only, not the items in the list.
// TODO: max sessions.
// TODO max keys.
bool mClearKeys;
MockOEMCrypto(BinaryKeybox *keybox = NULL);
virtual OEMCryptoResult initialize(void);
virtual OEMCryptoResult terminate(void);
virtual OEMCryptoResult openSession(OEMCrypto_SESSION *session);
virtual OEMCryptoResult closeSession(OEMCrypto_SESSION session);
virtual MockSession *findSession(OEMCrypto_SESSION id);
virtual OEMCryptoResult installKeybox(uint8_t *keybox,
size_t keyBoxLength);
virtual OEMCryptoResult isKeyboxValid(void);
virtual OEMCryptoResult getDeviceID(uint8_t* deviceID,
size_t* idLength);
virtual OEMCryptoResult getKeyData(uint8_t* keyData,
size_t* keyDataLength);
virtual ~MockOEMCrypto();
DISALLOW_EVIL_CONSTRUCTORS(MockOEMCrypto);
};
}
#endif // _WV_MOCK_OEMCRYPTO_H_

View File

@@ -1,239 +0,0 @@
/*********************************************************************
* OEMCryptoWrapper.cpp
*
* (c) Copyright 2011-2012 Google, Inc.
*
* OEMCryptoDASH fuctions wrapped around a Mock OEMCrypto object.
*********************************************************************/
#define LOG_TAG "WV.MockOEMCrypto"
#include <utils/Log.h>
#include <utils/String8.h>
#include "OEMCryptoDASH.h"
#include "MockOEMCrypto.h"
#include "openssl/rand.h"
using namespace android;
using namespace wvdrm;
extern "C"
OEMCryptoResult OEMCrypto_Initialize(void) {
if (MockOEMCrypto::sSingleton == NULL) MockOEMCrypto::sSingleton = new MockOEMCrypto();
return MockOEMCrypto::sSingleton->initialize();
}
extern "C"
OEMCryptoResult OEMCrypto_Terminate(void) {
if (!MockOEMCrypto::sSingleton) {
ALOGE( "[OEMCrypto_Terminate(): failed - not initialized, no engine]\n" );
return OEMCrypto_ERROR_TERMINATE_FAILED;
}
return MockOEMCrypto::sSingleton->terminate();
}
extern "C"
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION *session) {
if (! MockOEMCrypto::sSingleton) {
ALOGE("OEMCrypto not initialized");
return OEMCrypto_ERROR_OPEN_SESSION_FAILED;
}
return MockOEMCrypto::sSingleton->openSession(session);
}
extern "C"
OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session) {
if (! MockOEMCrypto::sSingleton) {
ALOGE("OEMCrypto not initialized");
return OEMCrypto_ERROR_TERMINATE_FAILED;
}
return MockOEMCrypto::sSingleton->closeSession(session);
}
extern "C"
OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session,
const uint8_t *mac_key_context,
uint32_t mac_key_context_length,
const uint8_t *enc_key_context,
uint32_t enc_key_context_length) {
if (! MockOEMCrypto::sSingleton) {
ALOGE("OEMCrypto not initialized");
return OEMCrypto_ERROR_INVALID_SESSION;
}
MockSession *s = MockOEMCrypto::sSingleton->findSession(session);
if (!s) {
ALOGE("OEMCrypto no session for id %d", session);
return OEMCrypto_ERROR_INVALID_SESSION;
}
return s->generateDerivedKeys(mac_key_context,mac_key_context_length,
enc_key_context, enc_key_context_length);
}
extern "C"
OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
uint32_t* nonce) {
if (! MockOEMCrypto::sSingleton) {
ALOGE("OEMCrypto not initialized");
return OEMCrypto_ERROR_INVALID_SESSION;
}
MockSession *s = MockOEMCrypto::sSingleton->findSession(session);
if (!s) {
ALOGE("OEMCrypto no session for id %d", session);
return OEMCrypto_ERROR_INVALID_SESSION;
}
return s->generateNonce(nonce);
}
extern "C"
OEMCryptoResult OEMCrypto_GenerateSignature(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length) {
if (! MockOEMCrypto::sSingleton) {
ALOGE("OEMCrypto not initialized");
return OEMCrypto_ERROR_INVALID_SESSION;
}
MockSession *s = MockOEMCrypto::sSingleton->findSession(session);
if (!s) {
ALOGE("OEMCrypto no session for id %d", session);
return OEMCrypto_ERROR_INVALID_SESSION;
}
return s->generateSignature(message, message_length,
signature, signature_length);
}
extern "C"
OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
const uint8_t* enc_mac_key_iv,
const uint8_t* enc_mac_key,
size_t num_keys,
const OEMCrypto_KeyObject* key_array) {
if (! MockOEMCrypto::sSingleton) {
ALOGE("OEMCrypto not initialized");
return OEMCrypto_ERROR_INVALID_SESSION;
}
MockSession *s = MockOEMCrypto::sSingleton->findSession(session);
if (!s) {
ALOGE("OEMCrypto no session for id %d", session);
return OEMCrypto_ERROR_INVALID_SESSION;
}
return s->loadKeys(message, message_length, signature, signature_length,
enc_mac_key_iv, enc_mac_key,
num_keys, key_array);
}
extern "C"
OEMCryptoResult
OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
size_t num_keys,
const OEMCrypto_KeyRefreshObject* key_array) {
if (! MockOEMCrypto::sSingleton) {
ALOGE("OEMCrypto not initialized");
return OEMCrypto_ERROR_INVALID_SESSION;
}
MockSession *s = MockOEMCrypto::sSingleton->findSession(session);
if (!s) {
ALOGE("OEMCrypto no session for id %d", session);
return OEMCrypto_ERROR_INVALID_SESSION;
}
return s->refreshKeys(message, message_length, signature,
signature_length, num_keys, key_array);
}
extern "C"
OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
const uint8_t* key_id,
size_t key_id_length) {
if (! MockOEMCrypto::sSingleton) {
ALOGE("OEMCrypto not initialized");
return OEMCrypto_ERROR_INVALID_SESSION;
}
MockSession *s = MockOEMCrypto::sSingleton->findSession(session);
if (!s) {
ALOGE("OEMCrypto no session for id %d", session);
return OEMCrypto_ERROR_INVALID_SESSION;
}
return s->selectKey(key_id, key_id_length);
}
extern "C"
OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
const uint8_t *data_addr,
size_t data_length,
bool is_encrypted,
const uint8_t *iv,
size_t offset,
const OEMCrypto_DestBufferDesc* out_buffer) {
if (! MockOEMCrypto::sSingleton) {
ALOGE("OEMCrypto not initialized");
return OEMCrypto_ERROR_INVALID_SESSION;
}
MockSession *s = MockOEMCrypto::sSingleton->findSession(session);
if (!s) {
ALOGE("OEMCrypto no session for id %d", session);
return OEMCrypto_ERROR_INVALID_SESSION;
}
return s->decryptCTR(data_addr, data_length, is_encrypted,
iv, offset, out_buffer);
}
extern "C"
OEMCryptoResult OEMCrypto_InstallKeybox(uint8_t *keybox,
size_t keyBoxLength) {
if (!MockOEMCrypto::sSingleton) {
MockOEMCrypto::sSingleton = new MockOEMCrypto(NULL);
}
return MockOEMCrypto::sSingleton->installKeybox(keybox, keyBoxLength);
}
extern "C"
OEMCryptoResult OEMCrypto_IsKeyboxValid(void) {
if (!MockOEMCrypto::sSingleton) {
MockOEMCrypto::sSingleton = new MockOEMCrypto(NULL);
}
return MockOEMCrypto::sSingleton->isKeyboxValid();
}
extern "C"
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
size_t *idLength) {
if (MockOEMCrypto::sSingleton == NULL) MockOEMCrypto::sSingleton = new MockOEMCrypto();
return MockOEMCrypto::sSingleton->getDeviceID(deviceID, idLength);
}
extern "C"
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,
size_t *keyDataLength) {
if (MockOEMCrypto::sSingleton == NULL) MockOEMCrypto::sSingleton = new MockOEMCrypto();
return MockOEMCrypto::sSingleton->getKeyData(keyData, keyDataLength);
}
extern "C"
OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData,
size_t dataLength) {
ALOGV("OEMCryptoResult OEMCrypto_GetRandom\n");
if (RAND_bytes(randomData, dataLength)) {
return OEMCrypto_SUCCESS;
} else {
return OEMCrypto_ERROR_RNG_FAILED;
}
}
extern "C"
OEMCryptoResult OEMCrypto_WrapKeybox(uint8_t *keybox,
size_t keyBoxLength,
uint8_t *wrappedKeybox,
size_t *wrappedKeyBoxLength,
uint8_t *transportKey,
size_t transportKeyLength) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}

View File

@@ -1,93 +0,0 @@
/*********************************************************************
* wvcrc32.cpp
*
* (c) Copyright 2011-2012 Google, Inc.
*
* Compte CRC32 Checksum. Needed for verification of WV Keybox.
*********************************************************************/
#include "wvcrc32.h"
#define INIT_CRC32 0xffffffff
uint32_t wvrunningcrc32(uint8_t* p_begin, int i_count, uint32_t i_crc) {
static uint32_t CRC32[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
/* Calculate the CRC */
while (i_count > 0) {
i_crc = (i_crc << 8) ^ CRC32[(i_crc >> 24) ^ ((uint32_t) * p_begin) ];
p_begin++;
i_count--;
}
return(i_crc);
}
uint32_t wvcrc32(uint8_t* p_begin, int i_count) {
return(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
}

View File

@@ -1,16 +0,0 @@
/*********************************************************************
* wvcrc32.h
*
* (c) Copyright 2011-2012 Google, Inc.
*
* Compte CRC32 Checksum. Needed for verification of WV Keybox.
*********************************************************************/
#ifndef WV_CRC_32_H_
#define WV_CRC_32_H_
#include <stdint.h>
uint32_t wvcrc32(uint8_t* p_begin, int i_count);
#endif // WV_MOCK_OEMCRYPTO_H_

View File

@@ -1,37 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
TestOEMCrypto.cpp
LOCAL_MODULE_TAGS := tests
LOCAL_C_INCLUDES += \
bionic \
vendor/widevine/libclearkeydrmengine/oemcrypto/include \
vendor/widevine/libclearkeydrmengine/oemcrypto/mock \
external/gtest/include \
external/openssl/include \
external/stlport/stlport \
LOCAL_STATIC_LIBRARIES := \
libgtest \
libgtest_main \
libmockoemcrypto # This is used before a real OEMCrypto library exists.
LOCAL_SHARED_LIBRARIES := \
libstlport \
liblog \
libutils \
libz \
libcutils \
libdl \
libcrypto \
LOCAL_MODULE:=test-oemcrypto
include $(BUILD_EXECUTABLE)
# Sublibraries Needed:
include vendor/widevine/libclearkeydrmengine/oemcrypto/mock/Android.mk

View File

@@ -1,528 +0,0 @@
/*
* Copyright (C) 2011 Google, Inc. All Rights Reserved
* Requires gtest "mm $ANDROID/external/gtest" before mm in this directory.
*/
#include <stdlib.h>
#include <unistd.h>
#include <termio.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>
#define LOG_TAG "WV.TestOEMCrypto"
#include <utils/Log.h>
#include <openssl/aes.h>
#include "OEMCryptoDASH.h" // Unit Test 1: The header file must compile.
#include "MockOEMCrypto.h"
#include "gtest/gtest.h"
using namespace wvdrm;
// Make an array of bytes from the string in Hexidecimal.
uint8_t * makeArray(const char *hex, size_t *length=NULL) {
size_t hex_length = strlen(hex);
uint8_t* array = new uint8_t[hex_length/2];
size_t hex_index = 0;
size_t array_index = 0;
while( hex_index < hex_length) {
// skip spaces and dashes.
if ((hex[hex_index] == '-') || (hex[hex_index] == ' ')) {
hex_index++;
} else {
unsigned int value;
sscanf(hex +hex_index, "%02x", &value);
array[array_index] = value;
hex_index += 2;
array_index += 1;
}
}
if (length != NULL) *length = array_index;
return array;
}
class OEMCryptoTest : public testing::Test {
protected:
virtual void SetUp() {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize())
<< "OEMCrypto_Initialize failed.";
}
virtual void TearDown() {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate())
<< "OEMCrypto_Terminate failed.";
}
public:
};
TEST_F(OEMCryptoTest, MockOEMCrypto_isKeyboxValid) {
ASSERT_EQ(OEMCrypto_IsKeyboxValid(), OEMCrypto_SUCCESS);
}
TEST_F(OEMCryptoTest, MockOEMCrypto_GenerateDerivedKeys) {
OEMCrypto_SESSION session;
// This is the Eureka test key.
static const uint8_t device_key[16] = {
0x89, 0xc0, 0x85, 0x0c, 0xbd, 0xcd, 0xa9, 0x62,
0xdc, 0x33, 0x2f, 0x96, 0x0e, 0x11, 0xcc, 0x67,
};
memcpy(MockOEMCrypto::sSingleton->mKeybox.mKey, device_key, 16);
// This data was captured from a successful licence request using the Eureka
// test data. I'm just going to borrow it.
uint32_t mac_length = 0;
const uint8_t *mac_context = makeArray("41555448454e5449434154494f4e00" // AUTHENTICATION
"0a4c0800124800000002000001241f34"
"4db9dff087f01d917910f39b60dc7797"
"cd97789ee82516dc07a478cb70b8c08c"
"299293150aa8e01d2dc9808c98daa16e"
"40a0e55dfe3618c7584dd3c7be42122c"
"122a0a10303132333435363738394142"
"4344454610011a146d79436f6f6c5265"
"71756573742c20447564652118012000"
"00000100", &mac_length);
uint32_t enc_length = 0;
const uint8_t *enc_context = makeArray("454e4352595054494f4e00" // ENCRYPTION
"0a4c0800124800000002000001241f34"
"4db9dff087f01d917910f39b60dc7797"
"cd97789ee82516dc07a478cb70b8c08c"
"299293150aa8e01d2dc9808c98daa16e"
"40a0e55dfe3618c7584dd3c7be42122c"
"122a0a10303132333435363738394142"
"4344454610011a146d79436f6f6c5265"
"71756573742c20447564652118012000"
"00000080",
&enc_length);
uint32_t key_length = 0;
const uint8_t* mac_key = makeArray("d53c018d4a4d2cdb19685d1764845a87"
"7474dc020a2d19225d385ce2176bd61c",
&key_length);
EXPECT_EQ(32, (int)key_length) << "The mac key has the wrong length.";
const uint8_t* enc_key = makeArray("9713d57529b9f0a84fa06371af92b791",
&key_length);
EXPECT_EQ(16, (int)key_length) << "The encrypt key has the wrong length";
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session))
<< "OpenSession not successful.";
MockSession* ms = MockOEMCrypto::sSingleton->findSession(session);
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GenerateDerivedKeys(session, mac_context, mac_length,
enc_context, enc_length))
<< "GenerateDerivedKeys failed.";
EXPECT_EQ(0, memcmp(ms->mEncryptKey, enc_key, 16));
EXPECT_EQ(0, memcmp(ms->mMacKey, mac_key, 32));
// printf("\n--------------------------\n");
// printf("enc is: ");
// for(int i=0; i < 16; i++) printf(" %02x", ms->encrypt_key[i]);
// printf("\n");
// printf("should: ");
// for(int i=0; i < 16; i++) printf(" %02x", enc_key[i]);
// printf("\n");
// printf("\n--------------------------\n");
// printf("mac is: ");
// for(int i=0; i < 32; i++) printf(" %02x", ms->mac_key[i]);
// printf("\n");
// printf("should: ");
// for(int i=0; i < 32; i++) printf(" %02x", mac_key[i]);
// printf("\n");
// printf("\n--------------------------\n");
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session))
<< "OEMCrypto_CloseSesion failed.";
EXPECT_EQ(OEMCrypto_ERROR_INVALID_SESSION, OEMCrypto_CloseSession(session))
<< "Can only close session once. ";
}
TEST_F(OEMCryptoTest, MockOEMCrypto_GenerateSignature) {
OEMCrypto_SESSION session;
// session = 0xdeadbeef;
size_t message_length = 0;
const uint8_t* message = makeArray("0a300a146d79436f6f6c526571756573"
"742c2044756465211208ec2316261123"
"b47c1a0a507572636861736573212001"
"28001204080118011a3612103cb829f7"
"c0241dc1434982d9e059ae0d1a20015f"
"6157446481b9a32823c2657c9c464fe2"
"e6115e96963f1d3c484ce95bff1e2001"
"1a2e0a066b657920696412104e793f3b"
"ef67bc83f7deacfbf1e9d3851a101308"
"fb0835bda16782f902f5c49644d52002"
"209580ff8505", &message_length);
uint8_t signature[32];
uint32_t signature_length = 32;
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session));
// MockSession *ms = MockOEMCrypto::sSingleton->findSession(session);
// TODO: enter some test vectors.
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GenerateSignature(session, message, message_length,
signature, &signature_length))
<< "Generate signature failed.";
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session))
<< "OEMCrypto_CloseSesion failed.";
delete [] message;
}
/* Test a single call to decryptCTR. */
TEST_F(OEMCryptoTest, MockOEMCrypto_DecryptContent) {
OEMCrypto_SESSION session;
// session = 0xdeadbeef;
// This is the test content from iStreamPlanet.
size_t keyid_length = 0;
const uint8_t* keyid = makeArray("60061e01-7e57-5e57-ce57-d00d1ed00d1e",
&keyid_length);
EXPECT_EQ(16, (int)keyid_length) << "Key ID setup incorrectly.";
size_t key_length = 0;
const uint8_t* key = makeArray("1a 8a 20 95 e4 de b2 d2 9e c8 16 ac 7b ae 20 82",
&keyid_length);
EXPECT_EQ(16, (int)keyid_length) << "Key setup incorrectly.";
uint8_t * iv = makeArray("000102030405060708090a0b0c0d0e0f");
uint8_t ecount[16];
uint8_t ivec[16];
unsigned int num = 0;
memset(ecount, 0, 16);
memcpy(ivec, iv, 16);
AES_KEY aes_key;
AES_set_encrypt_key(key, 128, &aes_key);
int bytes_read, bytes_written;
const size_t count = 751; // a nice big number, but not too round.
unsigned char indata[count];
unsigned char outdata[count];
memset(indata, 0xAA, count);
AES_ctr128_encrypt(indata, outdata, count, &aes_key, ivec, ecount, &num);
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session))
<< "OEMCrypto_OpenSession failed.";
// TODO: turn on clear keys. Or rather, allow clear keys to be turned off.
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session, key, keyid_length))
<< "OEMCrypto_SelectKey failed.";
OEMCrypto_DestBufferDesc out_buffer;
out_buffer.type = OEMCrypto_BufferType_Clear;
out_buffer.buffer.clear.address = new uint8_t[count];
out_buffer.buffer.clear.max_length = count;
memset(out_buffer.buffer.clear.address, 0, count);
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DecryptCTR(session, outdata, count, true, iv,
0, // offset=0
&out_buffer)) << "OEMCrypto_DecryptCTR";
EXPECT_EQ(0, memcmp(indata,out_buffer.buffer.clear.address, count))
<< "Final result was wrong.";
// printf("\n--------------------------\n");
// printf("ivec : ");
// for(int i=0; i < 16; i++) printf(" %02x", ivec[i]);
// printf("\n");
// printf("count: ");
// for(int i=0; i < 16; i++) printf(" %02x", ecount[i]);
// printf(" num=%d\n", num);
// printf("Input: ");
// for(int i=0; i < 16; i++) printf(" %02x", indata[i]);
// printf("\n");
// printf("Outpt: ");
// for(int i=0; i < 16; i++) printf(" %02x", out_buffer.buffer.clear.address[i]);
// printf("\n");
// printf("Encry: ");
// for(int i=0; i < 16; i++) printf(" %02x", outdata[i]);
// printf("\n");
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session))
<< "OEMCrypto_CloseSesion failed.";
delete [] out_buffer.buffer.clear.address;
delete [] keyid;
delete [] key;
}
TEST_F(OEMCryptoTest, MockOEMCrypto_LoadKeys) {
OEMCrypto_SESSION session;
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session));
MockSession* ms = MockOEMCrypto::sSingleton->findSession(session);
uint32_t key_length = 0;
const uint8_t* mac_key = makeArray("d53c018d4a4d2cdb19685d1764845a87"
"7474dc020a2d19225d385ce2176bd61c",
&key_length);
EXPECT_EQ(32, (int)key_length);
const uint8_t* enc_key = makeArray("9713d57529b9f0a84fa06371af92b791",
&key_length);
EXPECT_EQ(16, (int)key_length);
memcpy(ms->mEncryptKey, enc_key, 16);
memcpy(ms->mMacKey, mac_key, 32);
uint32_t message_length = 0;
const uint8_t* message = makeArray("0a300a146d79436f6f6c526571756573"
"742c2044756465211208ec2316261123"
"b47c1a0a507572636861736573212001"
"28001204080118011a3612103cb829f7"
"c0241dc1434982d9e059ae0d1a20015f"
"6157446481b9a32823c2657c9c464fe2"
"e6115e96963f1d3c484ce95bff1e2001"
"1a2e0a066b657920696412104e793f3b"
"ef67bc83f7deacfbf1e9d3851a101308"
"fb0835bda16782f902f5c49644d52002"
"209580ff8505",
&message_length);
uint32_t signature_length = 0;
const uint8_t* signature = makeArray("7941857a3a42dd46992dc585e8e3ac01"
"5ff491bd190921e5f4212074795575fd",
&signature_length);
uint8_t* enc_mac_key_iv = makeArray("3cb829f7c0241dc1434982d9e059ae0d",
&key_length);
EXPECT_EQ(16, (int)key_length);
uint8_t* enc_mac_key = makeArray("015f6157446481b9a32823c2657c9c46"
"4fe2e6115e96963f1d3c484ce95bff1e",
&key_length);
EXPECT_EQ(32, (int)key_length);
uint8_t* content_key = makeArray("30313233343536373839616263646566",
&key_length);
uint32_t num_keys = 1;
OEMCrypto_KeyObject key_array[1];
OEMCrypto_KeyControl control;
memcpy( control.mVerification, "kctl", 4);
control.mDuration = htonl(60*60*24); // 1 day.
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GenerateNonce(session, &control.mNonce))
<< "OEMCrypto_GenerateNonce";
control.mControl = htonl(0);
EXPECT_EQ(16, (int)sizeof(control));
AES_KEY aes_key;
AES_set_encrypt_key( content_key, 128, &aes_key);
uint8_t iv[16];
uint8_t enc_key_control[16];
memset( iv, 0, 16);
AES_cbc_encrypt((uint8_t *) &control, enc_key_control, 16, &aes_key,
iv, AES_ENCRYPT);
memset( iv, 0, 16);
key_array[0].key_id = makeArray("00000000000000000000000000000000",
&(key_array[0].key_id_length));
key_array[0].key_data_iv = makeArray("4e793f3bef67bc83f7deacfbf1e9d385"); // given.
key_array[0].key_data = makeArray("1308fb0835bda16782f902f5c49644d5"); // given.
key_array[0].key_control_iv = iv;
key_array[0].key_control = enc_key_control;
// printf("\n--------------------------\n");
// printf(" iv: ");
// for(int i=0; i < 16; i++) printf(" %02x", key_array[0].key_control_iv[i]);
// printf("\n");
// printf(" con: ");
// uint8_t *buffer = (uint8_t *) &control;
// for(int i=0; i < 16; i++) printf(" %02x", buffer[i]);
// printf("\n");
// printf("e con: ");
// for(int i=0; i < 16; i++) printf(" %02x", key_array[0].key_control[i]);
// printf("\n");
// printf("u key: ");
// for(int i=0; i < 16; i++) printf(" %02x", content_key[i]);
// printf("\n");
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadKeys(session, message, message_length,
signature, signature_length,
enc_mac_key_iv, enc_mac_key, num_keys, key_array))
<< "OEMCrypto_LoadKeys";
uint8_t* new_mac_key = makeArray("faa85bcdd67395e65566c4b891f8a2f0"
"2ff983dbad9a4cb44518e8235a4dbb5f",
&key_length);
EXPECT_EQ(0, memcmp(ms->mMacKey, new_mac_key, 32))
<< "New Mac key was not decrypted.";
// printf("\n--------------------------\n");
// printf(" mac: ");
// for(int i=0; i < 32; i++) printf(" %02x", ms->mac_key[i]);
// printf("\n");
// printf("new mac: ");
// for(int i=0; i < 32; i++) printf(" %02x", new_mac_key[i]);
// printf("\n");
EXPECT_EQ(1, (int)ms->mKeys.size());
if (ms->mKeys.size() > 0) {
EXPECT_EQ(0, memcmp( ms->mKeys[0].mKeyData, content_key, 16))
<< "Key data was not loaded correctly";
}
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session))
<< "OEMCrypto_CloseSesion failed.";
}
TEST_F(OEMCryptoTest, MockOEMCrypto_RefreshKeys) {
OEMCrypto_SESSION session;
// session = 0xdeadbeef;
const uint8_t* message = NULL;
uint32_t message_length = 0;
const uint8_t* signature = NULL;
uint32_t signature_length = 0;
uint32_t num_keys = 0;
const OEMCrypto_KeyRefreshObject* key_array = NULL;
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session));
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_RefreshKeys(session, message, message_length,
signature, signature_length,
num_keys, key_array))
<< "OEMCrypto_RefreshKeys";
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session))
<< "OEMCrypto_CloseSesion failed.";
}
/***********************************************************************/
/***********************************************************************/
// TODO: This test is just a stub. We will fix it in a future CL.
/***********************************************************************/
/***********************************************************************/
TEST_F(OEMCryptoTest, MockOEMCrypto_FullVideoTest) {
uint8_t *keybox = (uint8_t*)"pointer to some valid keybox data";
uint32_t keyBoxLength = strlen((char*)keybox);
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_InstallKeybox(keybox, keyBoxLength));
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
uint8_t deviceID[32] = "0123456789012345";
uint32_t idLength = 16;
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetDeviceID(deviceID, &idLength));
for (uint32_t i = 0; i < idLength; i++)
printf("%c", deviceID[i]);
printf("\n");
uint8_t* keyData;
uint32_t keyDataLength = 72;
keyData = (uint8_t*)malloc(keyDataLength); //not really but we will malloc it for the stub work
memset(keyData, 0, keyDataLength);
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetKeyData(keyData, &keyDataLength));
for (uint32_t i = 0; i < keyDataLength; i++) {
if ((i % 15) == 0)
printf("\n");
printf("0x%02x ", keyData[i]);
}
printf("\n");
printf("request an EMM\n");
delete keyData;
OEMCrypto_SESSION session;
// session = 0xdeadbeef;
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session));
// EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_EnterSecurePlayback());
const uint8_t* emmKey = (const uint8_t*)"0123456789012345";
const uint32_t emmKeyLength = 16;
// EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_SetEntitlementKey(emmKey, emmKeyLength));
const uint8_t* ecm = (const uint8_t*)"01234567890123450123456789012345";
const uint32_t length = 32;
uint32_t flags;
// EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_DeriveControlWord(ecm, length, &flags));
const uint8_t* contentKey = (const uint8_t*)"0123456789012345";
const uint32_t contentKeyLength = 16;
const uint8_t* control = (const uint8_t*)"abcd";
const uint32_t controlLength = 4;
// EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_SetContentKey(session, contentKey, contentKeyLength, control, controlLength));
{
const uint8_t* iv = (const uint8_t*)"0123456789012345";
const uint8_t* input = (const uint8_t*)"some nicely encrypted video data";
const uint32_t inputLength = strlen((char*)input);
uint32_t output_handle = 0xdeadbeef;
uint32_t output_offset = 0;
uint32_t outputLength;
// EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_DecryptVideo(iv, input, inputLength, output_handle, output_offset, &outputLength));
}
{
const uint8_t* iv = (const uint8_t*)"0123456789012345";
const uint8_t* input = (const uint8_t*)"some nicely encrypted audio data";
const uint32_t inputLength = strlen((char*)input);
uint8_t *output;
uint32_t outputLength;
// EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_DecryptAudio(iv, input, inputLength, output, &outputLength));
}
// EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_ExitSecurePlayback());
EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session))
<< "OEMCrypto_CloseSesion failed.";
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
#include "WVCreateDrmPluginFactory.h"
#include "WVDrmPluginFactory.h"
namespace wvclearkey {
WVDrmPluginFactory* pluginFactory = NULL;
WVDrmPluginFactory* createPluginFactory() {
if (pluginFactory == NULL) {
pluginFactory = new WVDrmPluginFactory();
}
return pluginFactory;
}
} // namespace wvclearkey
extern "C" android::DrmPluginFactory* createDrmPluginFactory() {
return wvclearkey::createPluginFactory();
}
extern "C" android::CryptoFactory *createCryptoFactory() {
return wvclearkey::createPluginFactory();
}

View File

@@ -1,120 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "wv_clear_key"
#include <utils/Log.h>
#include "WVDrmPluginFactory.h"
#include "WVCryptoPlugin.h"
#include "OEMCryptoDASH.h"
#include "utils/Errors.h"
#include <dlfcn.h>
namespace wvclearkey {
WVDrmPluginFactory::WVDrmPluginFactory() :
mLegacyLibraryHandle(NULL) {
OEMCryptoResult res = OEMCrypto_Initialize();
if (res != OEMCrypto_SUCCESS) {
ALOGE("OEMCrypto_Initialize error result: %d", res);
}
mLegacyLibraryHandle = dlopen("libdrmdecrypt.so", RTLD_NOW);
if (mLegacyLibraryHandle == NULL) {
ALOGE("Unable to locate libdrmdecrypt.so");
} else {
using android::CryptoFactory;
typedef CryptoFactory *(*CreateCryptoFactoryFunc)();
CreateCryptoFactoryFunc legacyCreateCryptoFactory =
(CreateCryptoFactoryFunc)dlsym(mLegacyLibraryHandle, "createCryptoFactory");
if (legacyCreateCryptoFactory == NULL) {
ALOGE("Unable to find legacy symbol 'createCryptoFactory'.");
} else {
mLegacyFactory = legacyCreateCryptoFactory();
if (mLegacyFactory == NULL) {
ALOGE("Legacy createCryptoFactory() failed.");
}
}
}
}
WVDrmPluginFactory::~WVDrmPluginFactory() {
OEMCryptoResult res = OEMCrypto_Terminate();
if (res != OEMCrypto_SUCCESS) {
ALOGE("OEMCrypto_Terminate error result: %d", res);
}
if (mLegacyFactory != NULL) {
delete mLegacyFactory;
mLegacyFactory = NULL;
}
if (mLegacyLibraryHandle != NULL) {
dlclose(mLegacyLibraryHandle);
mLegacyLibraryHandle = NULL;
}
}
bool WVDrmPluginFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const {
const uint8_t kWidevineUUID[16] = {
0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
};
const uint8_t kOldNetflixWidevineUUID[16] = {
0x29,0x70,0x1F,0xE4,0x3C,0xC7,0x4A,0x34,
0x8C,0x5B,0xAE,0x90,0xC7,0x43,0x9A,0x47
};
return !memcmp(uuid, kWidevineUUID, 16) ||
!memcmp(uuid, kOldNetflixWidevineUUID, 16);
}
status_t WVDrmPluginFactory::createCryptoPlugin(
const uint8_t uuid[16], const void *data, size_t size,
android::CryptoPlugin **plugin) {
if (!isCryptoSchemeSupported(uuid)) {
*plugin = NULL;
return android::BAD_VALUE;
}
// 0 size means they want an old-style Widevine plugin
if (size == 0) {
if (mLegacyFactory == NULL) {
return -EINVAL;
}
return mLegacyFactory->createPlugin(uuid, data, size, plugin);
}
// We received a session ID, so create a CENC plugin.
// Note that we ignore the session in the clear-key solution, but we won't
// in the real plugin.
*plugin = new WVCryptoPlugin();
return android::OK;
}
status_t WVDrmPluginFactory::createDrmClientPlugin(
const uint8_t uuid[16], const void *data, size_t size,
android::DrmClientPlugin **plugin) {
if (!isCryptoSchemeSupported(uuid)) {
*plugin = NULL;
return android::BAD_VALUE;
}
*plugin = NULL;
// In this demo code, there is no need for a Drm Client Plugin
return -EPERM;
}
} // namespace wvclearkey

View File

@@ -1,33 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
WVCreateDrmPluginFactory_test.cpp \
WVDrmPluginFactory_test.cpp \
EmptyWVCryptoPlugin.cpp \
../src/WVCreateDrmPluginFactory.cpp \
../src/WVDrmPluginFactory.cpp \
LOCAL_C_INCLUDES := \
bionic \
external/gtest/include \
external/stlport/stlport \
vendor/widevine/libclearkeydrmengine/include \
vendor/widevine/libclearkeydrmengine/crypto/include \
vendor/widevine/libclearkeydrmengine/oemcrypto/include \
LOCAL_STATIC_LIBRARIES := \
libgtest \
libgtest_main \
LOCAL_SHARED_LIBRARIES := \
libstlport \
liblog \
libdl \
libutils \
LOCAL_MODULE := libclearkeydrmengine_test
LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)

View File

@@ -1,21 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
#include "WVCryptoPlugin.h"
namespace wvclearkey {
WVCryptoPlugin::WVCryptoPlugin() {}
WVCryptoPlugin::~WVCryptoPlugin() {}
ssize_t WVCryptoPlugin::decrypt(
bool secure,
const uint8_t key[16],
const uint8_t iv[16],
Mode mode,
const void *srcPtr,
const SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
android::AString *errorDetailMsg) {
return 0;
}
}

View File

@@ -1,14 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
#include "utils/UniquePtr.h"
#include "WVCreateDrmPluginFactory.h"
#include "gtest/gtest.h"
TEST(CreateDrmPluginFactoryTest, CreatesObject) {
UniquePtr<android::DrmPluginFactory> factory(createDrmPluginFactory());
EXPECT_NE((android::DrmPluginFactory*)NULL, factory.get() ) <<
"createDrmPluginFactory() returned null";
}

View File

@@ -1,124 +0,0 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
#include "utils/UniquePtr.h"
#include "WVDrmPluginFactory.h"
#include "media/drm/DrmClientAPI.h"
#include "OEMCryptoDASH.h"
#include "gtest/gtest.h"
using namespace wvclearkey;
const uint8_t kWidevineUUID[16] = {
0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
};
const uint8_t kOldNetflixWidevineUUID[16] = {
0x29,0x70,0x1F,0xE4,0x3C,0xC7,0x4A,0x34,
0x8C,0x5B,0xAE,0x90,0xC7,0x43,0x9A,0x47
};
const uint8_t kUnknownUUID[16] = {
0x6A,0x7F,0xAA,0xB0,0x83,0xC7,0x9E,0x20,
0x08,0xBC,0xEF,0x32,0x34,0x1A,0x9A,0x26
};
TEST(WVDrmPluginFactoryTest, SupportsSupportedCryptoSchemes) {
UniquePtr<WVDrmPluginFactory> factory(new WVDrmPluginFactory());
EXPECT_TRUE(factory->isCryptoSchemeSupported(kWidevineUUID)) <<
"WVDrmPluginFactory does not support Widevine's UUID";
EXPECT_TRUE(factory->isCryptoSchemeSupported(kOldNetflixWidevineUUID)) <<
"WVDrmPluginFactory does not support the old Netflix Widevine UUID";
}
TEST(WVDrmPluginFactoryTest, DoesNotSupportUnsupportedCryptoSchemes) {
UniquePtr<WVDrmPluginFactory> factory(new WVDrmPluginFactory());
EXPECT_FALSE(factory->isCryptoSchemeSupported(kUnknownUUID)) <<
"WVDrmPluginFactory incorrectly claims to support an unknown UUID";
}
TEST(WVDrmPluginFactoryTest, CreatesCryptoPlugins) {
UniquePtr<WVDrmPluginFactory> factory(new WVDrmPluginFactory());
android::CryptoPlugin *plugin;
status_t result = factory->createCryptoPlugin(kWidevineUUID, NULL, 0, &plugin);
EXPECT_EQ(android::OK, result) <<
"WVDrmPluginFactory returned error from createCryptoPlugin()";
EXPECT_NE((android::CryptoPlugin *)NULL, plugin) <<
"WVDrmPluginFactory's createCryptoPlugin() did not create a plugin";
delete plugin;
}
TEST(WVDrmPluginFactoryTest, DoesNotCreateDrmClientPlugins) {
UniquePtr<WVDrmPluginFactory> factory(new WVDrmPluginFactory());
android::DrmClientPlugin *plugin;
status_t result = factory->createDrmClientPlugin(kWidevineUUID, NULL, 0, &plugin);
EXPECT_EQ(-EPERM, result) <<
"WVDrmPluginFactory did not indicate that createDrmClientPlugin() is not implemented";
EXPECT_EQ((android::DrmClientPlugin *)NULL, plugin) <<
"WVDrmPluginFactory's createDrmClientPlugin() created a plugin (?!?)";
delete plugin;
}
TEST(WVDrmPluginFactoryTest, RefusesToCreateWithUnsupportedCryptoScheme) {
UniquePtr<WVDrmPluginFactory> factory(new WVDrmPluginFactory());
android::CryptoPlugin *cryptoPlugin;
android::DrmClientPlugin *drmClientPlugin;
status_t result;
result = factory->createCryptoPlugin(kUnknownUUID, NULL, 0, &cryptoPlugin);
EXPECT_EQ(android::BAD_VALUE, result) <<
"WVDrmPluginFactory did not reject unknown UUID when creating a CryptoPlugin";
EXPECT_EQ((android::CryptoPlugin *)NULL, cryptoPlugin) <<
"WVDrmPluginFactory created a CryptoPlugin despite having an unknown UUID";
result = factory->createDrmClientPlugin(kUnknownUUID, NULL, 0, &drmClientPlugin);
EXPECT_EQ(android::BAD_VALUE, result) <<
"WVDrmPluginFactory did not reject unknown UUID when creating a DrmClientPlugin";
EXPECT_EQ((android::DrmClientPlugin *)NULL, drmClientPlugin) <<
"WVDrmPluginFactory created a DrmClientPlugin despite having an unknown UUID";
delete cryptoPlugin;
delete drmClientPlugin;
}
bool oemCryptoInitialized;
bool oemCryptoTerminated;
extern "C" {
OEMCryptoResult OEMCrypto_Initialize(void) {
oemCryptoInitialized = true;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult OEMCrypto_Terminate(void) {
oemCryptoTerminated = true;
return OEMCrypto_SUCCESS;
}
}
TEST(WVDrmPluginFactoryTest, CallsOemCrypto) {
oemCryptoInitialized = false;
oemCryptoTerminated = false;
WVDrmPluginFactory *factory = new WVDrmPluginFactory();
EXPECT_EQ(true, oemCryptoInitialized) <<
"WVDrmPluginFactory did not call OEMCrypto_Initialize()";
delete factory;
EXPECT_EQ(true, oemCryptoTerminated) <<
"WVDrmPluginFactory did not call OEMCrypto_Terminate()";
}