Initial Clear Key DRM Engine

Adds the initial pieces of a sample DRM Engine that accepts keys in the clear
through the decrypt call instead of using the DrmClientPlugin and its key
ladder.  This is to help unblock teams writing code that consumes DRM Engines
while Widevine continues working their real DRM engine.  This is based on the
in-progress Widevine DRM Engine.

This change contains the DRM Engine glue pieces (.so entry point,
DrmPluginFactory, etc.) and a CryptoPlugin implementation.  However, said
CryptoPlugin will not work until an implementation of OEMCrypto is provided
in a future checkin and the CryptoPlugin is hooked up to it.

For ease of loading, this library also implements the old CryptoFactory
interface and entry point.

If asked to create a CryptoPlugin with no data, it will defer to the old
Widevine Crypto Plugin.

Change-Id: I0bfbec7e32439a50a2956488dd970284f0075e61
This commit is contained in:
John "Juce" Bruce
2012-12-10 13:54:43 -08:00
committed by Jeff Tinker
parent d5aa1e41d3
commit 04bfbb0198
18 changed files with 1546 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
LOCAL_PATH := $(call my-dir)
# We depend on the static libraries from our subdirectories to build this
# shared library
include $(call all-subdir-makefiles)
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 \
LOCAL_SHARED_LIBRARIES := \
liblog \
libutils \
libdl \
LOCAL_MODULE := libclearkeydrmengine
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
Fred will fill this out

View File

@@ -0,0 +1,711 @@
/*********************************************************************
* 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_
#ifdef __cplusplus
extern "C" {
#endif
#define OEMCRYPTO_VERSION "4.0"
static const char oec_version[] = OEMCRYPTO_VERSION;
#include<stdint.h>
typedef uint32_t OEMCrypto_SESSION;
typedef enum OEMCryptoResult {
OEMCrypto_SUCCESS = 0,
OEMCrypto_ERROR_INIT_FAILED,
OEMCrypto_ERROR_TERMINATE_FAILED,
OEMCrypto_ERROR_OPEN_FAILURE,
OEMCrypto_ERROR_CLOSE_FAILURE,
OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED,
OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED,
OEMCrypto_ERROR_SHORT_BUFFER,
OEMCrypto_ERROR_NO_DEVICE_KEY,
OEMCrypto_ERROR_NO_ASSET_KEY,
OEMCrypto_ERROR_KEYBOX_INVALID,
OEMCrypto_ERROR_NO_KEYDATA,
OEMCrypto_ERROR_NO_CW,
OEMCrypto_ERROR_DECRYPT_FAILED,
OEMCrypto_ERROR_WRITE_KEYBOX,
OEMCrypto_ERROR_WRAP_KEYBOX,
OEMCrypto_ERROR_BAD_MAGIC,
OEMCrypto_ERROR_BAD_CRC,
OEMCrypto_ERROR_NO_DEVICEID,
OEMCrypto_ERROR_RNG_FAILED,
OEMCrypto_ERROR_RNG_NOT_SUPPORTED,
OEMCrypto_ERROR_SETUP,
OEMCrypto_ERROR_OPEN_SESSION_FAILED,
OEMCrypto_ERROR_CLOSE_SESSION_FAILED,
OEMCrypto_ERROR_INVALID_SESSION,
OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_ERROR_NO_CONTENT_KEY,
OEMCrypto_ERROR_CONTROL_INVALID,
OEMCrypto_ERROR_UNKNOWN_FAILURE,
OEMCrypto_ERROR_INVALID_CONTEXT,
OEMCrypto_ERROR_SIGNATURE_FAILURE
} 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;
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;
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
*
* 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
*
* 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.
*
* Returns:
* OEMCrypto_SUCCESS success
* 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.
*
* Returns:
* OEMCrypto_SUCCESS success
* 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
*
* Parameters:
* session (in) - crypto session identifier.
* context (in) - pointer to memory containing context data for computing the
* secondary keys.
* context_length (in) - length of the context data.
*
* 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 *context,
size_t context_length);
/*
* OEMCrypto_GenerateNonce
*
* Description:
* Generates a 32-bit nonce to detect possible replay attack on the key
* control block.
*
* Refer to documents "OEMCrypto Changes for V2 License Protocol" and "Key
* Control Block Definition" 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
*
* 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
*
* 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 mac_key is encrypted with the current encrypt_key and the offered IV.
* It replaces the mac_key created by OEMCrypto_GenerateDerivedkeys().
*
* 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 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
* 128 bits.
* num_keys (in) - number of keys present.
* key_array (in) - set of keys to be installed.
*
* 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_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() 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.
*
* 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()).
*
* This operation is supported only while performing CTR mode decryption
* (see OEMCrypto_DecryptCTR). 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: Lookup the encrypt_key (derived key). Latch the result in the
* hardware key ladder.
*
* Step 3: use the encrypt_key to decrypt (AES-128-CBC) the content key data,
* using the content key IV. Latch result in the hardware key ladder.
*
* Step 4: use the latched content key to decrypt (AES-128-CBC) the key
* control block using the key control block IV. Verify the key
* control block and apply it to the current session.
*
* Step 5: 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
*
* 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,
const 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.
*
* 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.
*
* 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
*
* 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.
*
* 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.
*
* 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.
*
* 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
* 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
*/
OEMCryptoResult OEMCrypto_WrapKeybox(uint8_t *keybox,
size_t keyBoxLength,
uint8_t *wrappedKeybox,
size_t *wrappedKeyBoxLength,
uint8_t *transportKey,
size_t transportKeyLength);
#ifdef __cplusplus
}
#endif
#endif // OEMCRYPTO_DASH_H_

View File

@@ -0,0 +1 @@
Fred will fill this out

View File

@@ -0,0 +1 @@
Fred will fill this out

View File

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

View File

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

View File

@@ -0,0 +1,34 @@
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 := \
external/gtest/include \
external/stlport/stlport \
bionic \
frameworks/native/include \
frameworks/av/include \
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 \
libutils \
LOCAL_MODULE := libclearkeydrmengine_test
LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)

View File

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

View File

@@ -0,0 +1,14 @@
/*
* 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) <<
"createDrmPluginFactory() returned null";
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*/
#include "utils/UniquePtr.h"
#include "WVDrmPluginFactory.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();
UniquePtr<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";
}
TEST(WVDrmPluginFactoryTest, DoesNotCreateDrmClientPlugins) {
UniquePtr<WVDrmPluginFactory> factory = new WVDrmPluginFactory();
UniquePtr<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 (?!?)";
}
TEST(WVDrmPluginFactoryTest, RefusesToCreateWithUnsupportedCryptoScheme) {
UniquePtr<WVDrmPluginFactory> factory = new WVDrmPluginFactory();
UniquePtr<android::CryptoPlugin> cryptoPlugin;
UniquePtr<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";
}
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()";
}