Builds libwvmdrmengine.so, which is loaded by the new MediaDrm APIs to support playback of Widevine/CENC protected content. Change-Id: I6f57dd37083dfd96c402cb9dd137c7d74edc8f1c
634 lines
22 KiB
C++
634 lines
22 KiB
C++
/*******************************************************************************
|
|
*
|
|
* 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
|