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:
@@ -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
|
||||
@@ -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)
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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.";
|
||||
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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.";
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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()";
|
||||
}
|
||||
Reference in New Issue
Block a user