Move OEMCrypto Mock files to Clear Key Library
In order to match the other implementations of CDM, we are going to replace the android OEMCrypto mockup with the one in the cdm repository. This would be disruptive to the clear key library because it relies on the current implementation of the mockup. In order to prevent that, I am moving the current mockup into the same directory as the clear key library. Then, we can put the new mockup under the directory libwvdrmengine. This mockup will then be deleted when the clear key library is deleted. Change-Id: I89ee23f249dacd18241ae5ca499329e620bf5a2c
This commit is contained in:
@@ -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/libwvdrmengine/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_
|
||||
Reference in New Issue
Block a user