Fix broken full_x86 and full_mips builds
Also cleans up some redundant files. Change-Id: Id9a18bcb917ae999865f7c5564a72dba27b0ce97
This commit is contained in:
@@ -1,524 +0,0 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "l3crypto_engine_mock.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "l3crypto_key_mock.h"
|
||||
#include "openssl/aes.h"
|
||||
#include "openssl/cmac.h"
|
||||
#include "openssl/hmac.h"
|
||||
#include "openssl/rand.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
// Increment counter for AES-CTR
|
||||
void ctr128_inc(uint8_t* counter) {
|
||||
uint32_t n = 16;
|
||||
do {
|
||||
if (++counter[--n] != 0) return;
|
||||
} while (n);
|
||||
}
|
||||
}
|
||||
|
||||
namespace wvoec_obfs {
|
||||
|
||||
SessionKeyTable::~SessionKeyTable() {
|
||||
for (KeyMap::iterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
if (NULL != i->second) {
|
||||
delete i->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SessionKeyTable::Insert(const KeyId key_id, const Key& key_data) {
|
||||
if (keys_.find(key_id) != keys_.end()) return false;
|
||||
keys_[key_id] = new Key(key_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
Key* SessionKeyTable::Find(const KeyId key_id) {
|
||||
if (keys_.find(key_id) == keys_.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return keys_[key_id];
|
||||
}
|
||||
|
||||
void SessionKeyTable::Remove(const KeyId key_id) {
|
||||
if (keys_.find(key_id) != keys_.end()) {
|
||||
delete keys_[key_id];
|
||||
keys_.erase(key_id);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionContext::Open() {
|
||||
}
|
||||
|
||||
void SessionContext::Close() {
|
||||
}
|
||||
|
||||
// Internal utility function to derive key using CMAC-128
|
||||
bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& context,
|
||||
int counter,
|
||||
std::vector<uint8_t>* out) {
|
||||
if (key.empty() || counter > 2 || context.empty() || out == NULL) {
|
||||
LOGE("[DeriveKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return false;
|
||||
}
|
||||
|
||||
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
|
||||
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
|
||||
|
||||
if (!CMAC_Init(cmac_ctx, &key[0], key.size(), cipher, 0)) {
|
||||
LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> message;
|
||||
message.push_back(counter);
|
||||
message.insert(message.end(), context.begin(), context.end());
|
||||
|
||||
if (!CMAC_Update(cmac_ctx, &message[0], message.size())) {
|
||||
LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t reslen;
|
||||
uint8_t res[128];
|
||||
if (!CMAC_Final(cmac_ctx, res, &reslen)) {
|
||||
LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]");
|
||||
return false;
|
||||
}
|
||||
|
||||
out->assign(res, res+reslen);
|
||||
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::DeriveKeys(const std::vector<uint8_t>& mac_key_context,
|
||||
const std::vector<uint8_t>& enc_key_context) {
|
||||
// Generate derived key for mac key
|
||||
std::vector<uint8_t> device_key = ce_->keybox().device_key().value();
|
||||
std::vector<uint8_t> mac_key;
|
||||
std::vector<uint8_t> result;
|
||||
if (!DeriveKey(device_key, mac_key_context, 1, &mac_key)) {
|
||||
return false;
|
||||
}
|
||||
if (!DeriveKey(device_key, mac_key_context, 2, &result)) {
|
||||
return false;
|
||||
}
|
||||
mac_key.insert( mac_key.end(), result.begin(), result.end());
|
||||
|
||||
// Generate derived key for encryption key
|
||||
std::vector<uint8_t> enc_key;
|
||||
if (!DeriveKey(device_key, enc_key_context, 1, &enc_key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_mac_key(mac_key);
|
||||
set_encryption_key(enc_key);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Utility function to generate a message signature
|
||||
bool SessionContext::GenerateSignature(const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length) {
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
LOGE("[OEMCrypto_GenerateSignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mac_key_.empty() || mac_key_.size() != wvcdm::MAC_KEY_SIZE) {
|
||||
LOGE("[GenerateSignature(): No MAC Key]");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*signature_length < SHA256_DIGEST_LENGTH) {
|
||||
*signature_length = SHA256_DIGEST_LENGTH;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int md_len = *signature_length;
|
||||
if (HMAC(EVP_sha256(), &mac_key_[0], SHA256_DIGEST_LENGTH,
|
||||
message, message_length, signature, &md_len)) {
|
||||
*signature_length = md_len;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate message signature
|
||||
bool SessionContext::ValidateMessage(const uint8_t* given_message,
|
||||
size_t message_length,
|
||||
const uint8_t* given_signature,
|
||||
size_t signature_length) {
|
||||
|
||||
if (signature_length != SHA256_DIGEST_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
uint8_t computed_signature[signature_length];
|
||||
if (! GenerateSignature(given_message, message_length,
|
||||
computed_signature, &signature_length)) {
|
||||
return false;
|
||||
}
|
||||
if (memcmp(given_signature, computed_signature, signature_length)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::ParseKeyControl(
|
||||
const std::vector<uint8_t>& key_control_string,
|
||||
KeyControlBlock& key_control_block) {
|
||||
|
||||
key_control_block.Invalidate();
|
||||
|
||||
if (key_control_string.size() < wvcdm::KEY_CONTROL_SIZE) {
|
||||
return false;
|
||||
}
|
||||
if (!key_control_block.SetFromString(key_control_string)) {
|
||||
LOGE("KCB: BAD Size or Structure");
|
||||
return false;
|
||||
}
|
||||
if (!key_control_block.Validate()) {
|
||||
LOGE("KCB: BAD Signature");
|
||||
return false;
|
||||
}
|
||||
// TODO(fredgc): This checks each key against a nonce and then throws it out.
|
||||
// Instead, it should use the same nonce for the whole message.
|
||||
// if (!CheckNonce(key_control_block.nonce())) {
|
||||
// LOGE("KCB: BAD Nonce");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
LOGD("KCB:");
|
||||
LOGD(" valid: %d", key_control_block.valid());
|
||||
LOGD(" duration: %d", key_control_block.duration());
|
||||
LOGD(" nonce: %08X", key_control_block.nonce());
|
||||
LOGD(" bits: %08X", key_control_block.control_bits());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::InstallKey(const KeyId& key_id,
|
||||
const std::vector<uint8_t>& key_data,
|
||||
const std::vector<uint8_t>& key_data_iv,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv) {
|
||||
|
||||
// Decrypt encrypted key_data using derived encryption key and offered iv
|
||||
std::vector<uint8_t> content_key;
|
||||
std::vector<uint8_t> key_control_str;
|
||||
KeyControlBlock key_control_block;
|
||||
|
||||
if (!ce_->DecryptMessage(this, encryption_key_, key_data_iv,
|
||||
key_data, &content_key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Key control must be supplied by license server
|
||||
if (key_control.empty()) {
|
||||
LOGE("[Installkey(): WARNING: No Key Control]");
|
||||
key_control_block.Invalidate();
|
||||
return false;
|
||||
} else {
|
||||
if (key_control_iv.empty()) {
|
||||
LOGE("[Installkey(): ERROR: No Key Control IV]");
|
||||
return false;
|
||||
}
|
||||
if (!ce_->DecryptMessage(this, content_key, key_control_iv,
|
||||
key_control, &key_control_str)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ParseKeyControl(key_control_str, key_control_block)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Key key(KEYTYPE_CONTENT, content_key, key_control_block);
|
||||
session_keys_.Insert(key_id, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::RefreshKey(const KeyId& key_id,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv) {
|
||||
if (key_id.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Key* content_key = session_keys_.Find(key_id);
|
||||
|
||||
if (NULL == content_key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!key_control.empty()) {
|
||||
const std::vector<uint8_t> content_key_value = content_key->value();
|
||||
|
||||
// Decrypt encrypted key control block
|
||||
// We don't actually make use of it in Oemcrypto mock, just to verify its
|
||||
// validity
|
||||
std::vector<uint8_t> control;
|
||||
if (key_control_iv.empty()) {
|
||||
control = key_control;
|
||||
} else if (!ce_->DecryptMessage(this, content_key_value, key_control_iv,
|
||||
key_control, &control)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyControlBlock key_control_block;
|
||||
if (!ParseKeyControl(control, key_control_block)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!content_key->UpdateControl(key_control_block)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::UpdateMacKey(const std::vector<uint8_t>& enc_mac_key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
|
||||
// Decrypt mac key from enc_mac_key using device_key
|
||||
std::vector<uint8_t> mac_key;
|
||||
if (!ce_->DecryptMessage(this, encryption_key_, iv,
|
||||
enc_mac_key, &mac_key)) {
|
||||
return false;
|
||||
}
|
||||
mac_key_ = mac_key;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::SelectContentKey(const KeyId& key_id) {
|
||||
const Key* content_key = session_keys_.Find(key_id);
|
||||
if (NULL == content_key) {
|
||||
LOGE("[SelectContentKey(): No key matches key id]");
|
||||
return false;
|
||||
}
|
||||
current_content_key_ = content_key;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SessionContext::AddNonce(uint32_t nonce) {
|
||||
nonce_table_.AddNonce(nonce);
|
||||
}
|
||||
|
||||
bool SessionContext::CheckNonce(uint32_t nonce) {
|
||||
return nonce_table_.CheckNonce(nonce);
|
||||
}
|
||||
|
||||
|
||||
CryptoEngine::CryptoEngine() :
|
||||
ce_state_(CE_INITIALIZED), current_session_(NULL) {
|
||||
valid_ = true;
|
||||
}
|
||||
|
||||
CryptoEngine::~CryptoEngine() {
|
||||
current_session_ = NULL;
|
||||
sessions_.clear();
|
||||
}
|
||||
|
||||
void CryptoEngine::Terminate() {
|
||||
}
|
||||
|
||||
KeyboxError CryptoEngine::ValidateKeybox() { return keybox_.Validate(); }
|
||||
|
||||
SessionId CryptoEngine::CreateSession() {
|
||||
wvcdm::AutoLock lock(session_table_lock_);
|
||||
static int unique_id = 1;
|
||||
SessionId sid = (SessionId)++unique_id;
|
||||
SessionContext* sctx = new SessionContext(this, sid);
|
||||
sessions_[sid] = sctx;
|
||||
return sid;
|
||||
}
|
||||
|
||||
bool CryptoEngine::DestroySession(SessionId sid) {
|
||||
SessionContext* sctx = FindSession(sid);
|
||||
wvcdm::AutoLock lock(session_table_lock_);
|
||||
if (sctx) {
|
||||
sessions_.erase(sid);
|
||||
delete sctx;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SessionContext* CryptoEngine::FindSession(SessionId sid) {
|
||||
wvcdm::AutoLock lock(session_table_lock_);
|
||||
ActiveSessions::iterator it = sessions_.find(sid);
|
||||
if (it != sessions_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Internal utility function to decrypt the message
|
||||
bool CryptoEngine::DecryptMessage(SessionContext* session,
|
||||
const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv,
|
||||
const std::vector<uint8_t>& message,
|
||||
std::vector<uint8_t>* decrypted) {
|
||||
if (key.empty() || iv.empty() || message.empty() || !decrypted) {
|
||||
LOGE("[DecryptMessage(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return false;
|
||||
}
|
||||
|
||||
decrypted->resize(message.size());
|
||||
uint8_t iv_buffer[16];
|
||||
memcpy(iv_buffer, &iv[0], 16);
|
||||
AES_KEY aes_key;
|
||||
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(&message[0], &(decrypted->front()), message.size(),
|
||||
&aes_key, iv_buffer, AES_DECRYPT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoEngine::DecryptCTR(SessionContext* session,
|
||||
const std::vector<uint8_t>& iv,
|
||||
size_t byte_offset,
|
||||
const std::vector<uint8_t>& cipher_data,
|
||||
bool is_encrypted,
|
||||
void* clear_data,
|
||||
BufferType buffer_type) {
|
||||
|
||||
// Check there is a content key
|
||||
if (session->current_content_key() == NULL) {
|
||||
LOGE("[DecryptCTR(): OEMCrypto_ERROR_NO_CONTENT_KEY]");
|
||||
return false;
|
||||
}
|
||||
const KeyControlBlock& control = session->current_content_key()->control();
|
||||
if (control.control_bits() & kControlDataPathSecure) {
|
||||
if (buffer_type == BUFFER_TYPE_CLEAR) {
|
||||
LOGE("[DecryptCTR(): Secure key with insecure buffer]");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// TODO(fredgc): Check duration of key.
|
||||
|
||||
const std::vector<uint8_t>& content_key = session->current_content_key()->value();
|
||||
|
||||
// Set the AES key.
|
||||
if (static_cast<int>(content_key.size()) != AES_BLOCK_SIZE) {
|
||||
LOGE("[DecryptCTR(): CONTENT_KEY has wrong size.");
|
||||
return false;
|
||||
}
|
||||
const uint8_t* key_u8 = &content_key[0];
|
||||
AES_KEY aes_key;
|
||||
if (AES_set_encrypt_key(key_u8, AES_BLOCK_SIZE * 8, &aes_key) != 0) {
|
||||
LOGE("[DecryptCTR(): FAILURE]");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer_type == BUFFER_TYPE_DIRECT) {
|
||||
// For reference implementation, we quietly drop direct video.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (buffer_type == BUFFER_TYPE_SECURE) {
|
||||
// For reference implementation, we also quietly drop secure data.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! is_encrypted) {
|
||||
memcpy(reinterpret_cast<uint8_t*>(clear_data),
|
||||
&cipher_data[0], cipher_data.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Local copy (will be modified).
|
||||
uint8_t aes_iv[AES_BLOCK_SIZE];
|
||||
if (static_cast<int>(iv.size()) != AES_BLOCK_SIZE) {
|
||||
LOGE("[DecryptCTR(): FAILURE: iv has wrong length]");
|
||||
return false;
|
||||
}
|
||||
memcpy(aes_iv, &iv[0], AES_BLOCK_SIZE);
|
||||
|
||||
// Encrypt the IV.
|
||||
uint8_t ecount_buf[AES_BLOCK_SIZE];
|
||||
if (byte_offset != 0) {
|
||||
// The context is needed only when not starting a new block.
|
||||
AES_encrypt(aes_iv, ecount_buf, &aes_key);
|
||||
ctr128_inc(aes_iv);
|
||||
}
|
||||
|
||||
// Decryption.
|
||||
unsigned int byte_offset_cur = byte_offset;
|
||||
AES_ctr128_encrypt(
|
||||
&cipher_data[0], reinterpret_cast<uint8_t*>(clear_data), cipher_data.size(),
|
||||
&aes_key, aes_iv, ecount_buf, &byte_offset_cur);
|
||||
if (byte_offset_cur != ((byte_offset + cipher_data.size()) % AES_BLOCK_SIZE)) {
|
||||
LOGE("[DecryptCTR(): FAILURE: byte offset wrong.]");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NonceTable::AddNonce(uint32_t nonce) {
|
||||
int new_slot = -1;
|
||||
int oldest_slot = -1;
|
||||
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
if (valid_[i]) {
|
||||
++age_[i];
|
||||
if (-1 == oldest_slot) {
|
||||
oldest_slot = i;
|
||||
} else {
|
||||
if (age_[i] > age_[oldest_slot]) {
|
||||
oldest_slot = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (-1 == new_slot) {
|
||||
age_[i] = 0;
|
||||
nonces_[i] = nonce;
|
||||
valid_[i] = true;
|
||||
new_slot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-1 == new_slot) {
|
||||
// reuse oldest
|
||||
// assert (oldest_slot != -1)
|
||||
int i = oldest_slot;
|
||||
age_[i] = 0;
|
||||
nonces_[i] = nonce;
|
||||
valid_[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool NonceTable::CheckNonce(uint32_t nonce) {
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
if (valid_[i]) {
|
||||
if (nonce == nonces_[i]) {
|
||||
valid_[i] = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}; // namespace wvoec_obfs
|
||||
@@ -1,208 +0,0 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef L3CRYPTO_ENGINE_MOCK_H_
|
||||
#define L3CRYPTO_ENGINE_MOCK_H_
|
||||
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include "lock.h"
|
||||
#include "l3crypto_key_mock.h"
|
||||
#include "l3crypto_keybox_mock.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvoec_obfs {
|
||||
|
||||
enum SessionState {
|
||||
SESSION_STATE_ILLEGAL,
|
||||
SESSION_STATE_INITIALIZED,
|
||||
SESSION_STATE_HAS_DERIVED_KEYS,
|
||||
SESSION_STATE_ACTIVE,
|
||||
SESSION_STATE_ERROR
|
||||
};
|
||||
|
||||
enum BufferType {
|
||||
BUFFER_TYPE_CLEAR,
|
||||
BUFFER_TYPE_SECURE,
|
||||
BUFFER_TYPE_DIRECT
|
||||
};
|
||||
|
||||
class SessionContext;
|
||||
class CryptoEngine;
|
||||
|
||||
typedef uint32_t SessionId;
|
||||
typedef std::map<SessionId, SessionContext*> ActiveSessions;
|
||||
|
||||
typedef std::vector<uint8_t> KeyId;
|
||||
typedef std::map<KeyId, Key*> KeyMap;
|
||||
|
||||
// SessionKeyTable holds the keys for the current session
|
||||
class SessionKeyTable {
|
||||
public:
|
||||
SessionKeyTable() {}
|
||||
~SessionKeyTable();
|
||||
|
||||
bool Insert(const KeyId key_id, const Key& key_data);
|
||||
Key* Find(const KeyId key_id);
|
||||
void Remove(const KeyId key_id);
|
||||
|
||||
private:
|
||||
KeyMap keys_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(SessionKeyTable);
|
||||
};
|
||||
|
||||
class NonceTable {
|
||||
public:
|
||||
static const int kTableSize = 16;
|
||||
NonceTable() {
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
valid_[i] = false;
|
||||
}
|
||||
}
|
||||
~NonceTable() {};
|
||||
void AddNonce(uint32_t nonce);
|
||||
bool CheckNonce(uint32_t nonce);
|
||||
private:
|
||||
bool valid_[kTableSize];
|
||||
uint32_t age_[kTableSize];
|
||||
uint32_t nonces_[kTableSize];
|
||||
};
|
||||
|
||||
class SessionContext {
|
||||
private:
|
||||
SessionContext() {}
|
||||
|
||||
public:
|
||||
explicit SessionContext(CryptoEngine* ce, SessionId sid)
|
||||
: valid_(true), ce_(ce), id_(sid), current_content_key_(NULL) {}
|
||||
~SessionContext() {}
|
||||
|
||||
void Open();
|
||||
void Close();
|
||||
|
||||
bool isValid() { return valid_; }
|
||||
|
||||
bool DeriveKeys(const std::vector<uint8_t>& mac_context,
|
||||
const std::vector<uint8_t>& enc_context);
|
||||
bool GenerateSignature(const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
|
||||
bool ValidateMessage(const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
bool InstallKey(const KeyId& key_id,
|
||||
const std::vector<uint8_t>& key_data,
|
||||
const std::vector<uint8_t>& key_data_iv,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv);
|
||||
bool ParseKeyControl(const std::vector<uint8_t>& key_control_string,
|
||||
KeyControlBlock& key_control_block);
|
||||
bool RefreshKey(const KeyId& key_id,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv);
|
||||
bool UpdateMacKey(const std::vector<uint8_t>& mac_key, const std::vector<uint8_t>& iv);
|
||||
bool SelectContentKey(const KeyId& key_id);
|
||||
const Key* current_content_key(void) {return current_content_key_;}
|
||||
void set_mac_key(const std::vector<uint8_t>& mac_key) { mac_key_ = mac_key; }
|
||||
const std::vector<uint8_t>& mac_key() { return mac_key_; }
|
||||
|
||||
void set_encryption_key(const std::vector<uint8_t>& enc_key) {
|
||||
encryption_key_ = enc_key;
|
||||
}
|
||||
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
|
||||
|
||||
void AddNonce(uint32_t nonce);
|
||||
bool CheckNonce(uint32_t nonce);
|
||||
|
||||
private:
|
||||
|
||||
bool DeriveKey(const std::vector<uint8_t>& key, const std::vector<uint8_t>& context,
|
||||
int counter, std::vector<uint8_t>* out);
|
||||
|
||||
bool valid_;
|
||||
CryptoEngine* ce_;
|
||||
SessionId id_;
|
||||
SessionState state_;
|
||||
std::vector<uint8_t> mac_key_;
|
||||
std::vector<uint8_t> encryption_key_;
|
||||
const Key* current_content_key_;
|
||||
SessionKeyTable session_keys_;
|
||||
NonceTable nonce_table_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
|
||||
};
|
||||
|
||||
class CryptoEngine {
|
||||
|
||||
private:
|
||||
|
||||
enum CryptoEngineState {
|
||||
CE_ILLEGAL,
|
||||
CE_INITIALIZED,
|
||||
CE_HAS_KEYBOX,
|
||||
CE_HAS_SESSIONS,
|
||||
CE_ERROR
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
CryptoEngine();
|
||||
~CryptoEngine();
|
||||
|
||||
bool Initialized() { return (ce_state_ != CE_ILLEGAL); }
|
||||
|
||||
void Terminate();
|
||||
|
||||
bool isValid() { return valid_; }
|
||||
|
||||
KeyboxError ValidateKeybox();
|
||||
WvKeybox& keybox() { return keybox_; }
|
||||
|
||||
SessionId CreateSession();
|
||||
|
||||
bool DestroySession(SessionId sid);
|
||||
|
||||
SessionContext* FindSession(SessionId sid);
|
||||
|
||||
void set_current_session_(SessionContext* current) {
|
||||
current_session_ = current;
|
||||
}
|
||||
|
||||
bool DecryptMessage(SessionContext* session,
|
||||
const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv,
|
||||
const std::vector<uint8_t>& message,
|
||||
std::vector<uint8_t>* decrypted);
|
||||
|
||||
bool DecryptCTR(SessionContext* session,
|
||||
const std::vector<uint8_t>& iv,
|
||||
size_t byte_offset,
|
||||
const std::vector<uint8_t>& cipher_data,
|
||||
bool is_encrypted,
|
||||
void* clear_data,
|
||||
BufferType buffer_type);
|
||||
|
||||
private:
|
||||
|
||||
bool valid_;
|
||||
CryptoEngineState ce_state_;
|
||||
SessionContext* current_session_;
|
||||
ActiveSessions sessions_;
|
||||
WvKeybox keybox_;
|
||||
wvcdm::Lock session_table_lock_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
|
||||
};
|
||||
|
||||
}; // namespace wvoec_eng
|
||||
#endif
|
||||
@@ -1,97 +0,0 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <cstring>
|
||||
#include "l3crypto_key_mock.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvoec_obfs {
|
||||
|
||||
bool KeyControlBlock::Validate() {
|
||||
|
||||
valid_ = false;
|
||||
if (0x6b63746c != verification_) {
|
||||
return false;
|
||||
}
|
||||
// TODO(gmorgan): validate control bits
|
||||
valid_ = true;
|
||||
return valid_;
|
||||
}
|
||||
|
||||
uint32_t KeyControlBlock::ExtractField(const std::vector<uint8_t>& str, int idx) {
|
||||
int bidx = idx * 4;
|
||||
uint32_t t = static_cast<unsigned char>(str[bidx]) << 24;
|
||||
t |= static_cast<unsigned char>(str[bidx+1]) << 16;
|
||||
t |= static_cast<unsigned char>(str[bidx+2]) << 8;
|
||||
t |= static_cast<unsigned char>(str[bidx+3]);
|
||||
return t;
|
||||
}
|
||||
|
||||
bool KeyControlBlock::SetFromString(const std::vector<uint8_t>& key_control_string) {
|
||||
if (key_control_string.size() < wvcdm::KEY_CONTROL_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
verification_ = ExtractField(key_control_string, 0);
|
||||
duration_ = ExtractField(key_control_string, 1);
|
||||
nonce_ = ExtractField(key_control_string, 2);
|
||||
control_bits_ = ExtractField(key_control_string, 0);
|
||||
|
||||
return Validate();
|
||||
}
|
||||
|
||||
Key::Key(KeyType ktype, const std::vector<uint8_t>& key_string,
|
||||
const KeyControlBlock& control) :
|
||||
valid_(true), type_(ktype),
|
||||
value_(key_string), has_control_(true),
|
||||
control_(control) {
|
||||
}
|
||||
|
||||
bool Key::setValue(const char* key_string, size_t key_string_length) {
|
||||
valid_ = false;
|
||||
if (!key_string || key_string_length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
value_.assign(key_string, key_string + key_string_length);
|
||||
|
||||
if (isValidType() && has_control_) {
|
||||
valid_ = true;
|
||||
}
|
||||
return valid_;
|
||||
}
|
||||
|
||||
bool Key::setType(KeyType ktype) {
|
||||
valid_ = false;
|
||||
type_ = ktype;
|
||||
if (value_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isValidType() && has_control_) {
|
||||
valid_ = true;
|
||||
}
|
||||
return valid_;
|
||||
}
|
||||
|
||||
bool Key::setControl(const KeyControlBlock& control) {
|
||||
valid_ = false;
|
||||
if (!control.valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
control_ = control;
|
||||
has_control_ = true;
|
||||
|
||||
if (isValidType() && !value_.empty()) {
|
||||
valid_ = true;
|
||||
}
|
||||
return valid_;
|
||||
}
|
||||
|
||||
}; // namespace wvoec_eng
|
||||
@@ -1,117 +0,0 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef L3CRYPTO_KEY_MOCK_H_
|
||||
#define L3CRYPTO_KEY_MOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace wvoec_obfs {
|
||||
|
||||
enum KeyType {
|
||||
KEYTYPE_UNKNOWN,
|
||||
KEYTYPE_PREPROV,
|
||||
KEYTYPE_ROOT,
|
||||
KEYTYPE_DEVICE,
|
||||
KEYTYPE_CONTENT,
|
||||
KEYTYPE_CONTENT_AUDIO,
|
||||
KEYTYPE_CONTENT_VIDEO,
|
||||
KEYTYPE_MAX
|
||||
};
|
||||
|
||||
const uint32_t kControlObserveDataPath = (1<<31);
|
||||
const uint32_t kControlObserveHDCP = (1<<30);
|
||||
const uint32_t kControlObserveCGMS = (1<<29);
|
||||
const uint32_t kControlDataPathSecure = (1<<4);
|
||||
const uint32_t kControlNonceEnabled = (1<<3);
|
||||
const uint32_t kControlHDCPRequired = (1<<2);
|
||||
const uint32_t kControlCGMSMask = (0x03);
|
||||
const uint32_t kControlCGMSCopyFreely = (0x00);
|
||||
const uint32_t kControlCGMSCopyOnce = (0x02);
|
||||
const uint32_t kControlCGMSCopyNever = (0x03);
|
||||
|
||||
class KeyControlBlock {
|
||||
public:
|
||||
KeyControlBlock() {}
|
||||
KeyControlBlock(const std::vector<uint8_t>& key_control_string) {
|
||||
valid_ = SetFromString(key_control_string);
|
||||
}
|
||||
~KeyControlBlock() {}
|
||||
|
||||
bool SetFromString(const std::vector<uint8_t>& key_control_string);
|
||||
bool Validate();
|
||||
void Invalidate() { valid_ = false; }
|
||||
|
||||
bool valid() const { return valid_; }
|
||||
uint32_t duration() const { return duration_; }
|
||||
uint32_t nonce() const { return nonce_; }
|
||||
uint32_t control_bits() const { return control_bits_; }
|
||||
|
||||
private:
|
||||
|
||||
uint32_t ExtractField(const std::vector<uint8_t>& str, int idx);
|
||||
|
||||
bool valid_;
|
||||
uint32_t verification_;
|
||||
uint32_t duration_;
|
||||
uint32_t nonce_;
|
||||
uint32_t control_bits_;
|
||||
};
|
||||
|
||||
// AES-128 crypto key
|
||||
class Key {
|
||||
public:
|
||||
Key() : valid_(false), type_(KEYTYPE_UNKNOWN), has_control_(false) {}
|
||||
Key(const Key& key) : valid_(key.valid_), type_(key.type_),
|
||||
value_(key.value_),
|
||||
has_control_(key.has_control_),
|
||||
control_(key.control_) {}
|
||||
Key(KeyType type, const std::vector<uint8_t>& key_string,
|
||||
const KeyControlBlock& control);
|
||||
|
||||
virtual ~Key() {};
|
||||
|
||||
// Key is valid iff setValue(), setType(), and setControl() have been called
|
||||
bool setValue(const char* key_string, size_t key_string_length);
|
||||
bool setType(KeyType ktype);
|
||||
bool setControl(const KeyControlBlock& control);
|
||||
bool UpdateControl(const KeyControlBlock& control) { return true; }
|
||||
|
||||
KeyType keyType() { return type_; }
|
||||
const std::vector<uint8_t>& value() const { return value_; }
|
||||
const KeyControlBlock& control() const { return control_; }
|
||||
|
||||
bool isDeviceKey() { return (KEYTYPE_DEVICE == type_); }
|
||||
bool isRootKey() { return (KEYTYPE_ROOT == type_); }
|
||||
bool isPreprovKey() { return (KEYTYPE_PREPROV == type_); }
|
||||
bool isContentKey() {
|
||||
bool ctypes = (KEYTYPE_CONTENT == type_) ||
|
||||
(KEYTYPE_CONTENT_AUDIO == type_) ||
|
||||
(KEYTYPE_CONTENT_VIDEO == type_);
|
||||
return ctypes;
|
||||
}
|
||||
bool isValidType() {
|
||||
return ((KEYTYPE_UNKNOWN < type_) && (KEYTYPE_MAX > type_));
|
||||
}
|
||||
bool isValid() { return valid_; }
|
||||
|
||||
void clear() { value_.clear(); valid_ = false; }
|
||||
|
||||
private:
|
||||
bool valid_;
|
||||
KeyType type_;
|
||||
std::vector<uint8_t> value_;
|
||||
bool has_control_;
|
||||
KeyControlBlock control_;
|
||||
};
|
||||
|
||||
}; // namespace wvoec_eng
|
||||
|
||||
#endif
|
||||
@@ -1,109 +0,0 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "l3crypto_keybox_mock.h"
|
||||
#include <arpa/inet.h> // TODO(fredgc): Add ntoh to wv_cdm_utilities.h
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <sys/types.h>
|
||||
#include "log.h"
|
||||
#include "wvcrc32.h"
|
||||
#include "wv_keybox.h"
|
||||
|
||||
namespace wvoec_obfs {
|
||||
|
||||
const WidevineKeybox kDefaultKeybox = {
|
||||
// Sample keybox used for test vectors
|
||||
{
|
||||
// deviceID
|
||||
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey01
|
||||
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
||||
}, {
|
||||
// key
|
||||
0xfb, 0xda, 0x04, 0x89, 0xa1, 0x58, 0x16, 0x0e,
|
||||
0xa4, 0x02, 0xe9, 0x29, 0xe3, 0xb6, 0x8f, 0x04,
|
||||
}, {
|
||||
// data
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19,
|
||||
0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1,
|
||||
0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd,
|
||||
0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, 0xd8,
|
||||
0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64,
|
||||
0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8,
|
||||
0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, 0xa8,
|
||||
0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64,
|
||||
0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39,
|
||||
}, {
|
||||
// magic
|
||||
0x6b, 0x62, 0x6f, 0x78,
|
||||
}, {
|
||||
// Crc
|
||||
0x0a, 0x7a, 0x2c, 0x35,
|
||||
}
|
||||
};
|
||||
|
||||
WvKeybox::WvKeybox() : valid_(false) {
|
||||
Prepare();
|
||||
}
|
||||
|
||||
bool WvKeybox::Prepare() {
|
||||
InstallKeybox(reinterpret_cast<const uint8_t*>(&kDefaultKeybox),
|
||||
sizeof(kDefaultKeybox));
|
||||
valid_ = true;
|
||||
return valid_;
|
||||
}
|
||||
|
||||
KeyboxError WvKeybox::Validate() {
|
||||
if (!valid_) {
|
||||
LOGE("[KEYBOX NOT LOADED]");
|
||||
return OTHER_ERROR;
|
||||
}
|
||||
if (strncmp(reinterpret_cast<char*>(magic_), "kbox", 4) != 0) {
|
||||
LOGE("[KEYBOX HAS BAD MAGIC]");
|
||||
return BAD_MAGIC;
|
||||
}
|
||||
uint32_t crc_computed;
|
||||
uint32_t* crc_stored = (uint32_t*)crc_;
|
||||
WidevineKeybox keybox;
|
||||
memset(&keybox, 0, sizeof(keybox));
|
||||
memcpy(keybox.device_id_, &device_id_[0], device_id_.size());
|
||||
memcpy(keybox.device_key_, &device_key_.value()[0], sizeof(keybox.device_key_));
|
||||
memcpy(keybox.data_, key_data_, sizeof(keybox.data_));
|
||||
memcpy(keybox.magic_, magic_, sizeof(keybox.magic_));
|
||||
|
||||
crc_computed = ntohl(wvcrc32(reinterpret_cast<uint8_t*>(&keybox),
|
||||
sizeof(keybox) - 4)); // Don't include last 4 bytes.
|
||||
if (crc_computed != *crc_stored) {
|
||||
LOGE("[KEYBOX CRC problem: computed = %08x, stored = %08x]\n",
|
||||
crc_computed, *crc_stored);
|
||||
return BAD_CRC;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool WvKeybox::InstallKeybox(const uint8_t* buffer, size_t keyBoxLength) {
|
||||
if (keyBoxLength != 128) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const WidevineKeybox* keybox
|
||||
= reinterpret_cast<const WidevineKeybox*>(buffer);
|
||||
device_id_.assign(keybox->device_id_,
|
||||
keybox->device_id_ + sizeof(keybox->device_id_));
|
||||
device_key_.setValue(reinterpret_cast<const char*>(keybox->device_key_),
|
||||
sizeof(keybox->device_key_));
|
||||
device_key_.setType(KEYTYPE_DEVICE);
|
||||
memcpy(key_data_, keybox->data_, sizeof(keybox->data_));
|
||||
memcpy(magic_, keybox->magic_, sizeof(keybox->magic_));
|
||||
memcpy(crc_, keybox->crc_, sizeof(keybox->crc_));
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // namespace wvoec_eng
|
||||
@@ -1,50 +0,0 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef L3CRYPTO_KEYBOX_MOCK_H_
|
||||
#define L3CRYPTO_KEYBOX_MOCK_H_
|
||||
|
||||
#include "l3crypto_key_mock.h"
|
||||
|
||||
namespace wvoec_obfs {
|
||||
|
||||
const int DEVICE_KEY_LENGTH = 16;
|
||||
typedef uint8_t WvKeyboxKey[DEVICE_KEY_LENGTH];
|
||||
|
||||
const int KEY_DATA_LENGTH = 72;
|
||||
typedef uint8_t WvKeyboxKeyData[KEY_DATA_LENGTH];
|
||||
|
||||
enum KeyboxError { NO_ERROR, BAD_CRC, BAD_MAGIC, OTHER_ERROR };
|
||||
|
||||
// Widevine keybox
|
||||
class WvKeybox {
|
||||
public:
|
||||
WvKeybox();
|
||||
~WvKeybox() {}
|
||||
|
||||
KeyboxError Validate();
|
||||
const std::vector<uint8_t>& device_id() { return device_id_; }
|
||||
Key& device_key() { return device_key_; }
|
||||
const WvKeyboxKeyData& key_data() { return key_data_; }
|
||||
size_t key_data_length() { return KEY_DATA_LENGTH; }
|
||||
bool InstallKeybox(const uint8_t* keybox, size_t keyBoxLength);
|
||||
|
||||
private:
|
||||
|
||||
bool Prepare();
|
||||
|
||||
bool valid_;
|
||||
std::vector<uint8_t> device_id_;
|
||||
Key device_key_;
|
||||
WvKeyboxKeyData key_data_;
|
||||
uint8_t magic_[4];
|
||||
uint8_t crc_[4];
|
||||
};
|
||||
|
||||
}; // namespace wvoec_eng
|
||||
#endif
|
||||
@@ -1,633 +0,0 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "L3CryptoCENC.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include "log.h"
|
||||
#include "l3crypto_engine_mock.h"
|
||||
#include "openssl/rand.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvoec_obfs {
|
||||
|
||||
static CryptoEngine* crypto_engine = NULL;
|
||||
|
||||
// Set this to true when you are generating test vectors.
|
||||
const bool trace_all_calls = false;
|
||||
|
||||
static void dump_hex(std::string name, const uint8_t* vector, size_t length) {
|
||||
printf("%s = ", name.c_str());
|
||||
if (vector == NULL) {
|
||||
printf("NULL;\n");
|
||||
return;
|
||||
}
|
||||
// TODO(fredgc): replace with HEXEncode.
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (i == 0) {
|
||||
printf("\n wvcdm::a2b_hex(\"");
|
||||
} else if (i % 32 == 0) {
|
||||
printf("\"\n \"");
|
||||
}
|
||||
printf("%02X", vector[i]);
|
||||
}
|
||||
printf("\");\n");
|
||||
}
|
||||
|
||||
void dump_array_part(std::string array, size_t index,
|
||||
std::string name, const uint8_t* vector, size_t length) {
|
||||
if (vector == NULL) {
|
||||
printf("%s[%d].%s = NULL;\n", array.c_str(), index, name.c_str());
|
||||
return;
|
||||
}
|
||||
printf("std::string s%d_", index);
|
||||
dump_hex(name, vector, length);
|
||||
printf("%s[%d].%s = message_ptr + message.find(s%d_%s.data());\n",
|
||||
array.c_str(), index, name.c_str(), index, name.c_str());
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_Initialize(void) {
|
||||
if (trace_all_calls) {
|
||||
printf("------------------------- L3Crypto_Initialize(void)\n");
|
||||
}
|
||||
|
||||
crypto_engine = new CryptoEngine;
|
||||
|
||||
if (!crypto_engine || !crypto_engine->Initialized()) {
|
||||
LOGE("[L3Crypto_Initialize(): failed]");
|
||||
return OEMCrypto_ERROR_INIT_FAILED;
|
||||
}
|
||||
LOGD("[L3Crypto_Initialize(): success]");
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_Terminate(void) {
|
||||
if (trace_all_calls) {
|
||||
printf("----------------- OEMCryptoResult L3Crypto_Terminate(void)\n");
|
||||
}
|
||||
|
||||
if (!crypto_engine) {
|
||||
LOGE("[L3Crypto_Terminate(): failed]");
|
||||
return OEMCrypto_ERROR_TERMINATE_FAILED;
|
||||
}
|
||||
|
||||
if (crypto_engine->Initialized()) {
|
||||
crypto_engine->Terminate();
|
||||
}
|
||||
|
||||
delete crypto_engine;
|
||||
crypto_engine = NULL;
|
||||
LOGD("[L3Crypto_Terminate(): success]");
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_OpenSession(OEMCrypto_SESSION* session) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_OpenSession(OEMCrypto_SESSION *session)\n");
|
||||
}
|
||||
SessionId sid = crypto_engine->CreateSession();
|
||||
*session = (OEMCrypto_SESSION)sid;
|
||||
LOGD("[L3Crypto_OpenSession(): SID=%08x]", sid);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_CloseSession(OEMCrypto_SESSION session) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_CloseSession(OEMCrypto_SESSION session)\n");
|
||||
}
|
||||
if (!crypto_engine->DestroySession((SessionId)session)) {
|
||||
LOGD("[L3Crypto_CloseSession(SID=%08X): failed]", session);
|
||||
return OEMCrypto_ERROR_CLOSE_SESSION_FAILED;
|
||||
} else {
|
||||
LOGD("[L3Crypto_CloseSession(SID=%08X): success]", session);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_GenerateNonce(OEMCrypto_SESSION session,
|
||||
uint32_t* nonce) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_GenerateNonce(OEMCrypto_SESSION session,\n");
|
||||
}
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[L3Crypto_GenerateNonce(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
uint32_t nonce_value;
|
||||
uint8_t* nonce_string = reinterpret_cast<uint8_t*>(&nonce_value);
|
||||
|
||||
// Generate 4 bytes of random data
|
||||
if (!RAND_bytes(nonce_string, 4)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
session_ctx->AddNonce(nonce_value);
|
||||
*nonce = nonce_value;
|
||||
if (trace_all_calls) {
|
||||
printf("nonce = %08x\n", nonce_value);
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_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 (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_GenerateDerivedKeys(\n");
|
||||
dump_hex("mac_key_context", mac_key_context, (size_t)mac_key_context_length);
|
||||
dump_hex("enc_key_context", enc_key_context, (size_t)enc_key_context_length);
|
||||
}
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[L3Crypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[L3Crypto_GenerateDerivedKeys(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> mac_ctx_str(mac_key_context,
|
||||
mac_key_context + mac_key_context_length);
|
||||
const std::vector<uint8_t> enc_ctx_str(enc_key_context,
|
||||
enc_key_context + enc_key_context_length);
|
||||
|
||||
// Generate mac and encryption keys for current session context
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, enc_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_GenerateSignature(
|
||||
OEMCrypto_SESSION session,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_GenerateSignature(\n");
|
||||
dump_hex("message", message, message_length);
|
||||
}
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[L3Crypto_GenerateSignature(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
LOGE("[L3Crypto_GenerateSignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[L3Crypto_GenerateSignature(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
if (session_ctx->GenerateSignature(message,
|
||||
message_length,
|
||||
signature,
|
||||
signature_length)) {
|
||||
if (trace_all_calls) {
|
||||
dump_hex("signature", signature, *signature_length);
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;;
|
||||
}
|
||||
|
||||
bool RangeCheck(const uint8_t* message,
|
||||
uint32_t message_length,
|
||||
const uint8_t* field,
|
||||
uint32_t field_length,
|
||||
bool allow_null) {
|
||||
if (field == NULL) return allow_null;
|
||||
if (field < message) return false;
|
||||
if (field + field_length > message + message_length) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_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 (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_LoadKeys(OEMCrypto_SESSION session,\n");
|
||||
dump_hex("message", message, message_length);
|
||||
dump_hex("signature", signature, signature_length);
|
||||
dump_hex("enc_mac_key_iv", enc_mac_key_iv, wvcdm::KEY_IV_SIZE);
|
||||
dump_hex("enc_mac_key", enc_mac_key, wvcdm::MAC_KEY_SIZE);
|
||||
for (size_t i = 0; i < num_keys; i++) {
|
||||
printf("key_array[%d].key_id_length=%d;\n", i, key_array[i].key_id_length);
|
||||
dump_array_part("key_array", i, "key_id",
|
||||
key_array[i].key_id, key_array[i].key_id_length);
|
||||
dump_array_part("key_array", i, "key_data_iv",
|
||||
key_array[i].key_data_iv, wvcdm::KEY_IV_SIZE);
|
||||
dump_array_part("key_array", i, "key_data",
|
||||
key_array[i].key_data, wvcdm::KEY_IV_SIZE);
|
||||
dump_array_part("key_array", i, "key_control_iv",
|
||||
key_array[i].key_control_iv, wvcdm::KEY_IV_SIZE);
|
||||
dump_array_part("key_array", i, "key_control",
|
||||
key_array[i].key_control, wvcdm::KEY_IV_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[L3Crypto_LoadKeys(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[L3Crypto_LoadKeys(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0 ||
|
||||
key_array == NULL || num_keys == 0) {
|
||||
LOGE("[L3Crypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
// Range check
|
||||
if (!RangeCheck(message, message_length, enc_mac_key,
|
||||
wvcdm::MAC_KEY_SIZE, true) ||
|
||||
!RangeCheck(message, message_length, enc_mac_key_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[L3Crypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE - range check.]");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
if (!RangeCheck(message, message_length, key_array[i].key_id,
|
||||
key_array[i].key_id_length, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_data,
|
||||
wvcdm::KEY_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_data_iv,
|
||||
wvcdm::KEY_IV_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[L3Crypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE -range check %d]", i);
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate message signature
|
||||
if (!session_ctx->ValidateMessage(message, message_length, signature, signature_length)) {
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
// Decrypt and install keys in key object
|
||||
std::vector<uint8_t> key_id;
|
||||
std::vector<uint8_t> enc_key_data;
|
||||
std::vector<uint8_t> key_data_iv;
|
||||
std::vector<uint8_t> key_control;
|
||||
std::vector<uint8_t> key_control_iv;
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
key_id.assign(key_array[i].key_id,
|
||||
key_array[i].key_id + key_array[i].key_id_length);
|
||||
enc_key_data.assign(key_array[i].key_data,
|
||||
key_array[i].key_data + wvcdm::KEY_SIZE);
|
||||
key_data_iv.assign(key_array[i].key_data_iv,
|
||||
key_array[i].key_data_iv + wvcdm::KEY_IV_SIZE);
|
||||
if (key_array[i].key_control == NULL) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
|
||||
if (!session_ctx->InstallKey(key_id, enc_key_data, key_data_iv, key_control,
|
||||
key_control_iv)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// enc_mac_key can be NULL if license renewal is not supported
|
||||
if (enc_mac_key == NULL) return OEMCrypto_SUCCESS;
|
||||
|
||||
// V2 license protocol: update mac key after processing license response
|
||||
const std::vector<uint8_t> enc_mac_key_str = std::vector<uint8_t>(
|
||||
enc_mac_key, enc_mac_key + wvcdm::MAC_KEY_SIZE);
|
||||
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
|
||||
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
|
||||
|
||||
if (!session_ctx->UpdateMacKey(enc_mac_key_str, enc_mac_key_iv_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_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 (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_RefreshKeys(OEMCrypto_SESSION session,\n");
|
||||
}
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[L3Crypto_RefreshKeys(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[L3Crypto_RefreshKeys(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
LOGE("[L3Crypto_RefreshKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
// Range check
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
if (!RangeCheck(message, message_length, key_array[i].key_id,
|
||||
key_array[i].key_id_length, true) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[L3Crypto_RefreshKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE]");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate message signature
|
||||
if (!session_ctx->ValidateMessage(message, message_length,
|
||||
signature, signature_length)) {
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
// Decrypt and refresh keys in key refresh object
|
||||
std::vector<uint8_t> key_id;
|
||||
std::vector<uint8_t> key_control;
|
||||
std::vector<uint8_t> key_control_iv;
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
// TODO(gmorgan): key_id may be null if special control key type (TBS)
|
||||
if (key_array[i].key_id != NULL) {
|
||||
key_id.assign(key_array[i].key_id,
|
||||
key_array[i].key_id + key_array[i].key_id_length);
|
||||
} else {
|
||||
key_id.clear();
|
||||
}
|
||||
if (key_array[i].key_control != NULL) {
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
} else {
|
||||
key_control.clear();
|
||||
key_control_iv.clear();
|
||||
}
|
||||
|
||||
if (!session_ctx->RefreshKey(key_id, key_control, key_control_iv)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_SelectKey(const OEMCrypto_SESSION session,
|
||||
const uint8_t* key_id,
|
||||
size_t key_id_length) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_SelectKey(const OEMCrypto_SESSION session,\n");
|
||||
dump_hex("key_id", key_id, key_id_length);
|
||||
}
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[L3Crypto_SelectKey(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[L3Crypto_SelectKey(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> key_id_str = std::vector<uint8_t>(key_id, key_id + key_id_length);
|
||||
if (!session_ctx->SelectContentKey(key_id_str)) {
|
||||
LOGE("[L3Crypto_SelectKey(): FAIL]");
|
||||
return OEMCrypto_ERROR_NO_CONTENT_KEY;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_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 (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_DecryptCTR(OEMCrypto_SESSION session,\n");
|
||||
}
|
||||
wvoec_obfs::BufferType buffer_type = BUFFER_TYPE_DIRECT;
|
||||
void *destination = NULL;
|
||||
size_t max_length = 0;
|
||||
switch (out_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
buffer_type = BUFFER_TYPE_CLEAR;
|
||||
destination = out_buffer->buffer.clear.address;
|
||||
max_length = out_buffer->buffer.clear.max_length;
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
buffer_type = BUFFER_TYPE_SECURE;
|
||||
destination = out_buffer->buffer.secure.handle;
|
||||
max_length = out_buffer->buffer.secure.max_length;
|
||||
break;
|
||||
default:
|
||||
case OEMCrypto_BufferType_Direct:
|
||||
buffer_type = BUFFER_TYPE_DIRECT;
|
||||
destination = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (buffer_type != BUFFER_TYPE_DIRECT && max_length < data_length) {
|
||||
LOGE("[L3Crypto_DecryptCTR(): OEMCrypto_ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[L3Crypto_DecryptCTR(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[L3Crypto_DecryptCTR(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
if (data_addr == NULL || data_length == 0 ||
|
||||
iv == NULL || out_buffer == NULL) {
|
||||
LOGE("[L3Crypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> iv_v(iv, iv+16);
|
||||
std::vector<uint8_t> content(data_addr, data_addr+data_length);
|
||||
|
||||
if (!crypto_engine->DecryptCTR(session_ctx, iv_v, (int)offset,
|
||||
content, is_encrypted,
|
||||
destination, buffer_type)) {
|
||||
LOGE("[L3Crypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_InstallKeybox(const uint8_t* keybox,
|
||||
size_t keyBoxLength) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_InstallKeybox(const uint8_t *keybox,\n");
|
||||
}
|
||||
if (crypto_engine->keybox().InstallKeybox(keybox, keyBoxLength)) {
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
return OEMCrypto_ERROR_WRITE_KEYBOX;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_IsKeyboxValid(void) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_IsKeyboxValid(void) {\n");
|
||||
}
|
||||
switch(crypto_engine->ValidateKeybox()) {
|
||||
case NO_ERROR: return OEMCrypto_SUCCESS;
|
||||
case BAD_CRC: return OEMCrypto_ERROR_BAD_CRC;
|
||||
case BAD_MAGIC: return OEMCrypto_ERROR_BAD_MAGIC;
|
||||
default:
|
||||
case OTHER_ERROR: return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_GetDeviceID(uint8_t* deviceID,
|
||||
size_t* idLength) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_GetDeviceID(uint8_t* deviceID,\n");
|
||||
}
|
||||
std::vector<uint8_t> dev_id_string = crypto_engine->keybox().device_id();
|
||||
if (dev_id_string.empty()) {
|
||||
LOGE("[L3Crypto_GetDeviceId(): Keybox Invalid]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
size_t dev_id_len = dev_id_string.size();
|
||||
if (*idLength < dev_id_len) {
|
||||
*idLength = dev_id_len;
|
||||
LOGE("[L3Crypto_GetDeviceId(): ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
memset(deviceID, 0, *idLength);
|
||||
memcpy(deviceID, &dev_id_string[0], dev_id_len);
|
||||
*idLength = dev_id_len;
|
||||
LOGD("[L3Crypto_GetDeviceId(): success]");
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_GetKeyData(uint8_t* keyData,
|
||||
size_t* keyDataLength) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_GetKeyData(uint8_t* keyData,\n");
|
||||
}
|
||||
size_t length = crypto_engine->keybox().key_data_length();
|
||||
if (*keyDataLength < length) {
|
||||
*keyDataLength = length;
|
||||
LOGE("[L3Crypto_GetKeyData(): ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
memset(keyData, 0, *keyDataLength);
|
||||
memcpy(keyData, crypto_engine->keybox().key_data(), length);
|
||||
*keyDataLength = length;
|
||||
LOGD("[L3Crypto_GetKeyData(): success]");
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_GetRandom(uint8_t* randomData, size_t dataLength) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_GetRandom(uint8_t* randomData, size_t dataLength) {\n");
|
||||
}
|
||||
if (!randomData) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (RAND_bytes(randomData, dataLength)) {
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult L3Crypto_WrapKeybox(const uint8_t* keybox,
|
||||
size_t keyBoxLength,
|
||||
uint8_t* wrappedKeybox,
|
||||
size_t* wrappedKeyBoxLength,
|
||||
const uint8_t* transportKey,
|
||||
size_t transportKeyLength) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult L3Crypto_WrapKeybox(const uint8_t *keybox,\n");
|
||||
}
|
||||
if (!keybox || !wrappedKeybox || !wrappedKeyBoxLength
|
||||
|| (keyBoxLength != *wrappedKeyBoxLength)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
// This implementation ignores the transport key. For test keys, we
|
||||
// don't need to encrypt the keybox.
|
||||
memcpy(wrappedKeybox, keybox, keyBoxLength);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
}; // namespace wvoec_obfs
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Lock class - provides a simple android specific mutex implementation
|
||||
|
||||
#include "lock.h"
|
||||
#include "utils/Mutex.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class Lock::Impl {
|
||||
public:
|
||||
android::Mutex lock_;
|
||||
};
|
||||
|
||||
Lock::Lock() : impl_(new Lock::Impl()) {
|
||||
}
|
||||
|
||||
Lock::~Lock() {
|
||||
delete impl_;
|
||||
impl_ = NULL;
|
||||
}
|
||||
|
||||
void Lock::Acquire() {
|
||||
impl_->lock_.lock();
|
||||
}
|
||||
|
||||
void Lock::Release() {
|
||||
impl_->lock_.unlock();
|
||||
}
|
||||
|
||||
bool Lock::Try() {
|
||||
return (impl_->lock_.tryLock() == 0);
|
||||
}
|
||||
|
||||
class AutoLock::Impl {
|
||||
public:
|
||||
android::Mutex::Autolock *autolock_;
|
||||
};
|
||||
|
||||
AutoLock::AutoLock(Lock& lock) : impl_(new AutoLock::Impl()) {
|
||||
impl_->autolock_ = new android::Mutex::Autolock(lock.impl_->lock_);
|
||||
}
|
||||
|
||||
AutoLock::AutoLock(Lock* lock) : impl_(new AutoLock::Impl()) {
|
||||
impl_->autolock_ = new android::Mutex::Autolock(lock->impl_->lock_);
|
||||
}
|
||||
|
||||
AutoLock::~AutoLock() {
|
||||
delete impl_->autolock_;
|
||||
delete impl_;
|
||||
impl_ = NULL;
|
||||
}
|
||||
|
||||
}; // namespace wvcdm
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Lock - Platform independent interface for a Mutex class
|
||||
//
|
||||
#ifndef L3CRYPTO_LOCK_H_
|
||||
#define L3CRYPTO_LOCK_H_
|
||||
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
// Simple lock class. The implementation is platform dependent.
|
||||
//
|
||||
// The lock must be unlocked by the thread that locked it.
|
||||
// The lock is also not recursive (ie. cannot be taken multiple times).
|
||||
class Lock {
|
||||
public:
|
||||
Lock();
|
||||
~Lock();
|
||||
|
||||
void Acquire();
|
||||
void Release();
|
||||
|
||||
// Acquires a lock if not held and returns true.
|
||||
// Returns false if the lock is held by another thread.
|
||||
bool Try();
|
||||
|
||||
friend class AutoLock;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
Impl *impl_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(Lock);
|
||||
};
|
||||
|
||||
// Manages the lock automatically. It will be locked when AutoLock
|
||||
// is constructed and release when AutoLock goes out of scope
|
||||
class AutoLock {
|
||||
public:
|
||||
explicit AutoLock(Lock& lock);
|
||||
explicit AutoLock(Lock* lock);
|
||||
~AutoLock();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
Impl *impl_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(AutoLock);
|
||||
};
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // L3CRYPTO_LOCK_H_
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Log - implemented using the standard Android logging mechanism
|
||||
|
||||
#define LOG_TAG "WVCdm"
|
||||
#define LOG_BUF_SIZE 1024
|
||||
|
||||
#include "log.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
void log_write(LogPriority level, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
char buf[LOG_BUF_SIZE];
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
android_LogPriority prio = ANDROID_LOG_VERBOSE;
|
||||
|
||||
switch(level) {
|
||||
case LOG_ERROR: prio = ANDROID_LOG_ERROR; break;
|
||||
case LOG_WARN: prio = ANDROID_LOG_WARN; break;
|
||||
case LOG_INFO: prio = ANDROID_LOG_INFO; break;
|
||||
case LOG_DEBUG: prio = ANDROID_LOG_DEBUG; break;
|
||||
case LOG_VERBOSE: prio = ANDROID_LOG_VERBOSE; break;
|
||||
}
|
||||
|
||||
__android_log_write(prio, LOG_TAG, buf);
|
||||
}
|
||||
|
||||
}; // namespace wvcdm
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Log - Platform independent interface for a Logging class
|
||||
//
|
||||
#ifndef OEMCRYPTO_LOG_H_
|
||||
#define OEMCRYPTO_LOG_H_
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
// Simple logging class. The implementation is platform dependent.
|
||||
|
||||
typedef enum {
|
||||
LOG_ERROR,
|
||||
LOG_WARN,
|
||||
LOG_INFO,
|
||||
LOG_DEBUG,
|
||||
LOG_VERBOSE
|
||||
} LogPriority;
|
||||
|
||||
void log_write(LogPriority priority, const char *fmt, ...);
|
||||
|
||||
// Log APIs
|
||||
#define LOGE(...) ((void)log_write(wvcdm::LOG_ERROR, __VA_ARGS__))
|
||||
#define LOGW(...) ((void)log_write(wvcdm::LOG_WARN, __VA_ARGS__))
|
||||
#define LOGI(...) ((void)log_write(wvcdm::LOG_INFO, __VA_ARGS__))
|
||||
#define LOGD(...) ((void)log_write(wvcdm::LOG_DEBUG, __VA_ARGS__))
|
||||
#define LOGV(...) ((void)log_write(wvcdm::LOG_VERBOSE, __VA_ARGS__))
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // OEMCRYPTO_LOG_H_
|
||||
@@ -1,79 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "string_conversions.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
static bool CharToDigit(char ch, unsigned char* digit) {
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
*digit = ch - '0';
|
||||
} else {
|
||||
ch = tolower(ch);
|
||||
if ((ch >= 'a') && (ch <= 'f')) {
|
||||
*digit = ch - 'a' + 10;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// converts an ascii hex string(2 bytes per digit) into a decimal byte string
|
||||
std::vector<uint8_t> a2b_hex(const std::string& byte) {
|
||||
std::vector<uint8_t> array(0);
|
||||
unsigned int count = byte.size();
|
||||
if (count == 0 || (count % 2) != 0) {
|
||||
LOGE("Invalid input size %u for string %s", count, byte.c_str());
|
||||
return array;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < count / 2; ++i) {
|
||||
unsigned char msb = 0; // most significant 4 bits
|
||||
unsigned char lsb = 0; // least significant 4 bits
|
||||
if (!CharToDigit(byte[i * 2], &msb) ||
|
||||
!CharToDigit(byte[i * 2 + 1], &lsb)) {
|
||||
LOGE("Invalid hex value %c%c at index %d", byte[i*2], byte[i*2+1], i);
|
||||
return array;
|
||||
}
|
||||
array.push_back((msb << 4) | lsb);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
std::string b2a_hex(const std::vector<uint8_t>& byte) {
|
||||
return HexEncode(&byte[0], byte.size());
|
||||
}
|
||||
|
||||
std::string HexEncode(const uint8_t* in_buffer, unsigned int size) {
|
||||
static const char kHexChars[] = "0123456789ABCDEF";
|
||||
|
||||
// Each input byte creates two output hex characters.
|
||||
std::string out_buffer(size * 2, '\0');
|
||||
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
char byte = in_buffer[i];
|
||||
out_buffer[(i << 1)] = kHexChars[(byte >> 4) & 0xf];
|
||||
out_buffer[(i << 1) + 1] = kHexChars[byte & 0xf];
|
||||
}
|
||||
return out_buffer;
|
||||
}
|
||||
|
||||
std::string IntToString(int value) {
|
||||
// log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
|
||||
// So round up to allocate 3 output characters per byte, plus 1 for '-'.
|
||||
const int kOutputBufSize = 3 * sizeof(int) + 1;
|
||||
char buffer[kOutputBufSize];
|
||||
memset(buffer, 0, kOutputBufSize);
|
||||
snprintf(buffer, kOutputBufSize, "%d", value);
|
||||
|
||||
std::string out_string(buffer, sizeof(buffer));
|
||||
return out_string;
|
||||
}
|
||||
|
||||
}; // namespace wvcdm
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef OEMCRYPTO_STRING_CONVERSIONS_H_
|
||||
#define OEMCRYPTO_STRING_CONVERSIONS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
std::vector<uint8_t> a2b_hex(const std::string& b);
|
||||
std::string b2a_hex(const std::vector<uint8_t>& b);
|
||||
std::string HexEncode(const uint8_t* bytes, unsigned size);
|
||||
std::string IntToString(int value);
|
||||
|
||||
}; // namespace wvcdm
|
||||
|
||||
#endif // OEMCRYPTO_STRING_CONVERSIONS_H_
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef OEMCRYPTO_WV_CDM_CONSTANTS_H_
|
||||
#define OEMCRYPTO_WV_CDM_CONSTANTS_H_
|
||||
|
||||
namespace wvcdm {
|
||||
static const size_t KEY_CONTROL_SIZE = 16;
|
||||
static const size_t KEY_IV_SIZE = 16;
|
||||
static const size_t KEY_PAD_SIZE = 16;
|
||||
static const size_t KEY_SIZE = 16;
|
||||
static const size_t MAC_KEY_SIZE = 32;
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // OEMCRYPTO_WV_CDM_CONSTANTS_H_
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef L3CRYPTO_WV_CDM_TYPES_H_
|
||||
#define L3CRYPTO_WV_CDM_TYPES_H_
|
||||
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
typedef std::string CdmKeySystem;
|
||||
typedef std::string CdmInitData;
|
||||
typedef std::string CdmKeyMessage;
|
||||
typedef std::string CdmKeyResponse;
|
||||
typedef std::string KeyId;
|
||||
typedef std::string CdmSessionId;
|
||||
typedef std::string RequestId;
|
||||
typedef uint32_t CryptoResult;
|
||||
typedef uint32_t CryptoSessionId;
|
||||
typedef std::string CryptoKeyId;
|
||||
|
||||
enum CdmResponseType {
|
||||
NO_ERROR,
|
||||
UNKNOWN_ERROR,
|
||||
KEY_ADDED,
|
||||
KEY_ERROR,
|
||||
KEY_MESSAGE,
|
||||
NEED_KEY,
|
||||
KEY_CANCELED,
|
||||
};
|
||||
|
||||
#define CORE_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
enum CdmEventType {
|
||||
LICENSE_EXPIRED,
|
||||
LICENSE_RENEWAL_NEEDED
|
||||
};
|
||||
|
||||
// forward class references
|
||||
class KeyMessage;
|
||||
class Request;
|
||||
class Key;
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // L3CRYPTO_WV_CDM_TYPES_H_
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef WV_KEYBOX_H_
|
||||
#define WV_KEYBOX_H_
|
||||
|
||||
namespace wvoec_obfs {
|
||||
|
||||
// This is the format of a Widevine keybox.
|
||||
typedef struct { // 128 bytes total.
|
||||
// C character string identifying the device. Null terminated.
|
||||
uint8_t device_id_[32];
|
||||
// 128 bit AES key assigned to device. Generated by Widevine.
|
||||
uint8_t device_key_[16];
|
||||
// Key Data. Encrypted data.
|
||||
uint8_t data_[72];
|
||||
// Constant code used to recognize a valid keybox "kbox" = 0x6b626f78.
|
||||
uint8_t magic_[4];
|
||||
// The CRC checksum of the first 124 bytes of the keybox.
|
||||
uint8_t crc_[4];
|
||||
} WidevineKeybox;
|
||||
|
||||
}
|
||||
|
||||
#endif // WV_KEYBOX_H_
|
||||
@@ -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_CRC_32_H_
|
||||
1162
libwvdrmengine/level3/mips/entry_points.cpp
Normal file
1162
libwvdrmengine/level3/mips/entry_points.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1162
libwvdrmengine/level3/x86/entry_points.cpp
Normal file
1162
libwvdrmengine/level3/x86/entry_points.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user