Squashed commit of the following CDM changes:
* Add additional parameters to CDM decryption API https://widevine-internal-review.googlesource.com/#/c/6500/ * Pass Length and Flags Parameters to Decrypt() https://widevine-internal-review.googlesource.com/#/c/6740/ * Remove core files from oemcrypto/mock https://widevine-internal-review.googlesource.com/#/c/6853/ Change-Id: I1c73f5454da20da99130b161543fb990e16e7130
This commit is contained in:
@@ -85,16 +85,7 @@ class CdmEngine : public TimerHandler {
|
|||||||
// Decryption and key related methods
|
// Decryption and key related methods
|
||||||
// Accept encrypted buffer and return decrypted data.
|
// Accept encrypted buffer and return decrypted data.
|
||||||
virtual CdmResponseType Decrypt(const CdmSessionId& session_id,
|
virtual CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||||
bool is_encrypted,
|
const CdmDecryptionParameters& parameters);
|
||||||
bool is_secure,
|
|
||||||
const KeyId& key_id,
|
|
||||||
const uint8_t* encrypt_buffer,
|
|
||||||
size_t encrypt_length,
|
|
||||||
const std::vector<uint8_t>& iv,
|
|
||||||
size_t block_offset,
|
|
||||||
void* decrypt_buffer,
|
|
||||||
size_t decrypt_buffer_offset,
|
|
||||||
bool is_video);
|
|
||||||
|
|
||||||
// Is the key known to any session?
|
// Is the key known to any session?
|
||||||
virtual bool IsKeyValid(const KeyId& key_id);
|
virtual bool IsKeyValid(const KeyId& key_id);
|
||||||
|
|||||||
@@ -59,11 +59,7 @@ class CdmSession {
|
|||||||
CdmResponseType QueryKeyControlInfo(CdmQueryMap* key_info);
|
CdmResponseType QueryKeyControlInfo(CdmQueryMap* key_info);
|
||||||
|
|
||||||
// Decrypt() - Accept encrypted buffer and return decrypted data.
|
// Decrypt() - Accept encrypted buffer and return decrypted data.
|
||||||
CdmResponseType Decrypt(bool is_encrypted, bool is_secure,
|
CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
||||||
const KeyId& key_id, const uint8_t* encrypt_buffer,
|
|
||||||
size_t encrypt_length, const std::vector<uint8_t>& iv,
|
|
||||||
size_t block_offset, void* decrypt_buffer,
|
|
||||||
size_t decrypt_buffer_offset, bool is_video);
|
|
||||||
|
|
||||||
// License renewal
|
// License renewal
|
||||||
// GenerateRenewalRequest() - Construct valid renewal request for the current
|
// GenerateRenewalRequest() - Construct valid renewal request for the current
|
||||||
|
|||||||
@@ -68,15 +68,7 @@ class CryptoSession {
|
|||||||
|
|
||||||
// Media data path
|
// Media data path
|
||||||
bool SelectKey(const std::string& key_id);
|
bool SelectKey(const std::string& key_id);
|
||||||
CdmResponseType Decrypt(bool is_encrypted,
|
CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
||||||
bool is_secure,
|
|
||||||
const uint8_t* encrypt_buffer,
|
|
||||||
size_t encrypt_length,
|
|
||||||
const std::vector<uint8_t>& iv,
|
|
||||||
size_t block_offset,
|
|
||||||
void* decrypt_buffer,
|
|
||||||
size_t decrypt_buffer_offset,
|
|
||||||
bool is_video);
|
|
||||||
|
|
||||||
bool GetRandom(uint8_t* random_data, size_t data_length);
|
bool GetRandom(uint8_t* random_data, size_t data_length);
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ enum CdmResponseType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define CORE_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
#define CORE_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||||
TypeName(const TypeName&); \
|
TypeName(const TypeName&); \
|
||||||
void operator=(const TypeName&)
|
void operator=(const TypeName&)
|
||||||
|
|
||||||
enum CdmEventType {
|
enum CdmEventType {
|
||||||
@@ -55,6 +55,50 @@ enum CdmLicenseType {
|
|||||||
kLicenseTypeRelease
|
kLicenseTypeRelease
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CdmDecryptionParameters {
|
||||||
|
bool is_encrypted;
|
||||||
|
bool is_secure;
|
||||||
|
const KeyId* key_id;
|
||||||
|
const uint8_t* encrypt_buffer;
|
||||||
|
size_t encrypt_length;
|
||||||
|
const std::vector<uint8_t>* iv;
|
||||||
|
size_t block_offset;
|
||||||
|
void* decrypt_buffer;
|
||||||
|
size_t decrypt_buffer_length;
|
||||||
|
size_t decrypt_buffer_offset;
|
||||||
|
uint8_t subsample_flags;
|
||||||
|
bool is_video;
|
||||||
|
CdmDecryptionParameters()
|
||||||
|
: is_encrypted(true),
|
||||||
|
is_secure(true),
|
||||||
|
key_id(NULL),
|
||||||
|
encrypt_buffer(NULL),
|
||||||
|
encrypt_length(0),
|
||||||
|
iv(NULL),
|
||||||
|
block_offset(0),
|
||||||
|
decrypt_buffer(NULL),
|
||||||
|
decrypt_buffer_length(0),
|
||||||
|
decrypt_buffer_offset(0),
|
||||||
|
subsample_flags(0),
|
||||||
|
is_video(true) {}
|
||||||
|
CdmDecryptionParameters(const KeyId* key, const uint8_t* encrypted_buffer,
|
||||||
|
size_t encrypted_length,
|
||||||
|
const std::vector<uint8_t>* initialization_vector,
|
||||||
|
size_t offset, void* decrypted_buffer)
|
||||||
|
: is_encrypted(true),
|
||||||
|
is_secure(true),
|
||||||
|
key_id(key),
|
||||||
|
encrypt_buffer(encrypted_buffer),
|
||||||
|
encrypt_length(encrypted_length),
|
||||||
|
iv(initialization_vector),
|
||||||
|
block_offset(offset),
|
||||||
|
decrypt_buffer(decrypted_buffer),
|
||||||
|
decrypt_buffer_length(encrypted_length),
|
||||||
|
decrypt_buffer_offset(0),
|
||||||
|
subsample_flags(0),
|
||||||
|
is_video(true) {}
|
||||||
|
};
|
||||||
|
|
||||||
// forward class references
|
// forward class references
|
||||||
class KeyMessage;
|
class KeyMessage;
|
||||||
class Request;
|
class Request;
|
||||||
|
|||||||
@@ -458,26 +458,34 @@ CdmResponseType CdmEngine::ReleaseSecureStops(
|
|||||||
|
|
||||||
CdmResponseType CdmEngine::Decrypt(
|
CdmResponseType CdmEngine::Decrypt(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
bool is_encrypted,
|
const CdmDecryptionParameters& parameters) {
|
||||||
bool is_secure,
|
if (parameters.key_id == NULL) {
|
||||||
const KeyId& key_id,
|
LOGE("CdmEngine::Decrypt: no key_id");
|
||||||
const uint8_t* encrypt_buffer,
|
return KEY_ERROR;
|
||||||
size_t encrypt_length,
|
}
|
||||||
const std::vector<uint8_t>& iv,
|
|
||||||
size_t block_offset,
|
if (parameters.encrypt_buffer == NULL) {
|
||||||
void* decrypt_buffer,
|
LOGE("CdmEngine::Decrypt: no src encrypt buffer");
|
||||||
size_t decrypt_buffer_offset,
|
return KEY_ERROR;
|
||||||
bool is_video) {
|
}
|
||||||
|
|
||||||
|
if (parameters.iv == NULL) {
|
||||||
|
LOGE("CdmEngine::Decrypt: no iv");
|
||||||
|
return KEY_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.decrypt_buffer == NULL) {
|
||||||
|
LOGE("CdmEngine::Decrypt: no dest decrypt buffer");
|
||||||
|
return KEY_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||||
if (iter == sessions_.end()) {
|
if (iter == sessions_.end()) {
|
||||||
LOGW("CdmEngine::Decrypt: session_id not found = %s", session_id.c_str());
|
LOGW("CdmEngine::Decrypt: session_id not found = %s", session_id.c_str());
|
||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return iter->second->Decrypt(is_encrypted, is_secure, key_id, encrypt_buffer,
|
return iter->second->Decrypt(parameters);
|
||||||
encrypt_length, iv, block_offset,
|
|
||||||
decrypt_buffer, decrypt_buffer_offset,
|
|
||||||
is_video);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdmEngine::IsKeyValid(const KeyId& key_id) {
|
bool CdmEngine::IsKeyValid(const KeyId& key_id) {
|
||||||
|
|||||||
@@ -217,8 +217,15 @@ CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* key_info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) {
|
CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) {
|
||||||
if (crypto_session_.get() == NULL || !crypto_session_->IsOpen())
|
if (crypto_session_.get() == NULL) {
|
||||||
|
LOGW("CdmSession::QueryKeyControlInfo: Invalid crypto session");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!crypto_session_->IsOpen()) {
|
||||||
|
LOGW("CdmSession::QueryKeyControlInfo: Crypto session not open");
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << crypto_session_->oec_session_id();
|
ss << crypto_session_->oec_session_id();
|
||||||
@@ -234,28 +241,22 @@ CdmResponseType CdmSession::CancelKeyRequest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt() - Accept encrypted buffer and return decrypted data.
|
// Decrypt() - Accept encrypted buffer and return decrypted data.
|
||||||
CdmResponseType CdmSession::Decrypt(
|
CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||||
bool is_encrypted, bool is_secure, const KeyId& key_id,
|
|
||||||
const uint8_t* encrypt_buffer, size_t encrypt_length,
|
|
||||||
const std::vector<uint8_t>& iv, size_t block_offset, void* decrypt_buffer,
|
|
||||||
size_t decrypt_buffer_offset, bool is_video) {
|
|
||||||
if (crypto_session_.get() == NULL || !crypto_session_->IsOpen())
|
if (crypto_session_.get() == NULL || !crypto_session_->IsOpen())
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
|
|
||||||
// Check if key needs to be selected
|
// Check if key needs to be selected
|
||||||
if (is_encrypted) {
|
if (params.is_encrypted) {
|
||||||
if (key_id_.compare(key_id) != 0) {
|
if (key_id_.compare(*params.key_id) != 0) {
|
||||||
if (crypto_session_->SelectKey(key_id)) {
|
if (crypto_session_->SelectKey(*params.key_id)) {
|
||||||
key_id_ = key_id;
|
key_id_ = *params.key_id;
|
||||||
} else {
|
} else {
|
||||||
return NEED_KEY;
|
return NEED_KEY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return crypto_session_->Decrypt(
|
return crypto_session_->Decrypt(params);
|
||||||
is_encrypted, is_secure, encrypt_buffer, encrypt_length, iv, block_offset,
|
|
||||||
decrypt_buffer, decrypt_buffer_offset, is_video);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// License renewal
|
// License renewal
|
||||||
|
|||||||
@@ -529,39 +529,41 @@ bool CryptoSession::GenerateSignature(const std::string& message, bool use_rsa,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CryptoSession::Decrypt(
|
CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||||
bool is_encrypted, bool is_secure, const uint8_t* encrypt_buffer,
|
|
||||||
size_t encrypt_length, const std::vector<uint8_t>& iv, size_t block_offset,
|
|
||||||
void* decrypt_buffer, size_t decrypt_buffer_offset, bool is_video) {
|
|
||||||
if (!is_destination_buffer_type_valid_) {
|
if (!is_destination_buffer_type_valid_) {
|
||||||
if (!SetDestinationBufferType()) return UNKNOWN_ERROR;
|
if (!SetDestinationBufferType()) return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCrypto_DestBufferDesc buffer_descriptor;
|
OEMCrypto_DestBufferDesc buffer_descriptor;
|
||||||
buffer_descriptor.type =
|
buffer_descriptor.type =
|
||||||
is_secure ? destination_buffer_type_ : OEMCrypto_BufferType_Clear;
|
params.is_secure ? destination_buffer_type_ : OEMCrypto_BufferType_Clear;
|
||||||
|
|
||||||
switch (buffer_descriptor.type) {
|
switch (buffer_descriptor.type) {
|
||||||
case OEMCrypto_BufferType_Clear:
|
case OEMCrypto_BufferType_Clear:
|
||||||
buffer_descriptor.buffer.clear.address =
|
buffer_descriptor.buffer.clear.address =
|
||||||
static_cast<uint8_t*>(decrypt_buffer) + decrypt_buffer_offset;
|
static_cast<uint8_t*>(params.decrypt_buffer) + params.decrypt_buffer_offset;
|
||||||
buffer_descriptor.buffer.clear.max_length = encrypt_length;
|
buffer_descriptor.buffer.clear.max_length = params.decrypt_buffer_length;
|
||||||
break;
|
break;
|
||||||
case OEMCrypto_BufferType_Secure:
|
case OEMCrypto_BufferType_Secure:
|
||||||
buffer_descriptor.buffer.secure.handle = decrypt_buffer;
|
buffer_descriptor.buffer.secure.handle = params.decrypt_buffer;
|
||||||
buffer_descriptor.buffer.secure.offset = decrypt_buffer_offset;
|
buffer_descriptor.buffer.secure.offset = params.decrypt_buffer_offset;
|
||||||
buffer_descriptor.buffer.secure.max_length = encrypt_length;
|
buffer_descriptor.buffer.secure.max_length = params.decrypt_buffer_length;
|
||||||
break;
|
break;
|
||||||
case OEMCrypto_BufferType_Direct:
|
case OEMCrypto_BufferType_Direct:
|
||||||
buffer_descriptor.type = OEMCrypto_BufferType_Direct;
|
buffer_descriptor.type = OEMCrypto_BufferType_Direct;
|
||||||
buffer_descriptor.buffer.direct.is_video = is_video;
|
buffer_descriptor.buffer.direct.is_video = params.is_video;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCryptoResult sts = OEMCrypto_DecryptCTR(
|
OEMCryptoResult sts = OEMCrypto_DecryptCTR(
|
||||||
oec_session_id_, encrypt_buffer, encrypt_length, is_encrypted, &iv[0],
|
oec_session_id_,
|
||||||
block_offset, &buffer_descriptor,
|
params.encrypt_buffer,
|
||||||
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample);
|
params.encrypt_length,
|
||||||
|
params.is_encrypted,
|
||||||
|
&(*params.iv).front(),
|
||||||
|
params.block_offset,
|
||||||
|
&buffer_descriptor,
|
||||||
|
params.subsample_flags);
|
||||||
|
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ class WvContentDecryptionModule {
|
|||||||
|
|
||||||
// Provisioning related methods
|
// Provisioning related methods
|
||||||
virtual CdmResponseType GetProvisioningRequest(
|
virtual CdmResponseType GetProvisioningRequest(
|
||||||
CdmProvisioningRequest* request,
|
CdmProvisioningRequest* request, std::string* default_url);
|
||||||
std::string* default_url);
|
|
||||||
|
|
||||||
virtual CdmResponseType HandleProvisioningResponse(
|
virtual CdmResponseType HandleProvisioningResponse(
|
||||||
CdmProvisioningResponse& response);
|
CdmProvisioningResponse& response);
|
||||||
@@ -67,23 +66,20 @@ class WvContentDecryptionModule {
|
|||||||
virtual CdmResponseType ReleaseSecureStops(
|
virtual CdmResponseType ReleaseSecureStops(
|
||||||
const CdmSecureStopReleaseMessage& message);
|
const CdmSecureStopReleaseMessage& message);
|
||||||
|
|
||||||
// Accept encrypted buffer and return decrypted data.
|
// Accept encrypted buffer and decrypt data.
|
||||||
|
// Decryption parameters that need to be specified are
|
||||||
|
// is_encrypted, is_secure, key_id, encrypt_buffer, encrypt_length,
|
||||||
|
// iv, block_offset, decrypt_buffer, decrypt_buffer_length,
|
||||||
|
// decrypt_buffer_offset and subsample_flags
|
||||||
virtual CdmResponseType Decrypt(const CdmSessionId& session_id,
|
virtual CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||||
bool is_encrypted,
|
const CdmDecryptionParameters& parameters);
|
||||||
bool is_secure,
|
|
||||||
const KeyId& key_id,
|
|
||||||
const uint8_t* encrypt_buffer,
|
|
||||||
size_t encrypt_length,
|
|
||||||
const std::vector<uint8_t>& iv,
|
|
||||||
size_t block_offset,
|
|
||||||
void* decrypt_buffer,
|
|
||||||
size_t decrypt_buffer_offset);
|
|
||||||
|
|
||||||
// Event listener related methods
|
// Event listener related methods
|
||||||
virtual bool AttachEventListener(const CdmSessionId& session_id,
|
virtual bool AttachEventListener(const CdmSessionId& session_id,
|
||||||
WvCdmEventListener* listener);
|
WvCdmEventListener* listener);
|
||||||
virtual bool DetachEventListener(const CdmSessionId& session_id,
|
virtual bool DetachEventListener(const CdmSessionId& session_id,
|
||||||
WvCdmEventListener* listener);
|
WvCdmEventListener* listener);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// instance variables
|
// instance variables
|
||||||
|
|||||||
@@ -11,16 +11,13 @@
|
|||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
WvContentDecryptionModule::WvContentDecryptionModule() :
|
WvContentDecryptionModule::WvContentDecryptionModule()
|
||||||
cdm_engine_(new CdmEngine()) {
|
: cdm_engine_(new CdmEngine()) {}
|
||||||
}
|
|
||||||
|
|
||||||
WvContentDecryptionModule::~WvContentDecryptionModule() {
|
WvContentDecryptionModule::~WvContentDecryptionModule() {}
|
||||||
}
|
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::OpenSession(
|
CdmResponseType WvContentDecryptionModule::OpenSession(
|
||||||
const CdmKeySystem& key_system,
|
const CdmKeySystem& key_system, CdmSessionId* session_id) {
|
||||||
CdmSessionId* session_id) {
|
|
||||||
return cdm_engine_->OpenSession(key_system, session_id);
|
return cdm_engine_->OpenSession(key_system, session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,26 +72,22 @@ CdmResponseType WvContentDecryptionModule::CancelKeyRequest(
|
|||||||
return cdm_engine_->CancelKeyRequest(session_id);
|
return cdm_engine_->CancelKeyRequest(session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::QueryStatus(
|
CdmResponseType WvContentDecryptionModule::QueryStatus(CdmQueryMap* key_info) {
|
||||||
CdmQueryMap* key_info) {
|
|
||||||
return cdm_engine_->QueryStatus(key_info);
|
return cdm_engine_->QueryStatus(key_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::QueryKeyStatus(
|
CdmResponseType WvContentDecryptionModule::QueryKeyStatus(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id, CdmQueryMap* key_info) {
|
||||||
CdmQueryMap* key_info) {
|
|
||||||
return cdm_engine_->QueryKeyStatus(session_id, key_info);
|
return cdm_engine_->QueryKeyStatus(session_id, key_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::QueryKeyControlInfo(
|
CdmResponseType WvContentDecryptionModule::QueryKeyControlInfo(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id, CdmQueryMap* key_info) {
|
||||||
CdmQueryMap* key_info) {
|
|
||||||
return cdm_engine_->QueryKeyControlInfo(session_id, key_info);
|
return cdm_engine_->QueryKeyControlInfo(session_id, key_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
|
CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
|
||||||
CdmProvisioningRequest* request,
|
CdmProvisioningRequest* request, std::string* default_url) {
|
||||||
std::string* default_url) {
|
|
||||||
return cdm_engine_->GetProvisioningRequest(request, default_url);
|
return cdm_engine_->GetProvisioningRequest(request, default_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,30 +108,17 @@ CdmResponseType WvContentDecryptionModule::ReleaseSecureStops(
|
|||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::Decrypt(
|
CdmResponseType WvContentDecryptionModule::Decrypt(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
bool is_encrypted,
|
const CdmDecryptionParameters& parameters) {
|
||||||
bool is_secure,
|
return cdm_engine_->Decrypt(session_id, parameters);
|
||||||
const KeyId& key_id,
|
|
||||||
const uint8_t* encrypt_buffer,
|
|
||||||
size_t encrypt_length,
|
|
||||||
const std::vector<uint8_t>& iv,
|
|
||||||
size_t block_offset,
|
|
||||||
void* decrypt_buffer,
|
|
||||||
size_t decrypt_buffer_offset) {
|
|
||||||
return cdm_engine_->Decrypt(session_id, is_encrypted, is_secure, key_id,
|
|
||||||
encrypt_buffer, encrypt_length, iv,
|
|
||||||
block_offset, decrypt_buffer,
|
|
||||||
decrypt_buffer_offset, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WvContentDecryptionModule::AttachEventListener(
|
bool WvContentDecryptionModule::AttachEventListener(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id, WvCdmEventListener* listener) {
|
||||||
WvCdmEventListener* listener) {
|
|
||||||
return cdm_engine_->AttachEventListener(session_id, listener);
|
return cdm_engine_->AttachEventListener(session_id, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WvContentDecryptionModule::DetachEventListener(
|
bool WvContentDecryptionModule::DetachEventListener(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id, WvCdmEventListener* listener) {
|
||||||
WvCdmEventListener* listener) {
|
|
||||||
return cdm_engine_->DetachEventListener(session_id, listener);
|
return cdm_engine_->DetachEventListener(session_id, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "license_request.h"
|
#include "license_request.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
#include "string_conversions.h"
|
#include "string_conversions.h"
|
||||||
#include "url_request.h"
|
#include "url_request.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
@@ -28,15 +29,163 @@ int g_use_full_path = 0; // cannot use boolean in getopt_long
|
|||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
typedef struct DecryptionData {
|
// TODO(rfrias): refactor to print out the decryption test names
|
||||||
|
struct SubSampleInfo {
|
||||||
|
bool retrieve_key;
|
||||||
|
size_t num_of_subsamples;
|
||||||
bool is_encrypted;
|
bool is_encrypted;
|
||||||
bool is_secure;
|
bool is_secure;
|
||||||
wvcdm::KeyId key_id;
|
wvcdm::KeyId key_id;
|
||||||
std::vector<uint8_t> encrypt_data;
|
std::vector<uint8_t> encrypt_data;
|
||||||
|
std::vector<uint8_t> decrypt_data;
|
||||||
std::vector<uint8_t> iv;
|
std::vector<uint8_t> iv;
|
||||||
size_t block_offset;
|
size_t block_offset;
|
||||||
std::vector<uint8_t> decrypt_data;
|
};
|
||||||
} DecryptionData;
|
|
||||||
|
SubSampleInfo clear_sub_sample = {
|
||||||
|
true, 1, false, false, wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
||||||
|
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
||||||
|
"7bc083ccbb83e6d9c03794ee97f50081221a8e5eb123f6dfa895e7a971166483"
|
||||||
|
"cdadd61cd8d0f859501e750e9d356d57252ecd9f7388459f5470de9d92198c44"
|
||||||
|
"0b520055b3b9a1c6b2c9d21e78dce99622d9d031fc7dee28a6d1d6dfb81502eb"
|
||||||
|
"463c4c189555f496d9aa529b3f5522e9f46dcf70b2bfe8df47daf02b6a267f93"
|
||||||
|
"f80d871786eb4bd7f08f9c52079c034a9534d885ba4c00cbe2234cfbb5205a56"
|
||||||
|
"41dd760f83d0f09f27881ad490efa8b99b7ab24b34311a2e8416b1a80d736ad7"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
||||||
|
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
||||||
|
"7bc083ccbb83e6d9c03794ee97f50081221a8e5eb123f6dfa895e7a971166483"
|
||||||
|
"cdadd61cd8d0f859501e750e9d356d57252ecd9f7388459f5470de9d92198c44"
|
||||||
|
"0b520055b3b9a1c6b2c9d21e78dce99622d9d031fc7dee28a6d1d6dfb81502eb"
|
||||||
|
"463c4c189555f496d9aa529b3f5522e9f46dcf70b2bfe8df47daf02b6a267f93"
|
||||||
|
"f80d871786eb4bd7f08f9c52079c034a9534d885ba4c00cbe2234cfbb5205a56"
|
||||||
|
"41dd760f83d0f09f27881ad490efa8b99b7ab24b34311a2e8416b1a80d736ad7"),
|
||||||
|
wvcdm::a2b_hex("50a6c61c3f7c2b37e72b0c047000dd4a"), 0};
|
||||||
|
|
||||||
|
SubSampleInfo clear_sub_sample_no_key = {
|
||||||
|
false, 1, false, false, wvcdm::a2bs_hex("77777777777777777777777777777777"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
||||||
|
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
||||||
|
"7bc083ccbb83e6d9c03794ee97f50081221a8e5eb123f6dfa895e7a971166483"
|
||||||
|
"cdadd61cd8d0f859501e750e9d356d57252ecd9f7388459f5470de9d92198c44"
|
||||||
|
"0b520055b3b9a1c6b2c9d21e78dce99622d9d031fc7dee28a6d1d6dfb81502eb"
|
||||||
|
"463c4c189555f496d9aa529b3f5522e9f46dcf70b2bfe8df47daf02b6a267f93"
|
||||||
|
"f80d871786eb4bd7f08f9c52079c034a9534d885ba4c00cbe2234cfbb5205a56"
|
||||||
|
"41dd760f83d0f09f27881ad490efa8b99b7ab24b34311a2e8416b1a80d736ad7"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
||||||
|
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
||||||
|
"7bc083ccbb83e6d9c03794ee97f50081221a8e5eb123f6dfa895e7a971166483"
|
||||||
|
"cdadd61cd8d0f859501e750e9d356d57252ecd9f7388459f5470de9d92198c44"
|
||||||
|
"0b520055b3b9a1c6b2c9d21e78dce99622d9d031fc7dee28a6d1d6dfb81502eb"
|
||||||
|
"463c4c189555f496d9aa529b3f5522e9f46dcf70b2bfe8df47daf02b6a267f93"
|
||||||
|
"f80d871786eb4bd7f08f9c52079c034a9534d885ba4c00cbe2234cfbb5205a56"
|
||||||
|
"41dd760f83d0f09f27881ad490efa8b99b7ab24b34311a2e8416b1a80d736ad7"),
|
||||||
|
wvcdm::a2b_hex("50a6c61c3f7c2b37e72b0c047000dd4a"), 0};
|
||||||
|
|
||||||
|
SubSampleInfo single_encrypted_sub_sample = {
|
||||||
|
// key 1, encrypted, 256b
|
||||||
|
true, 1, true, false, wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"3b2cbde084973539329bd5656da22d20396249bf4a18a51c38c4743360cc9fea"
|
||||||
|
"a1c78d53de1bd7e14dc5d256fd20a57178a98b83804258c239acd7aa38f2d7d2"
|
||||||
|
"eca614965b3d22049e19e236fc1800e60965d8b36415677bf2f843d50a6943c4"
|
||||||
|
"683c07c114a32f5e5fbc9939c483c3a1b2ecd3d82b554d649798866191724283"
|
||||||
|
"f0ab082eba2da79aaca5c4eaf186f9ee9a0c568f621f705a578f30e4e2ef7b96"
|
||||||
|
"5e14cc046ce6dbf272ee5558b098f332333e95fc879dea6c29bf34acdb649650"
|
||||||
|
"f08201b9e649960f2493fd7677cc3abf5ae70e5445845c947ba544456b431646"
|
||||||
|
"d95a133bff5f57614dda5e4446cd8837901d074149dadf4b775b5b07bb88ca20"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"5a36c0b633b58faf22156d78fdfb608e54a8095788b2b0463ef78d030b4abf82"
|
||||||
|
"eff34b8d9b7b6352e7d72de991b599662aa475da355033620152e2356ebfadee"
|
||||||
|
"06172be9e1058fa177e223b9fdd191380cff53c3ea810c6fd852a1df4967b799"
|
||||||
|
"415179a2276ec388ef763bab89605b9c6952c28dc8d6bf86b03fabbb46b392a3"
|
||||||
|
"1dad15be602eeeeabb45070b3e25d6bb0217073b1fc44c9fe848594121fd6a91"
|
||||||
|
"304d605e21f69615e1b57db18312b6b948725724b74e91d8aea7371e99532469"
|
||||||
|
"1b358bdee873f1936b63efe83d190a53c2d21754d302d63ff285174023473755"
|
||||||
|
"58b938c2e3ca4c2ce48942da97f9e45797f2c074ac6004734e93784a48af6160"),
|
||||||
|
wvcdm::a2b_hex("4cca615fc013102892f91efee936639b"), 0};
|
||||||
|
|
||||||
|
SubSampleInfo switch_key_encrypted_sub_sample[2] = {
|
||||||
|
// block 0, key 1, encrypted, 256b
|
||||||
|
{true, 2, true, false, wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"3b2cbde084973539329bd5656da22d20396249bf4a18a51c38c4743360cc9fea"
|
||||||
|
"a1c78d53de1bd7e14dc5d256fd20a57178a98b83804258c239acd7aa38f2d7d2"
|
||||||
|
"eca614965b3d22049e19e236fc1800e60965d8b36415677bf2f843d50a6943c4"
|
||||||
|
"683c07c114a32f5e5fbc9939c483c3a1b2ecd3d82b554d649798866191724283"
|
||||||
|
"f0ab082eba2da79aaca5c4eaf186f9ee9a0c568f621f705a578f30e4e2ef7b96"
|
||||||
|
"5e14cc046ce6dbf272ee5558b098f332333e95fc879dea6c29bf34acdb649650"
|
||||||
|
"f08201b9e649960f2493fd7677cc3abf5ae70e5445845c947ba544456b431646"
|
||||||
|
"d95a133bff5f57614dda5e4446cd8837901d074149dadf4b775b5b07bb88ca20"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"5a36c0b633b58faf22156d78fdfb608e54a8095788b2b0463ef78d030b4abf82"
|
||||||
|
"eff34b8d9b7b6352e7d72de991b599662aa475da355033620152e2356ebfadee"
|
||||||
|
"06172be9e1058fa177e223b9fdd191380cff53c3ea810c6fd852a1df4967b799"
|
||||||
|
"415179a2276ec388ef763bab89605b9c6952c28dc8d6bf86b03fabbb46b392a3"
|
||||||
|
"1dad15be602eeeeabb45070b3e25d6bb0217073b1fc44c9fe848594121fd6a91"
|
||||||
|
"304d605e21f69615e1b57db18312b6b948725724b74e91d8aea7371e99532469"
|
||||||
|
"1b358bdee873f1936b63efe83d190a53c2d21754d302d63ff285174023473755"
|
||||||
|
"58b938c2e3ca4c2ce48942da97f9e45797f2c074ac6004734e93784a48af6160"),
|
||||||
|
wvcdm::a2b_hex("4cca615fc013102892f91efee936639b"), 0},
|
||||||
|
// block 1, key 3, encrypted, 256b
|
||||||
|
{true, 2, true, false, wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"337f294addb4c16d1015fd839e80314472432eda503bd0529422318bec7d2b34"
|
||||||
|
"2b28d24b2c0bf999fd31711901a2b90e03373cb9553ffd4b2e6e655b80a39fe8"
|
||||||
|
"61718220948f0031a37fe277f943409d09c83ff1c19fe8d601f5b4d139821750"
|
||||||
|
"47170006db5f38cb84706a9beeaa455fca3b17d8de90c143eb36aaaac3f4670a"
|
||||||
|
"7194064f4d59996c95992a3e6a848d4da8adddae3ad03c8d28110fda3e5c1d0a"
|
||||||
|
"35d175c816481275a02d2da96c7fc313864ae076f03887309cdf00ca856bad28"
|
||||||
|
"2146141964b7f7972e9b253b1fbed6d74ffedcfc51bb91fa78a602479b0b757f"
|
||||||
|
"53a16cca15c381a4eab3034ee38e12280982d575fe3de23dd65cf8ba240daa88"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"c397c1c9bc6782cd859e92f7158e3ff2a54ee984869582b942b400c22ebb6843"
|
||||||
|
"7c50f999f73831fa12040f6aab607f57280189ff1db1ab1d0046ffaa55ce1790"
|
||||||
|
"3baf0f9c983351b2ff15cc4f61f0f8db6922804e74a207e1e5baaeca67b427c7"
|
||||||
|
"2dd7883ee8232041a9c4e56ccfb8bdc3016602c73fa8944e734ee34c41cf1a17"
|
||||||
|
"b009b404fd924d23dfee1f494b5e374c9e87c2910de36826044bff89939a70d2"
|
||||||
|
"47ff1a8a0baa7643026b8d9442fda69dde6802816ddd4b6e3b18f0a95e788d6d"
|
||||||
|
"166ed7435ef663ef019b4438d3e203734eb95d68758e028f29cd623f35cde4bd"
|
||||||
|
"edfea33ade378a92a356020bcf3fbba01c9ab16ad448ce6ebe708f768c6676a7"),
|
||||||
|
wvcdm::a2b_hex("6d4ee851e563b951119cd33c52aadbf5"), 0}};
|
||||||
|
|
||||||
|
SubSampleInfo partial_single_encrypted_sub_sample = {
|
||||||
|
// key 3, encrypted, 125b, offset 0
|
||||||
|
true, 1, true, false, wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"337f294addb4c16d1015fd839e80314472432eda503bd0529422318bec7d2b34"
|
||||||
|
"2b28d24b2c0bf999fd31711901a2b90e03373cb9553ffd4b2e6e655b80a39fe8"
|
||||||
|
"61718220948f0031a37fe277f943409d09c83ff1c19fe8d601f5b4d139821750"
|
||||||
|
"47170006db5f38cb84706a9beeaa455fca3b17d8de90c143eb36aaaac3"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"c397c1c9bc6782cd859e92f7158e3ff2a54ee984869582b942b400c22ebb6843"
|
||||||
|
"7c50f999f73831fa12040f6aab607f57280189ff1db1ab1d0046ffaa55ce1790"
|
||||||
|
"3baf0f9c983351b2ff15cc4f61f0f8db6922804e74a207e1e5baaeca67b427c7"
|
||||||
|
"2dd7883ee8232041a9c4e56ccfb8bdc3016602c73fa8944e734ee34c41"),
|
||||||
|
wvcdm::a2b_hex("6d4ee851e563b951119cd33c52aadbf5"), 0};
|
||||||
|
|
||||||
|
SubSampleInfo partial_offset_single_encrypted_sub_sample = {
|
||||||
|
// key 3, encrypted, 123b, offset 5
|
||||||
|
true, 1, true, false, wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"97f39b919ba56f3c3a51ecdcd7318bc130f054320c74db3990f925"
|
||||||
|
"054734c03ec79ee0da68938dc4f8c2d91e46ec2342ef24f9328294a9475f7ead"
|
||||||
|
"8ad3e71db62d6328e826e4ab375f4796aa2bc8b9266551e3007fb3c253780293"
|
||||||
|
"31fbc32ed29afcb9e7152cf072712c5a22c6b52d60e381eb53eeb58d36528746"),
|
||||||
|
wvcdm::a2b_hex(
|
||||||
|
"d36911b44f470ff05d152a7bc69ea6b68aa812cd3676964acb4597"
|
||||||
|
"b518fe4b7ec0fe44469b1e4f8806922af9ac998d3e23349cea0e68f833564c15"
|
||||||
|
"e49584f94ef16b7ab6cd2d0b152430f1fb4d7644a0f591980388ac02012d3d42"
|
||||||
|
"73d6c9604517b1a622b66b8f4e8414e40b00351cc9859061bde810190c7b5df8"),
|
||||||
|
wvcdm::a2b_hex("43ba341482212c70f79d81c0f4faef8a"), 5};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace wvcdm {
|
||||||
|
|
||||||
class TestWvCdmEventListener : public WvCdmEventListener {
|
class TestWvCdmEventListener : public WvCdmEventListener {
|
||||||
public:
|
public:
|
||||||
@@ -183,6 +332,10 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
|||||||
CdmKeySetId key_set_id_;
|
CdmKeySetId key_set_id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WvCdmDecryptionTest
|
||||||
|
: public WvCdmRequestLicenseTest,
|
||||||
|
public ::testing::WithParamInterface<SubSampleInfo*> {};
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
||||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||||
std::string provisioning_server_url;
|
std::string provisioning_server_url;
|
||||||
@@ -430,294 +583,37 @@ TEST_F(WvCdmRequestLicenseTest, QueryKeyControlInfo) {
|
|||||||
decryptor_.CloseSession(session_id_);
|
decryptor_.CloseSession(session_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, ClearDecryptionTest) {
|
TEST_P(WvCdmDecryptionTest, DecryptionTest) {
|
||||||
|
SubSampleInfo* data = GetParam();
|
||||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
if (data->retrieve_key) {
|
||||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||||
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||||
|
}
|
||||||
|
|
||||||
// key 1, clear, 256b
|
for (size_t i = 0; i < data->num_of_subsamples; i++) {
|
||||||
DecryptionData data;
|
std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size());
|
||||||
data.is_encrypted = false;
|
CdmDecryptionParameters decryption_parameters(
|
||||||
data.is_secure = false;
|
&(data + i)->key_id, &(data + i)->encrypt_data.front(),
|
||||||
data.key_id = wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E");
|
(data + i)->encrypt_data.size(), &(data + i)->iv,
|
||||||
data.encrypt_data = wvcdm::a2b_hex(
|
(data + i)->block_offset, &decrypt_buffer[0]);
|
||||||
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
decryption_parameters.is_encrypted = (data + i)->is_encrypted;
|
||||||
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
decryption_parameters.is_secure = (data + i)->is_secure;
|
||||||
"7bc083ccbb83e6d9c03794ee97f50081221a8e5eb123f6dfa895e7a971166483"
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, decryption_parameters));
|
||||||
"cdadd61cd8d0f859501e750e9d356d57252ecd9f7388459f5470de9d92198c44"
|
|
||||||
"0b520055b3b9a1c6b2c9d21e78dce99622d9d031fc7dee28a6d1d6dfb81502eb"
|
|
||||||
"463c4c189555f496d9aa529b3f5522e9f46dcf70b2bfe8df47daf02b6a267f93"
|
|
||||||
"f80d871786eb4bd7f08f9c52079c034a9534d885ba4c00cbe2234cfbb5205a56"
|
|
||||||
"41dd760f83d0f09f27881ad490efa8b99b7ab24b34311a2e8416b1a80d736ad7");
|
|
||||||
data.iv = wvcdm::a2b_hex("50a6c61c3f7c2b37e72b0c047000dd4a");
|
|
||||||
data.block_offset = 0;
|
|
||||||
data.decrypt_data = wvcdm::a2b_hex(
|
|
||||||
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
|
||||||
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
|
||||||
"7bc083ccbb83e6d9c03794ee97f50081221a8e5eb123f6dfa895e7a971166483"
|
|
||||||
"cdadd61cd8d0f859501e750e9d356d57252ecd9f7388459f5470de9d92198c44"
|
|
||||||
"0b520055b3b9a1c6b2c9d21e78dce99622d9d031fc7dee28a6d1d6dfb81502eb"
|
|
||||||
"463c4c189555f496d9aa529b3f5522e9f46dcf70b2bfe8df47daf02b6a267f93"
|
|
||||||
"f80d871786eb4bd7f08f9c52079c034a9534d885ba4c00cbe2234cfbb5205a56"
|
|
||||||
"41dd760f83d0f09f27881ad490efa8b99b7ab24b34311a2e8416b1a80d736ad7");
|
|
||||||
|
|
||||||
std::vector<uint8_t> decrypt_buffer;
|
EXPECT_TRUE(std::equal((data + i)->decrypt_data.begin(),
|
||||||
size_t encrypt_length = data.encrypt_data.size();
|
(data + i)->decrypt_data.end(),
|
||||||
decrypt_buffer.resize(encrypt_length);
|
decrypt_buffer.begin()));
|
||||||
|
|
||||||
EXPECT_EQ(NO_ERROR,
|
|
||||||
decryptor_.Decrypt(session_id_, data.is_encrypted, data.is_secure,
|
|
||||||
data.key_id, &data.encrypt_data.front(),
|
|
||||||
encrypt_length, data.iv, data.block_offset,
|
|
||||||
&decrypt_buffer.front(), 0));
|
|
||||||
|
|
||||||
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
|
||||||
decrypt_buffer.begin()));
|
|
||||||
decryptor_.CloseSession(session_id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, ClearDecryptionNoKeyTest) {
|
|
||||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
|
||||||
|
|
||||||
// key 1, clear, 256b
|
|
||||||
DecryptionData data;
|
|
||||||
data.is_encrypted = false;
|
|
||||||
data.is_secure = false;
|
|
||||||
data.key_id = wvcdm::a2bs_hex("77777777777777777777777777777777");
|
|
||||||
data.encrypt_data = wvcdm::a2b_hex(
|
|
||||||
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
|
||||||
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
|
||||||
"7bc083ccbb83e6d9c03794ee97f50081221a8e5eb123f6dfa895e7a971166483"
|
|
||||||
"cdadd61cd8d0f859501e750e9d356d57252ecd9f7388459f5470de9d92198c44"
|
|
||||||
"0b520055b3b9a1c6b2c9d21e78dce99622d9d031fc7dee28a6d1d6dfb81502eb"
|
|
||||||
"463c4c189555f496d9aa529b3f5522e9f46dcf70b2bfe8df47daf02b6a267f93"
|
|
||||||
"f80d871786eb4bd7f08f9c52079c034a9534d885ba4c00cbe2234cfbb5205a56"
|
|
||||||
"41dd760f83d0f09f27881ad490efa8b99b7ab24b34311a2e8416b1a80d736ad7");
|
|
||||||
data.iv = wvcdm::a2b_hex("50a6c61c3f7c2b37e72b0c047000dd4a");
|
|
||||||
data.block_offset = 0;
|
|
||||||
data.decrypt_data = wvcdm::a2b_hex(
|
|
||||||
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
|
||||||
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
|
||||||
"7bc083ccbb83e6d9c03794ee97f50081221a8e5eb123f6dfa895e7a971166483"
|
|
||||||
"cdadd61cd8d0f859501e750e9d356d57252ecd9f7388459f5470de9d92198c44"
|
|
||||||
"0b520055b3b9a1c6b2c9d21e78dce99622d9d031fc7dee28a6d1d6dfb81502eb"
|
|
||||||
"463c4c189555f496d9aa529b3f5522e9f46dcf70b2bfe8df47daf02b6a267f93"
|
|
||||||
"f80d871786eb4bd7f08f9c52079c034a9534d885ba4c00cbe2234cfbb5205a56"
|
|
||||||
"41dd760f83d0f09f27881ad490efa8b99b7ab24b34311a2e8416b1a80d736ad7");
|
|
||||||
|
|
||||||
std::vector<uint8_t> decrypt_buffer;
|
|
||||||
size_t encrypt_length = data.encrypt_data.size();
|
|
||||||
decrypt_buffer.resize(encrypt_length);
|
|
||||||
|
|
||||||
EXPECT_EQ(NO_ERROR,
|
|
||||||
decryptor_.Decrypt(session_id_, data.is_encrypted, data.is_secure,
|
|
||||||
data.key_id, &data.encrypt_data.front(),
|
|
||||||
encrypt_length, data.iv, data.block_offset,
|
|
||||||
&decrypt_buffer.front(), 0));
|
|
||||||
|
|
||||||
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
|
||||||
decrypt_buffer.begin()));
|
|
||||||
decryptor_.CloseSession(session_id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, DecryptionTest) {
|
|
||||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
|
||||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
|
||||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
|
||||||
|
|
||||||
// key 1, encrypted, 256b
|
|
||||||
DecryptionData data;
|
|
||||||
data.is_encrypted = true;
|
|
||||||
data.is_secure = false;
|
|
||||||
data.key_id = wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E");
|
|
||||||
data.encrypt_data = wvcdm::a2b_hex(
|
|
||||||
"3b2cbde084973539329bd5656da22d20396249bf4a18a51c38c4743360cc9fea"
|
|
||||||
"a1c78d53de1bd7e14dc5d256fd20a57178a98b83804258c239acd7aa38f2d7d2"
|
|
||||||
"eca614965b3d22049e19e236fc1800e60965d8b36415677bf2f843d50a6943c4"
|
|
||||||
"683c07c114a32f5e5fbc9939c483c3a1b2ecd3d82b554d649798866191724283"
|
|
||||||
"f0ab082eba2da79aaca5c4eaf186f9ee9a0c568f621f705a578f30e4e2ef7b96"
|
|
||||||
"5e14cc046ce6dbf272ee5558b098f332333e95fc879dea6c29bf34acdb649650"
|
|
||||||
"f08201b9e649960f2493fd7677cc3abf5ae70e5445845c947ba544456b431646"
|
|
||||||
"d95a133bff5f57614dda5e4446cd8837901d074149dadf4b775b5b07bb88ca20");
|
|
||||||
data.iv = wvcdm::a2b_hex("4cca615fc013102892f91efee936639b");
|
|
||||||
data.block_offset = 0;
|
|
||||||
data.decrypt_data = wvcdm::a2b_hex(
|
|
||||||
"5a36c0b633b58faf22156d78fdfb608e54a8095788b2b0463ef78d030b4abf82"
|
|
||||||
"eff34b8d9b7b6352e7d72de991b599662aa475da355033620152e2356ebfadee"
|
|
||||||
"06172be9e1058fa177e223b9fdd191380cff53c3ea810c6fd852a1df4967b799"
|
|
||||||
"415179a2276ec388ef763bab89605b9c6952c28dc8d6bf86b03fabbb46b392a3"
|
|
||||||
"1dad15be602eeeeabb45070b3e25d6bb0217073b1fc44c9fe848594121fd6a91"
|
|
||||||
"304d605e21f69615e1b57db18312b6b948725724b74e91d8aea7371e99532469"
|
|
||||||
"1b358bdee873f1936b63efe83d190a53c2d21754d302d63ff285174023473755"
|
|
||||||
"58b938c2e3ca4c2ce48942da97f9e45797f2c074ac6004734e93784a48af6160");
|
|
||||||
|
|
||||||
std::vector<uint8_t> decrypt_buffer;
|
|
||||||
size_t encrypt_length = data.encrypt_data.size();
|
|
||||||
decrypt_buffer.resize(encrypt_length);
|
|
||||||
|
|
||||||
EXPECT_EQ(NO_ERROR,
|
|
||||||
decryptor_.Decrypt(session_id_, data.is_encrypted, data.is_secure,
|
|
||||||
data.key_id, &data.encrypt_data.front(),
|
|
||||||
encrypt_length, data.iv, data.block_offset,
|
|
||||||
&decrypt_buffer.front(), 0));
|
|
||||||
|
|
||||||
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
|
||||||
decrypt_buffer.begin()));
|
|
||||||
decryptor_.CloseSession(session_id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, SwitchKeyDecryptionTest) {
|
|
||||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
|
||||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
|
||||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
|
||||||
|
|
||||||
uint8_t data_blocks = 2;
|
|
||||||
DecryptionData data[data_blocks];
|
|
||||||
|
|
||||||
// block 0, key 1, encrypted, 256b
|
|
||||||
data[0].is_encrypted = true;
|
|
||||||
data[0].is_secure = false;
|
|
||||||
data[0].key_id = wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E");
|
|
||||||
data[0].encrypt_data = wvcdm::a2b_hex(
|
|
||||||
"3b2cbde084973539329bd5656da22d20396249bf4a18a51c38c4743360cc9fea"
|
|
||||||
"a1c78d53de1bd7e14dc5d256fd20a57178a98b83804258c239acd7aa38f2d7d2"
|
|
||||||
"eca614965b3d22049e19e236fc1800e60965d8b36415677bf2f843d50a6943c4"
|
|
||||||
"683c07c114a32f5e5fbc9939c483c3a1b2ecd3d82b554d649798866191724283"
|
|
||||||
"f0ab082eba2da79aaca5c4eaf186f9ee9a0c568f621f705a578f30e4e2ef7b96"
|
|
||||||
"5e14cc046ce6dbf272ee5558b098f332333e95fc879dea6c29bf34acdb649650"
|
|
||||||
"f08201b9e649960f2493fd7677cc3abf5ae70e5445845c947ba544456b431646"
|
|
||||||
"d95a133bff5f57614dda5e4446cd8837901d074149dadf4b775b5b07bb88ca20");
|
|
||||||
data[0].iv = wvcdm::a2b_hex("4cca615fc013102892f91efee936639b");
|
|
||||||
data[0].block_offset = 0;
|
|
||||||
data[0].decrypt_data = wvcdm::a2b_hex(
|
|
||||||
"5a36c0b633b58faf22156d78fdfb608e54a8095788b2b0463ef78d030b4abf82"
|
|
||||||
"eff34b8d9b7b6352e7d72de991b599662aa475da355033620152e2356ebfadee"
|
|
||||||
"06172be9e1058fa177e223b9fdd191380cff53c3ea810c6fd852a1df4967b799"
|
|
||||||
"415179a2276ec388ef763bab89605b9c6952c28dc8d6bf86b03fabbb46b392a3"
|
|
||||||
"1dad15be602eeeeabb45070b3e25d6bb0217073b1fc44c9fe848594121fd6a91"
|
|
||||||
"304d605e21f69615e1b57db18312b6b948725724b74e91d8aea7371e99532469"
|
|
||||||
"1b358bdee873f1936b63efe83d190a53c2d21754d302d63ff285174023473755"
|
|
||||||
"58b938c2e3ca4c2ce48942da97f9e45797f2c074ac6004734e93784a48af6160");
|
|
||||||
|
|
||||||
// block 1, key 3, encrypted, 256b
|
|
||||||
data[1].is_encrypted = true;
|
|
||||||
data[1].is_secure = false;
|
|
||||||
data[1].key_id = wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62");
|
|
||||||
data[1].encrypt_data = wvcdm::a2b_hex(
|
|
||||||
"337f294addb4c16d1015fd839e80314472432eda503bd0529422318bec7d2b34"
|
|
||||||
"2b28d24b2c0bf999fd31711901a2b90e03373cb9553ffd4b2e6e655b80a39fe8"
|
|
||||||
"61718220948f0031a37fe277f943409d09c83ff1c19fe8d601f5b4d139821750"
|
|
||||||
"47170006db5f38cb84706a9beeaa455fca3b17d8de90c143eb36aaaac3f4670a"
|
|
||||||
"7194064f4d59996c95992a3e6a848d4da8adddae3ad03c8d28110fda3e5c1d0a"
|
|
||||||
"35d175c816481275a02d2da96c7fc313864ae076f03887309cdf00ca856bad28"
|
|
||||||
"2146141964b7f7972e9b253b1fbed6d74ffedcfc51bb91fa78a602479b0b757f"
|
|
||||||
"53a16cca15c381a4eab3034ee38e12280982d575fe3de23dd65cf8ba240daa88");
|
|
||||||
data[1].iv = wvcdm::a2b_hex("6d4ee851e563b951119cd33c52aadbf5");
|
|
||||||
data[1].block_offset = 0;
|
|
||||||
data[1].decrypt_data = wvcdm::a2b_hex(
|
|
||||||
"c397c1c9bc6782cd859e92f7158e3ff2a54ee984869582b942b400c22ebb6843"
|
|
||||||
"7c50f999f73831fa12040f6aab607f57280189ff1db1ab1d0046ffaa55ce1790"
|
|
||||||
"3baf0f9c983351b2ff15cc4f61f0f8db6922804e74a207e1e5baaeca67b427c7"
|
|
||||||
"2dd7883ee8232041a9c4e56ccfb8bdc3016602c73fa8944e734ee34c41cf1a17"
|
|
||||||
"b009b404fd924d23dfee1f494b5e374c9e87c2910de36826044bff89939a70d2"
|
|
||||||
"47ff1a8a0baa7643026b8d9442fda69dde6802816ddd4b6e3b18f0a95e788d6d"
|
|
||||||
"166ed7435ef663ef019b4438d3e203734eb95d68758e028f29cd623f35cde4bd"
|
|
||||||
"edfea33ade378a92a356020bcf3fbba01c9ab16ad448ce6ebe708f768c6676a7");
|
|
||||||
std::vector<uint8_t> decrypt_buffer;
|
|
||||||
|
|
||||||
for (int i = 0; i < data_blocks; ++i) {
|
|
||||||
size_t encrypt_length = data[i].encrypt_data.size();
|
|
||||||
decrypt_buffer.resize(encrypt_length);
|
|
||||||
|
|
||||||
EXPECT_EQ(
|
|
||||||
NO_ERROR,
|
|
||||||
decryptor_.Decrypt(session_id_, data[i].is_encrypted, data[i].is_secure,
|
|
||||||
data[i].key_id, &data[i].encrypt_data.front(),
|
|
||||||
encrypt_length, data[i].iv, data[i].block_offset,
|
|
||||||
&decrypt_buffer.front(), 0));
|
|
||||||
|
|
||||||
EXPECT_TRUE(std::equal(data[i].decrypt_data.begin(),
|
|
||||||
data[i].decrypt_data.end(), decrypt_buffer.begin()));
|
|
||||||
}
|
}
|
||||||
decryptor_.CloseSession(session_id_);
|
decryptor_.CloseSession(session_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, PartialBlockDecryptionTest) {
|
INSTANTIATE_TEST_CASE_P(
|
||||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
Cdm, WvCdmDecryptionTest,
|
||||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
::testing::Values(&clear_sub_sample, &clear_sub_sample_no_key,
|
||||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
&single_encrypted_sub_sample,
|
||||||
|
&switch_key_encrypted_sub_sample[0],
|
||||||
// key 3, encrypted, 125b, offset 0
|
&partial_single_encrypted_sub_sample));
|
||||||
DecryptionData data;
|
|
||||||
data.is_encrypted = true;
|
|
||||||
data.is_secure = false;
|
|
||||||
data.key_id = wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62");
|
|
||||||
data.encrypt_data = wvcdm::a2b_hex(
|
|
||||||
"337f294addb4c16d1015fd839e80314472432eda503bd0529422318bec7d2b34"
|
|
||||||
"2b28d24b2c0bf999fd31711901a2b90e03373cb9553ffd4b2e6e655b80a39fe8"
|
|
||||||
"61718220948f0031a37fe277f943409d09c83ff1c19fe8d601f5b4d139821750"
|
|
||||||
"47170006db5f38cb84706a9beeaa455fca3b17d8de90c143eb36aaaac3");
|
|
||||||
data.iv = wvcdm::a2b_hex("6d4ee851e563b951119cd33c52aadbf5");
|
|
||||||
data.block_offset = 0;
|
|
||||||
data.decrypt_data = wvcdm::a2b_hex(
|
|
||||||
"c397c1c9bc6782cd859e92f7158e3ff2a54ee984869582b942b400c22ebb6843"
|
|
||||||
"7c50f999f73831fa12040f6aab607f57280189ff1db1ab1d0046ffaa55ce1790"
|
|
||||||
"3baf0f9c983351b2ff15cc4f61f0f8db6922804e74a207e1e5baaeca67b427c7"
|
|
||||||
"2dd7883ee8232041a9c4e56ccfb8bdc3016602c73fa8944e734ee34c41");
|
|
||||||
|
|
||||||
std::vector<uint8_t> decrypt_buffer;
|
|
||||||
size_t encrypt_length = data.encrypt_data.size();
|
|
||||||
decrypt_buffer.resize(encrypt_length);
|
|
||||||
|
|
||||||
EXPECT_EQ(NO_ERROR,
|
|
||||||
decryptor_.Decrypt(session_id_, data.is_encrypted, data.is_secure,
|
|
||||||
data.key_id, &data.encrypt_data.front(),
|
|
||||||
encrypt_length, data.iv, data.block_offset,
|
|
||||||
&decrypt_buffer.front(), 0));
|
|
||||||
|
|
||||||
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
|
||||||
decrypt_buffer.begin()));
|
|
||||||
decryptor_.CloseSession(session_id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, PartialBlockWithOffsetDecryptionTest) {
|
|
||||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
|
||||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
|
||||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
|
||||||
|
|
||||||
// key 3, encrypted, 123b, offset 5
|
|
||||||
DecryptionData data;
|
|
||||||
data.is_encrypted = true;
|
|
||||||
data.is_secure = false;
|
|
||||||
data.key_id = wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62");
|
|
||||||
data.encrypt_data = wvcdm::a2b_hex(
|
|
||||||
"97f39b919ba56f3c3a51ecdcd7318bc130f054320c74db3990f925"
|
|
||||||
"054734c03ec79ee0da68938dc4f8c2d91e46ec2342ef24f9328294a9475f7ead"
|
|
||||||
"8ad3e71db62d6328e826e4ab375f4796aa2bc8b9266551e3007fb3c253780293"
|
|
||||||
"31fbc32ed29afcb9e7152cf072712c5a22c6b52d60e381eb53eeb58d36528746");
|
|
||||||
data.iv = wvcdm::a2b_hex("43ba341482212c70f79d81c0f4faef8a");
|
|
||||||
data.block_offset = 5;
|
|
||||||
data.decrypt_data = wvcdm::a2b_hex(
|
|
||||||
"d36911b44f470ff05d152a7bc69ea6b68aa812cd3676964acb4597"
|
|
||||||
"b518fe4b7ec0fe44469b1e4f8806922af9ac998d3e23349cea0e68f833564c15"
|
|
||||||
"e49584f94ef16b7ab6cd2d0b152430f1fb4d7644a0f591980388ac02012d3d42"
|
|
||||||
"73d6c9604517b1a622b66b8f4e8414e40b00351cc9859061bde810190c7b5df8");
|
|
||||||
|
|
||||||
std::vector<uint8_t> decrypt_buffer;
|
|
||||||
size_t encrypt_length = data.encrypt_data.size();
|
|
||||||
decrypt_buffer.resize(encrypt_length);
|
|
||||||
|
|
||||||
EXPECT_EQ(NO_ERROR,
|
|
||||||
decryptor_.Decrypt(session_id_, data.is_encrypted, data.is_secure,
|
|
||||||
data.key_id, &data.encrypt_data.front(),
|
|
||||||
encrypt_length, data.iv, data.block_offset,
|
|
||||||
&decrypt_buffer.front(), 0));
|
|
||||||
|
|
||||||
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
|
||||||
decrypt_buffer.begin()));
|
|
||||||
|
|
||||||
decryptor_.CloseSession(session_id_);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, DISABLED_OfflineLicenseDecryptionTest) {
|
TEST_F(WvCdmRequestLicenseTest, DISABLED_OfflineLicenseDecryptionTest) {
|
||||||
decryptor_.OpenSession(g_key_system, &session_id_);
|
decryptor_.OpenSession(g_key_system, &session_id_);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ LOCAL_C_INCLUDES := \
|
|||||||
vendor/widevine/libwvdrmengine/cdm/include \
|
vendor/widevine/libwvdrmengine/cdm/include \
|
||||||
vendor/widevine/libwvdrmengine/include \
|
vendor/widevine/libwvdrmengine/include \
|
||||||
vendor/widevine/libwvdrmengine/mediacrypto/include \
|
vendor/widevine/libwvdrmengine/mediacrypto/include \
|
||||||
|
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||||
|
|
||||||
LOCAL_MODULE := libwvdrmcryptoplugin
|
LOCAL_MODULE := libwvdrmcryptoplugin
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "mapErrors-inl.h"
|
#include "mapErrors-inl.h"
|
||||||
#include "media/stagefright/MediaErrors.h"
|
#include "media/stagefright/MediaErrors.h"
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
#include "openssl/sha.h"
|
#include "openssl/sha.h"
|
||||||
#include "utils/Errors.h"
|
#include "utils/Errors.h"
|
||||||
#include "utils/String8.h"
|
#include "utils/String8.h"
|
||||||
@@ -83,6 +84,22 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE],
|
|||||||
const uint8_t* const source = static_cast<const uint8_t*>(srcPtr);
|
const uint8_t* const source = static_cast<const uint8_t*>(srcPtr);
|
||||||
uint8_t* const dest = static_cast<uint8_t*>(dstPtr);
|
uint8_t* const dest = static_cast<uint8_t*>(dstPtr);
|
||||||
|
|
||||||
|
// Calculate the output buffer size
|
||||||
|
size_t destSize = 0;
|
||||||
|
for (size_t i = 0; i < numSubSamples; i++) {
|
||||||
|
const SubSample &subSample = subSamples[i];
|
||||||
|
destSize += subSample.mNumBytesOfClearData;
|
||||||
|
destSize += subSample.mNumBytesOfEncryptedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the decrypt params that do not vary.
|
||||||
|
CdmDecryptionParameters params = CdmDecryptionParameters();
|
||||||
|
params.is_secure = secure;
|
||||||
|
params.key_id = &keyId;
|
||||||
|
params.iv = &ivVector;
|
||||||
|
params.decrypt_buffer = dest;
|
||||||
|
params.decrypt_buffer_length = destSize;
|
||||||
|
|
||||||
// Iterate through subsamples, sending them to the CDM serially.
|
// Iterate through subsamples, sending them to the CDM serially.
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
static const size_t kAESBlockSize = 16;
|
static const size_t kAESBlockSize = 16;
|
||||||
@@ -97,13 +114,40 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE],
|
|||||||
return kErrorExpectedUnencrypted;
|
return kErrorExpectedUnencrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate any flags that apply to this subsample's parts.
|
||||||
|
uint8_t clearFlags = 0;
|
||||||
|
uint8_t encryptedFlags = 0;
|
||||||
|
|
||||||
|
// If this is the first subsample…
|
||||||
|
if (i == 0) {
|
||||||
|
// …add OEMCrypto_FirstSubsample to the first part that is present.
|
||||||
|
if (subSample.mNumBytesOfClearData != 0) {
|
||||||
|
clearFlags = clearFlags | OEMCrypto_FirstSubsample;
|
||||||
|
} else {
|
||||||
|
encryptedFlags = encryptedFlags | OEMCrypto_FirstSubsample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If this is the last subsample…
|
||||||
|
if (i == numSubSamples - 1) {
|
||||||
|
// …add OEMCrypto_LastSubsample to the last part that is present
|
||||||
|
if (subSample.mNumBytesOfEncryptedData != 0) {
|
||||||
|
encryptedFlags = encryptedFlags | OEMCrypto_LastSubsample;
|
||||||
|
} else {
|
||||||
|
clearFlags = clearFlags | OEMCrypto_LastSubsample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// "Decrypt" any unencrypted data. Per the ISO-CENC standard, clear data
|
// "Decrypt" any unencrypted data. Per the ISO-CENC standard, clear data
|
||||||
// comes before encrypted data.
|
// comes before encrypted data.
|
||||||
if (subSample.mNumBytesOfClearData != 0) {
|
if (subSample.mNumBytesOfClearData != 0) {
|
||||||
CdmResponseType res = mCDM->Decrypt(mSessionId, false, secure, keyId,
|
params.is_encrypted = false;
|
||||||
source + offset,
|
params.encrypt_buffer = source + offset;
|
||||||
subSample.mNumBytesOfClearData,
|
params.encrypt_length = subSample.mNumBytesOfClearData;
|
||||||
ivVector, 0, dest, offset);
|
params.block_offset = 0;
|
||||||
|
params.decrypt_buffer_offset = offset;
|
||||||
|
params.subsample_flags = clearFlags;
|
||||||
|
|
||||||
|
CdmResponseType res = mCDM->Decrypt(mSessionId, params);
|
||||||
|
|
||||||
if (!isCdmResponseTypeSuccess(res)) {
|
if (!isCdmResponseTypeSuccess(res)) {
|
||||||
ALOGE("Decrypt error result in session %s during unencrypted block: %d",
|
ALOGE("Decrypt error result in session %s during unencrypted block: %d",
|
||||||
@@ -118,10 +162,14 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE],
|
|||||||
// Decrypt any encrypted data. Per the ISO-CENC standard, encrypted data
|
// Decrypt any encrypted data. Per the ISO-CENC standard, encrypted data
|
||||||
// comes after clear data.
|
// comes after clear data.
|
||||||
if (subSample.mNumBytesOfEncryptedData != 0) {
|
if (subSample.mNumBytesOfEncryptedData != 0) {
|
||||||
CdmResponseType res = mCDM->Decrypt(mSessionId, true, secure, keyId,
|
params.is_encrypted = true;
|
||||||
source + offset,
|
params.encrypt_buffer = source + offset;
|
||||||
subSample.mNumBytesOfEncryptedData,
|
params.encrypt_length = subSample.mNumBytesOfEncryptedData;
|
||||||
ivVector, blockOffset, dest, offset);
|
params.block_offset = blockOffset;
|
||||||
|
params.decrypt_buffer_offset = offset;
|
||||||
|
params.subsample_flags = encryptedFlags;
|
||||||
|
|
||||||
|
CdmResponseType res = mCDM->Decrypt(mSessionId, params);
|
||||||
|
|
||||||
if (!isCdmResponseTypeSuccess(res)) {
|
if (!isCdmResponseTypeSuccess(res)) {
|
||||||
ALOGE("Decrypt error result in session %s during encrypted block: %d",
|
ALOGE("Decrypt error result in session %s during encrypted block: %d",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ LOCAL_C_INCLUDES := \
|
|||||||
vendor/widevine/libwvdrmengine/cdm/core/include \
|
vendor/widevine/libwvdrmengine/cdm/core/include \
|
||||||
vendor/widevine/libwvdrmengine/cdm/include \
|
vendor/widevine/libwvdrmengine/cdm/include \
|
||||||
vendor/widevine/libwvdrmengine/mediacrypto/include \
|
vendor/widevine/libwvdrmengine/mediacrypto/include \
|
||||||
|
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||||
vendor/widevine/libwvdrmengine/test/gmock/include \
|
vendor/widevine/libwvdrmengine/test/gmock/include \
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := \
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "media/stagefright/foundation/ABase.h"
|
#include "media/stagefright/foundation/ABase.h"
|
||||||
#include "media/stagefright/foundation/AString.h"
|
#include "media/stagefright/foundation/AString.h"
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
#include "wv_cdm_types.h"
|
#include "wv_cdm_types.h"
|
||||||
#include "wv_content_decryption_module.h"
|
#include "wv_content_decryption_module.h"
|
||||||
@@ -23,10 +24,8 @@ using namespace wvdrm;
|
|||||||
|
|
||||||
class MockCDM : public WvContentDecryptionModule {
|
class MockCDM : public WvContentDecryptionModule {
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD10(Decrypt, CdmResponseType(const CdmSessionId&, bool, bool,
|
MOCK_METHOD2(Decrypt, CdmResponseType(const CdmSessionId&,
|
||||||
const KeyId&, const uint8_t*, size_t,
|
const CdmDecryptionParameters&));
|
||||||
const std::vector<uint8_t>&, size_t,
|
|
||||||
void*, size_t));
|
|
||||||
|
|
||||||
MOCK_METHOD1(QueryStatus, CdmResponseType(CdmQueryMap*));
|
MOCK_METHOD1(QueryStatus, CdmResponseType(CdmQueryMap*));
|
||||||
};
|
};
|
||||||
@@ -70,6 +69,74 @@ TEST_F(WVCryptoPluginTest, CorrectlyReportsSecureBuffers) {
|
|||||||
"WVCryptoPlugin incorrectly expects a secure audio decoder";
|
"WVCryptoPlugin incorrectly expects a secure audio decoder";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Factory for matchers that perform deep matching of values against a
|
||||||
|
// CdmDecryptionParameters struct. For use in the test AttemptsToDecrypt.
|
||||||
|
class CDPMatcherFactory {
|
||||||
|
public:
|
||||||
|
// Some values do not change over the course of the test. To avoid having
|
||||||
|
// to re-specify them at every call site, we pass them into the factory
|
||||||
|
// constructor.
|
||||||
|
CDPMatcherFactory(bool isSecure, uint8_t* keyId, void* out, size_t outLen)
|
||||||
|
: mIsSecure(isSecure), mKeyId(keyId), mOut(out), mOutLen(outLen) {}
|
||||||
|
|
||||||
|
Matcher<const CdmDecryptionParameters&> operator()(bool isEncrypted,
|
||||||
|
uint8_t* in,
|
||||||
|
size_t inLen,
|
||||||
|
uint8_t* iv,
|
||||||
|
size_t blockOffset,
|
||||||
|
size_t outOffset,
|
||||||
|
uint8_t flags) const {
|
||||||
|
return Truly(CDPMatcher(mIsSecure, mKeyId, mOut, mOutLen, isEncrypted,
|
||||||
|
in, inLen, iv, blockOffset, outOffset, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Predicate that validates that the fields of a passed-in
|
||||||
|
// CdmDecryptionParameters match the values it was given at construction
|
||||||
|
// time.
|
||||||
|
class CDPMatcher {
|
||||||
|
public:
|
||||||
|
CDPMatcher(bool isSecure, uint8_t* keyId, void* out, size_t outLen,
|
||||||
|
bool isEncrypted, uint8_t* in, size_t inLen, uint8_t* iv,
|
||||||
|
size_t blockOffset, size_t outOffset, uint8_t flags)
|
||||||
|
: mIsSecure(isSecure), mKeyId(keyId), mOut(out), mOutLen(outLen),
|
||||||
|
mIsEncrypted(isEncrypted), mIn(in), mInLen(inLen), mIv(iv),
|
||||||
|
mBlockOffset(blockOffset), mOutOffset(outOffset), mFlags(flags) {}
|
||||||
|
|
||||||
|
bool operator()(const CdmDecryptionParameters& params) const {
|
||||||
|
return params.is_secure == mIsSecure &&
|
||||||
|
Value(*params.key_id, ElementsAreArray(mKeyId, KEY_ID_SIZE)) &&
|
||||||
|
params.decrypt_buffer == mOut &&
|
||||||
|
params.decrypt_buffer_length == mOutLen &&
|
||||||
|
params.is_encrypted == mIsEncrypted &&
|
||||||
|
params.encrypt_buffer == mIn &&
|
||||||
|
params.encrypt_length == mInLen &&
|
||||||
|
Value(*params.iv, ElementsAreArray(mIv, KEY_IV_SIZE)) &&
|
||||||
|
params.block_offset == mBlockOffset &&
|
||||||
|
params.decrypt_buffer_offset == mOutOffset &&
|
||||||
|
params.subsample_flags == mFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mIsSecure;
|
||||||
|
uint8_t* mKeyId;
|
||||||
|
void* mOut;
|
||||||
|
size_t mOutLen;
|
||||||
|
bool mIsEncrypted;
|
||||||
|
uint8_t* mIn;
|
||||||
|
size_t mInLen;
|
||||||
|
uint8_t* mIv;
|
||||||
|
size_t mBlockOffset;
|
||||||
|
size_t mOutOffset;
|
||||||
|
uint8_t mFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool mIsSecure;
|
||||||
|
uint8_t* mKeyId;
|
||||||
|
void* mOut;
|
||||||
|
size_t mOutLen;
|
||||||
|
};
|
||||||
|
|
||||||
TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||||
StrictMock<MockCDM> cdm;
|
StrictMock<MockCDM> cdm;
|
||||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm);
|
WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm);
|
||||||
@@ -111,61 +178,49 @@ TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
|||||||
memcpy(iv[4], baseIv, sizeof(baseIv));
|
memcpy(iv[4], baseIv, sizeof(baseIv));
|
||||||
iv[4][15] = 7;
|
iv[4][15] = 7;
|
||||||
|
|
||||||
|
CDPMatcherFactory ParamsAre = CDPMatcherFactory(false, keyId, out, kDataSize);
|
||||||
|
|
||||||
{
|
{
|
||||||
InSequence calls;
|
InSequence calls;
|
||||||
|
|
||||||
// SubSample 0
|
// SubSample 0
|
||||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
ParamsAre(true, in, 16, iv[0], 0, 0,
|
||||||
in, 16, ElementsAreArray(iv[0], KEY_IV_SIZE),
|
OEMCrypto_FirstSubsample)))
|
||||||
0, out, 0))
|
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
// SubSample 1
|
// SubSample 1
|
||||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), false,
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
ParamsAre(false, in + 16, 16, iv[1], 0, 16, 0)))
|
||||||
in + 16, 16, ElementsAreArray(iv[1], KEY_IV_SIZE),
|
|
||||||
0, out, 16))
|
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
ParamsAre(true, in + 32, 16, iv[1], 0, 32, 0)))
|
||||||
in + 32, 16, ElementsAreArray(iv[1], KEY_IV_SIZE),
|
|
||||||
0, out, 32))
|
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
// SubSample 2
|
// SubSample 2
|
||||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
ParamsAre(true, in + 48, 8, iv[2], 0, 48, 0)))
|
||||||
in + 48, 8, ElementsAreArray(iv[2], KEY_IV_SIZE),
|
|
||||||
0, out, 48))
|
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
// SubSample 3
|
// SubSample 3
|
||||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), false,
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
ParamsAre(false, in + 56, 29, iv[2], 0, 56, 0)))
|
||||||
in + 56, 29, ElementsAreArray(iv[2], KEY_IV_SIZE),
|
|
||||||
0, out, 56))
|
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
ParamsAre(true, in + 85, 24, iv[2], 8, 85, 0)))
|
||||||
in + 85, 24, ElementsAreArray(iv[2], KEY_IV_SIZE),
|
|
||||||
8, out, 85))
|
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
// SubSample 4
|
// SubSample 4
|
||||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
ParamsAre(true, in + 109, 60, iv[3], 0, 109, 0)))
|
||||||
in + 109, 60, ElementsAreArray(iv[3], KEY_IV_SIZE),
|
|
||||||
0, out, 109))
|
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
// SubSample 5
|
// SubSample 5
|
||||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||||
false, ElementsAreArray(keyId, KEY_ID_SIZE),
|
ParamsAre(true, in + 169, 16, iv[4], 12, 169,
|
||||||
in + 169, 16, ElementsAreArray(iv[4], KEY_IV_SIZE),
|
OEMCrypto_LastSubsample)))
|
||||||
12, out, 169))
|
|
||||||
.Times(1);
|
.Times(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,10 +263,12 @@ TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
|||||||
{
|
{
|
||||||
InSequence calls;
|
InSequence calls;
|
||||||
|
|
||||||
EXPECT_CALL(cdm, Decrypt(_, _, false, _, _, _, _, _, _, _))
|
typedef CdmDecryptionParameters CDP;
|
||||||
|
|
||||||
|
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::is_secure, false)))
|
||||||
.Times(2);
|
.Times(2);
|
||||||
|
|
||||||
EXPECT_CALL(cdm, Decrypt(_, _, true, _, _, _, _, _, _, _))
|
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::is_secure, true)))
|
||||||
.Times(2);
|
.Times(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,3 +289,81 @@ TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
|||||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||||
"WVCryptoPlugin reported a detailed error message.";
|
"WVCryptoPlugin reported a detailed error message.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WVCryptoPluginTest, SetsFlagsForMinimumSubsampleRuns) {
|
||||||
|
MockCDM cdm;
|
||||||
|
WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm);
|
||||||
|
|
||||||
|
uint8_t keyId[KEY_ID_SIZE];
|
||||||
|
uint8_t iv[KEY_IV_SIZE];
|
||||||
|
|
||||||
|
static const size_t kDataSize = 16;
|
||||||
|
uint8_t in[kDataSize];
|
||||||
|
uint8_t out[kDataSize];
|
||||||
|
|
||||||
|
FILE* fp = fopen("/dev/urandom", "r");
|
||||||
|
fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp);
|
||||||
|
fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp);
|
||||||
|
fread(in, sizeof(uint8_t), kDataSize, fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
static const uint32_t kSubSampleCount = 1;
|
||||||
|
CryptoPlugin::SubSample clearSubSamples[kSubSampleCount];
|
||||||
|
memset(clearSubSamples, 0, sizeof(clearSubSamples));
|
||||||
|
clearSubSamples[0].mNumBytesOfClearData = 16;
|
||||||
|
|
||||||
|
CryptoPlugin::SubSample encryptedSubSamples[kSubSampleCount];
|
||||||
|
memset(encryptedSubSamples, 0, sizeof(encryptedSubSamples));
|
||||||
|
encryptedSubSamples[0].mNumBytesOfEncryptedData = 16;
|
||||||
|
|
||||||
|
CryptoPlugin::SubSample mixedSubSamples[kSubSampleCount];
|
||||||
|
memset(mixedSubSamples, 0, sizeof(mixedSubSamples));
|
||||||
|
mixedSubSamples[0].mNumBytesOfClearData = 8;
|
||||||
|
mixedSubSamples[0].mNumBytesOfEncryptedData = 8;
|
||||||
|
|
||||||
|
// Specify the expected calls to Decrypt
|
||||||
|
{
|
||||||
|
InSequence calls;
|
||||||
|
|
||||||
|
typedef CdmDecryptionParameters CDP;
|
||||||
|
|
||||||
|
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::subsample_flags,
|
||||||
|
OEMCrypto_FirstSubsample |
|
||||||
|
OEMCrypto_LastSubsample)))
|
||||||
|
.Times(2);
|
||||||
|
|
||||||
|
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::subsample_flags,
|
||||||
|
OEMCrypto_FirstSubsample)))
|
||||||
|
.Times(1);
|
||||||
|
|
||||||
|
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::subsample_flags,
|
||||||
|
OEMCrypto_LastSubsample)))
|
||||||
|
.Times(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AString errorDetailMessage;
|
||||||
|
|
||||||
|
ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||||
|
in, clearSubSamples, kSubSampleCount, out,
|
||||||
|
&errorDetailMessage);
|
||||||
|
ASSERT_GE(res, 0) <<
|
||||||
|
"WVCryptoPlugin returned an error";
|
||||||
|
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||||
|
"WVCryptoPlugin reported a detailed error message.";
|
||||||
|
|
||||||
|
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, in,
|
||||||
|
encryptedSubSamples, kSubSampleCount, out,
|
||||||
|
&errorDetailMessage);
|
||||||
|
ASSERT_GE(res, 0) <<
|
||||||
|
"WVCryptoPlugin returned an error";
|
||||||
|
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||||
|
"WVCryptoPlugin reported a detailed error message.";
|
||||||
|
|
||||||
|
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, in,
|
||||||
|
mixedSubSamples, kSubSampleCount, out,
|
||||||
|
&errorDetailMessage);
|
||||||
|
ASSERT_GE(res, 0) <<
|
||||||
|
"WVCryptoPlugin returned an error";
|
||||||
|
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||||
|
"WVCryptoPlugin reported a detailed error message.";
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,21 +2,26 @@ LOCAL_PATH:= $(call my-dir)
|
|||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
CDM_SRC_DIR=../../cdm/src
|
||||||
|
CORE_SRC_DIR=../../cdm/core/src
|
||||||
|
|
||||||
LOCAL_SRC_FILES:= \
|
LOCAL_SRC_FILES:= \
|
||||||
src/oemcrypto_engine_mock.cpp \
|
src/oemcrypto_engine_mock.cpp \
|
||||||
src/oemcrypto_key_mock.cpp \
|
src/oemcrypto_key_mock.cpp \
|
||||||
src/oemcrypto_keybox_mock.cpp \
|
src/oemcrypto_keybox_mock.cpp \
|
||||||
src/oemcrypto_mock.cpp \
|
src/oemcrypto_mock.cpp \
|
||||||
src/lock.cpp \
|
|
||||||
src/log.cpp \
|
|
||||||
src/string_conversions.cpp \
|
|
||||||
src/wvcrc.cpp \
|
src/wvcrc.cpp \
|
||||||
|
$(CDM_SRC_DIR)/lock.cpp \
|
||||||
|
$(CDM_SRC_DIR)/log.cpp \
|
||||||
|
$(CORE_SRC_DIR)/string_conversions.cpp \
|
||||||
|
|
||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
|
|
||||||
LOCAL_C_INCLUDES += \
|
LOCAL_C_INCLUDES += \
|
||||||
$(LOCAL_PATH)/../include \
|
$(LOCAL_PATH)/../include \
|
||||||
$(LOCAL_PATH)/src \
|
$(LOCAL_PATH)/src \
|
||||||
|
vendor/widevine/libwvdrmengine/cdm/core/include \
|
||||||
|
vendor/widevine/libwvdrmengine/third_party/stringencoders/src \
|
||||||
bionic \
|
bionic \
|
||||||
external/gtest/include \
|
external/gtest/include \
|
||||||
external/openssl/include \
|
external/openssl/include \
|
||||||
@@ -32,6 +37,7 @@ LOCAL_SHARED_LIBRARIES := \
|
|||||||
libutils \
|
libutils \
|
||||||
libz \
|
libz \
|
||||||
|
|
||||||
|
LOCAL_WHOLE_STATIC_LIBRARIES := libmodp_b64
|
||||||
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)
|
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)
|
||||||
LOCAL_MODULE := liboemcrypto
|
LOCAL_MODULE := liboemcrypto
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +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_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lock::Acquire() {
|
|
||||||
impl_->lock_.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Lock::Release() {
|
|
||||||
impl_->lock_.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Lock::Try() {
|
|
||||||
return (impl_->lock_.tryLock() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace wvcdm
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Lock - Platform independent interface for a Mutex class
|
|
||||||
//
|
|
||||||
#ifndef OEMCRYPTO_LOCK_H_
|
|
||||||
#define OEMCRYPTO_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) : lock_(&lock) {
|
|
||||||
lock_->Acquire();
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit AutoLock(Lock* lock) : lock_(lock) {
|
|
||||||
lock_->Acquire();
|
|
||||||
}
|
|
||||||
|
|
||||||
~AutoLock() {
|
|
||||||
lock_->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Lock *lock_;
|
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(AutoLock);
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // namespace wvcdm
|
|
||||||
|
|
||||||
#endif // OEMCRYPTO_LOCK_H_
|
|
||||||
@@ -1,35 +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 InitLogging(int argc, const char* const* argv) {}
|
|
||||||
|
|
||||||
void Log(const char* file, int line, 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,40 +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;
|
|
||||||
|
|
||||||
// Required to enable/disable verbose logging (LOGV) in Chromium. In Chromium,
|
|
||||||
// verbose logging level is controlled using command line switches --v (global)
|
|
||||||
// or --vmodule (per module). This function calls logging::InitLogging to
|
|
||||||
// initialize logging, which should have already been included in most Chromium
|
|
||||||
// based binaries. However, it is typically not included by default in
|
|
||||||
// unittests, in particular, the unittests in CDM core need to call InitLogging
|
|
||||||
// to be able to control verbose logging in command line.
|
|
||||||
void InitLogging(int argc, const char* const* argv);
|
|
||||||
|
|
||||||
void Log(const char* file, int line, LogPriority level, const char* fmt, ...);
|
|
||||||
|
|
||||||
// Log APIs
|
|
||||||
#define LOGE(...) Log(__FILE__, __LINE__, wvcdm::LOG_ERROR, __VA_ARGS__)
|
|
||||||
#define LOGW(...) Log(__FILE__, __LINE__, wvcdm::LOG_WARN, __VA_ARGS__)
|
|
||||||
#define LOGI(...) Log(__FILE__, __LINE__, wvcdm::LOG_INFO, __VA_ARGS__)
|
|
||||||
#define LOGD(...) Log(__FILE__, __LINE__, wvcdm::LOG_DEBUG, __VA_ARGS__)
|
|
||||||
#define LOGV(...) Log(__FILE__, __LINE__, wvcdm::LOG_VERBOSE, __VA_ARGS__)
|
|
||||||
|
|
||||||
}; // namespace wvcdm
|
|
||||||
|
|
||||||
#endif // OEMCRYPTO_LOG_H_
|
|
||||||
@@ -1,91 +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;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string UintToString(unsigned 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.
|
|
||||||
const int kOutputBufSize = 3 * sizeof(unsigned int);
|
|
||||||
char buffer[kOutputBufSize];
|
|
||||||
memset(buffer, 0, kOutputBufSize);
|
|
||||||
snprintf(buffer, kOutputBufSize, "%u", value);
|
|
||||||
|
|
||||||
std::string out_string(buffer, sizeof(buffer));
|
|
||||||
return out_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
}; // namespace wvcdm
|
|
||||||
@@ -1,20 +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);
|
|
||||||
std::string UintToString(unsigned 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 OEMCRYPTO_WV_CDM_TYPES_H_
|
|
||||||
#define OEMCRYPTO_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 // OEMCRYPTO_WV_CDM_TYPES_H_
|
|
||||||
@@ -4,8 +4,7 @@ LOCAL_PATH:= $(call my-dir)
|
|||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
LOCAL_SRC_FILES:= \
|
LOCAL_SRC_FILES:= \
|
||||||
oemcrypto_test.cpp \
|
oemcrypto_test.cpp
|
||||||
../../cdm/src/log.cpp \
|
|
||||||
|
|
||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
|
|
||||||
@@ -19,6 +18,8 @@ LOCAL_C_INCLUDES += \
|
|||||||
external/stlport/stlport \
|
external/stlport/stlport \
|
||||||
$(LOCAL_PATH)/../include \
|
$(LOCAL_PATH)/../include \
|
||||||
$(LOCAL_PATH)/../mock/src \
|
$(LOCAL_PATH)/../mock/src \
|
||||||
|
vendor/widevine/libwvdrmengine/cdm/core/include \
|
||||||
|
vendor/widevine/libwvdrmengine/third_party/stringencoders/src \
|
||||||
|
|
||||||
# TODO(fredgc): fix order dependencies on libwvlevel3 and libwvwrapper.
|
# TODO(fredgc): fix order dependencies on libwvlevel3 and libwvwrapper.
|
||||||
LOCAL_STATIC_LIBRARIES := \
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
|
|||||||
Reference in New Issue
Block a user