Widevine CENC drm engine update: enable decryption

This import syncs to the widevine git repostiory change
commit ab3e1e43642cf36900f55169597a33f222709fdb

Change-Id: I3a6f1e2969e5fe7ed1ca12f90b0eb0a3b7899835
This commit is contained in:
Jeff Tinker
2013-04-09 13:24:32 -07:00
parent c0f1d6750e
commit 826576315c
14 changed files with 630 additions and 143 deletions

View File

@@ -278,10 +278,28 @@ CdmResponseType CdmEngine::RenewKey(
CdmResponseType CdmEngine::QueryStatus(CdmQueryMap* key_info) {
LOGI("CdmEngine::QueryStatus");
CryptoEngine* crypto_engine = CryptoEngine::GetInstance();
if (crypto_engine) {
return crypto_engine->Query(key_info);
if (!crypto_engine) {
return KEY_ERROR;
}
return KEY_ERROR;
switch (crypto_engine->GetSecurityLevel()) {
case CryptoEngine::kSecurityLevelL1:
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1;
break;
case CryptoEngine::kSecurityLevelL2:
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L2;
break;
case CryptoEngine::kSecurityLevelL3:
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3;
break;
case CryptoEngine::kSecurityLevelUnknown:
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_Unknown;
break;
default:
return KEY_ERROR;
}
return NO_ERROR;
}
CdmResponseType CdmEngine::QueryKeyStatus(
@@ -325,23 +343,21 @@ CdmResponseType CdmEngine::Decrypt(
const CdmSessionId& session_id,
bool is_encrypted,
const KeyId& key_id,
const uint8_t* encrypted_buffer,
size_t encrypted_size,
const uint8_t* encrypt_buffer,
size_t encrypt_length,
const std::vector<uint8_t>& iv,
size_t block_offset,
uint8_t* decrypted_buffer) {
void* decrypt_buffer,
bool is_video) {
CdmSessionIter iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGW("CdmEngine::Decrypt: session_id not found = %s", session_id.c_str());
return KEY_ERROR;
}
if (NO_ERROR != iter->second->Decrypt(encrypted_buffer, encrypted_size,
block_offset, iv, key_id,
decrypted_buffer))
return UNKNOWN_ERROR;
return NO_ERROR;
return iter->second->Decrypt(is_encrypted, key_id, encrypt_buffer,
encrypt_length, iv, block_offset,
decrypt_buffer, is_video);
}
bool CdmEngine::IsKeyValid(const KeyId& key_id) {

View File

@@ -5,10 +5,11 @@
#include <iostream>
#include "clock.h"
#include "crypto_engine.h"
#include "log.h"
#include "properties.h"
#include "string_conversions.h"
#include "clock.h"
#include "wv_cdm_constants.h"
namespace wvcdm {
@@ -30,6 +31,15 @@ bool CdmSession::Init() {
std::string token;
if (!crypto_engine->GetToken(&token)) return false;
if (!Properties::GetInstance()->GetProperty(
kPropertyKeyRequireExplicitRenewRequest,
require_explicit_renew_request_)) {
LOGE("CdmSession::Init: Unable to access property - require explicit renew");
}
else {
properties_valid_ = true;
}
return license_parser_.Init(token, crypto_session_, &policy_engine_);
}
@@ -50,20 +60,57 @@ bool CdmSession::VerifySession(const CdmKeySystem& key_system,
CdmResponseType CdmSession::GenerateKeyRequest(const CdmInitData& init_data,
CdmKeyMessage* key_request) {
crypto_session_->Open();
if(!license_parser_.PrepareKeyRequest(init_data, key_request)) {
return KEY_ERROR;
} else {
return KEY_MESSAGE;
if (!properties_valid_) {
LOGW("CdmSession::GenerateKeyRequest: Unable to access properties");
return UNKNOWN_ERROR;
}
if (!crypto_session_) {
LOGW("CdmSession::GenerateKeyRequest: Invalid crypto session");
return UNKNOWN_ERROR;
}
if (!crypto_session_->IsOpen()) {
LOGW("CdmSession::GenerateKeyRequest: Crypto session not open");
return UNKNOWN_ERROR;
}
if (license_received_) {
return require_explicit_renew_request_ ?
UNKNOWN_ERROR : GenerateRenewalRequest(key_request);
}
else {
if(!license_parser_.PrepareKeyRequest(init_data, key_request)) {
return KEY_ERROR;
} else {
return KEY_MESSAGE;
}
}
}
// AddKey() - Accept license response and extract key info.
CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) {
if (!license_parser_.HandleKeyResponse(key_response)) {
return KEY_ERROR;
} else {
return KEY_ADDED;
if (!crypto_session_) {
LOGW("CdmSession::AddKey: Invalid crypto session");
return UNKNOWN_ERROR;
}
if (!crypto_session_->IsOpen()) {
LOGW("CdmSession::AddKey: Crypto session not open");
return UNKNOWN_ERROR;
}
if (license_received_) {
return require_explicit_renew_request_ ?
UNKNOWN_ERROR : RenewKey(key_response);
}
else {
if (!license_parser_.HandleKeyResponse(key_response)) {
return KEY_ERROR;
} else {
license_received_ = true;
return KEY_ADDED;
}
}
}
@@ -79,23 +126,29 @@ CdmResponseType CdmSession::CancelKeyRequest() {
}
// Decrypt() - Accept encrypted buffer and return decrypted data.
CdmResponseType CdmSession::Decrypt(const uint8_t* encrypted_buffer,
size_t encrypted_size,
size_t block_offset,
const std::vector<uint8_t>& iv,
CdmResponseType CdmSession::Decrypt(bool is_encrypted,
const KeyId& key_id,
uint8_t* decrypted_buffer) {
if (!crypto_session_)
const uint8_t* encrypt_buffer,
size_t encrypt_length,
const std::vector<uint8_t>& iv,
size_t block_offset,
void* decrypt_buffer,
bool is_video) {
if (!crypto_session_ || !crypto_session_->IsOpen())
return UNKNOWN_ERROR;
if (!crypto_session_->SelectKey(key_id))
return UNKNOWN_ERROR;
// Check if key needs to be selected
if (key_id_.compare(key_id) != 0) {
if (crypto_session_->SelectKey(key_id)) {
key_id_ = key_id;
}
else {
return UNKNOWN_ERROR;
}
}
if (!crypto_session_->Decrypt(encrypted_buffer, encrypted_size,
block_offset, iv, decrypted_buffer))
return UNKNOWN_ERROR;
return NO_ERROR;
return crypto_session_->Decrypt(is_encrypted, encrypt_buffer, encrypt_length,
iv, block_offset, decrypt_buffer, is_video);
}
// License renewal

View File

@@ -9,6 +9,7 @@
#include "log.h"
#include "OEMCryptoCENC.h"
#include "properties.h"
#include "wv_cdm_constants.h"
namespace wvcdm {
@@ -23,7 +24,11 @@ Lock CryptoEngine::crypto_engine_lock_;
// CryptoEngine methods
CryptoEngine::CryptoEngine() : initialized_(false) {}
CryptoEngine::CryptoEngine() : initialized_(false),
properties_valid_(false),
oem_crypto_use_secure_buffers_(false),
oem_crypto_use_fifo_(false),
oem_crypto_use_userspace_buffers_(false) {}
CryptoEngine::~CryptoEngine() {
if (initialized_) {
@@ -61,6 +66,29 @@ void CryptoEngine::DeleteInstance() {
}
bool CryptoEngine::Init() {
properties_valid_ = true;
if (!Properties::GetInstance()->GetProperty(
kPropertyKeyOemCryptoUseSecureBuffers,
oem_crypto_use_secure_buffers_)) {
LOGW("CryptoEngine::CryptoEngine: Unable to access property - oemcrypto use secure buffers");
properties_valid_ = false;
}
if (!Properties::GetInstance()->GetProperty(
kPropertyKeyOemCryptoUseFifo,
oem_crypto_use_fifo_)) {
LOGW("CryptoEngine::CryptoEngine: Unable to access property - oemcrypto use fifos");
properties_valid_ = false;
}
if (!Properties::GetInstance()->GetProperty(
kPropertyKeyOemCryptoUseUserSpaceBuffers,
oem_crypto_use_userspace_buffers_)) {
LOGW("CryptoEngine::CryptoEngine: Unable to access property - oemcrypto use userspace buffers");
properties_valid_ = false;
}
LOGV("CryptoEngine::Init: Lock");
AutoLock auto_lock(crypto_lock_);
if (!initialized_) {
@@ -175,10 +203,22 @@ bool CryptoEngine::GetToken(std::string* token) {
return true;
}
CdmResponseType CryptoEngine::Query(CdmQueryMap* key_info) {
LOGV("CryptoEngine::GetToken: Query");
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = OEMCrypto_SecurityLevel();
return NO_ERROR;
CryptoEngine::SecurityLevel CryptoEngine::GetSecurityLevel() {
std::string security_level = OEMCrypto_SecurityLevel();
if ((security_level.size() != 2) ||
(security_level.at(0) != 'L')) {
return kSecurityLevelUnknown;
}
switch (security_level.at(1)) {
case '1': return kSecurityLevelL1;
case '2': return kSecurityLevelL2;
case '3': return kSecurityLevelL3;
default : return kSecurityLevelUnknown;
}
return kSecurityLevelUnknown;
}
}; // namespace wvcdm

View File

@@ -35,10 +35,16 @@ namespace wvcdm {
// CryptoSession methods
CryptoSession::CryptoSession() : valid_(false), open_(false) {}
CryptoSession::CryptoSession() :
valid_(false),
open_(false),
is_destination_buffer_type_valid_(false) {}
CryptoSession::CryptoSession(const std::string& sname) : valid_(true),
open_(false), cdm_session_id_(sname) {}
CryptoSession::CryptoSession(const std::string& sname) :
valid_(true),
open_(false),
cdm_session_id_(sname),
is_destination_buffer_type_valid_(false) {}
CryptoSession::~CryptoSession() {
if (open_) {
@@ -222,7 +228,7 @@ bool CryptoSession::LoadKeys(const std::string& message,
enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
}
OEMCrypto_KeyObject load_key_array[num_keys];
std::vector<OEMCrypto_KeyObject> load_key_array(num_keys);
for (int i=0; i<num_keys; ++i) {
const CryptoKey* ki = &key_array[i];
OEMCrypto_KeyObject* ko = &load_key_array[i];
@@ -246,7 +252,7 @@ bool CryptoSession::LoadKeys(const std::string& message,
oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), enc_mac_key_iv, enc_mac_key,
num_keys, load_key_array));
num_keys, &load_key_array[0]));
}
bool CryptoSession::RefreshKeys(const std::string& message,
@@ -258,7 +264,7 @@ bool CryptoSession::RefreshKeys(const std::string& message,
AutoLock auto_lock(crypto_engine->crypto_lock_);
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
OEMCrypto_KeyRefreshObject load_key_array[num_keys];
std::vector<OEMCrypto_KeyRefreshObject> load_key_array(num_keys);
for (int i=0; i<num_keys; ++i) {
const CryptoKey* ki = &key_array[i];
OEMCrypto_KeyRefreshObject* ko = &load_key_array[i];
@@ -285,7 +291,7 @@ bool CryptoSession::RefreshKeys(const std::string& message,
oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(),
num_keys, load_key_array));
num_keys, &load_key_array[0]));
}
bool CryptoSession::SelectKey(const std::string& key_id) {
@@ -304,55 +310,49 @@ bool CryptoSession::SelectKey(const std::string& key_id) {
return true;
}
bool CryptoSession::Decrypt(const InputDescriptor input,
const OutputDescriptor output) {
LOGV("CryptoSession::Decrypt: Lock");
CryptoEngine* crypto_engine = CryptoEngine::GetInstance();
AutoLock auto_lock(crypto_engine->crypto_lock_);
// TODO(gmorgan): handle inputs and outputs to decrypt call
const uint8_t* data_addr = NULL;
uint32_t data_length = 0;
bool is_encrypted = false;
uint8_t* iv = NULL;
uint32_t offset = 0;
const OEMCrypto_DestBufferDesc* out_buffer = NULL;
OEMCryptoResult sts = OEMCrypto_DecryptCTR(oec_session_id_, data_addr,
data_length, is_encrypted, iv,
offset, out_buffer);
if (OEMCrypto_SUCCESS != sts) {
return false;
CdmResponseType CryptoSession::Decrypt(bool is_encrypted,
const uint8_t* encrypt_buffer,
size_t encrypt_length,
const std::vector<uint8_t>& iv,
size_t block_offset,
void* decrypt_buffer,
bool is_video) {
if (!is_destination_buffer_type_valid_) {
if (!SetDestinationBufferType())
return UNKNOWN_ERROR;
}
return true;
}
// TODO(jfore): Define InputDescriptor and OutputDecriptor and
// remove this method. For now this is a level 3 decrypt.
bool CryptoSession::Decrypt(const uint8_t* encrypted_buffer,
size_t encrypted_size,
size_t block_offset,
const std::vector<uint8_t>& iv,
uint8_t* decrypted_buffer) {
LOGV("CryptoSession::Decrypt: Lock");
CryptoEngine* crypto_engine = CryptoEngine::GetInstance();
AutoLock auto_lock(crypto_engine->crypto_lock_);
// TODO(gmorgan): handle inputs and outputs to decrypt call
const uint8_t* data_addr = NULL;
uint32_t data_length = 0;
bool is_encrypted = false;
uint32_t offset = block_offset;
OEMCrypto_DestBufferDesc out_buffer;
OEMCrypto_DestBufferDesc buffer_descriptor;
buffer_descriptor.type = destination_buffer_type_;
out_buffer.type = OEMCrypto_BufferType_Clear;
out_buffer.buffer.clear.address = decrypted_buffer;
out_buffer.buffer.clear.max_length = encrypted_size;
if (!is_encrypted)
buffer_descriptor.type = OEMCrypto_BufferType_Clear;
OEMCryptoResult sts = OEMCrypto_DecryptCTR(oec_session_id_, encrypted_buffer,
encrypted_size, true, &iv[0],
offset, &out_buffer);
if (OEMCrypto_SUCCESS != sts) {
return false;
switch (buffer_descriptor.type) {
case OEMCrypto_BufferType_Clear:
buffer_descriptor.buffer.clear.address =
static_cast<uint8_t*>(decrypt_buffer);
buffer_descriptor.buffer.clear.max_length = encrypt_length;
break;
case OEMCrypto_BufferType_Secure:
buffer_descriptor.buffer.secure.handle = decrypt_buffer;
buffer_descriptor.buffer.secure.max_length = encrypt_length;
break;
case OEMCrypto_BufferType_Direct:
buffer_descriptor.type = OEMCrypto_BufferType_Direct;
buffer_descriptor.buffer.direct.is_video = is_video;
break;
}
return true;
OEMCryptoResult sts = OEMCrypto_DecryptCTR(oec_session_id_, encrypt_buffer,
encrypt_length, is_encrypted,
&iv[0], block_offset,
&buffer_descriptor);
if (OEMCrypto_SUCCESS != sts) {
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
bool CryptoSession::GenerateNonce(uint32_t* nonce) {
@@ -366,4 +366,33 @@ bool CryptoSession::GenerateNonce(uint32_t* nonce) {
AutoLock auto_lock(crypto_engine->crypto_lock_);
return(OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(oec_session_id_, nonce));
}
bool CryptoSession::SetDestinationBufferType() {
CryptoEngine* crypto_engine = CryptoEngine::GetInstance();
if (!crypto_engine->properties_valid())
return false;
if (crypto_engine->oem_crypto_use_secure_buffers()) {
if (crypto_engine->GetSecurityLevel() == CryptoEngine::kSecurityLevelL1) {
destination_buffer_type_ = OEMCrypto_BufferType_Secure;
}
else {
destination_buffer_type_ = OEMCrypto_BufferType_Clear;
}
}
else if (crypto_engine->oem_crypto_use_fifo()) {
destination_buffer_type_ = OEMCrypto_BufferType_Direct;
}
else if (crypto_engine->oem_crypto_use_userspace_buffers()) {
destination_buffer_type_ = OEMCrypto_BufferType_Clear;
}
else {
return false;
}
is_destination_buffer_type_valid_ = true;
return true;
}
}; // namespace wvcdm