OEMCrypto v11 Refrence Code and Unit Tests
This CL is a merge from the widevine repo of http://go/wvgerrit/16553 Prebuilt Level 3 OEMCrypto for Android http://go/wvgerrit/16238 Require OEMCrypto v11 for Android N Unit Tests http://go/wvgerrit/16484 Shared License Tests (OEMCrypto v11) http://go/wvgerrit/16448 Pattern Decrypt Unit Tests and Reference Implementation http://go/wvgerrit/16489 Enforce UNUSED Variables http://go/wvgerrit/16479 Pattern Decrypt for Level 3 OEMCrypto http://go/wvgerrit/16280 Correctly handle bad RSA key http://go/wvgerrit/16315 Security Patch Level - haystack version http://go/wvgerrit/16282 Correctly handle null pointer in GetKeyData http://go/wvgerrit/16294 Initialize data for generation number It contains the Level 3 implementation, as well. mips/libwvlevel3.a Level3 Library Jan 22 2016 14:30:27 arm/libwvlevel3.a Level3 Library Jan 22 2016 15:03:55 x86/libwvlevel3.a Level3 Library Jan 22 2016 13:52:29 b/26692954 [DRM] OEMCrypto v11 needed for Nexus devices Change-Id: Ibb1384959620f63a1be1e82ce2952ec9f48f0d3e
This commit is contained in:
@@ -30,7 +30,6 @@ using wvcdm::kLevel3;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// TODO(fredgc): rename to _V10 after removing from level3.h.
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const uint8_t* key_id;
|
const uint8_t* key_id;
|
||||||
size_t key_id_length;
|
size_t key_id_length;
|
||||||
@@ -39,7 +38,7 @@ typedef struct {
|
|||||||
size_t key_data_length;
|
size_t key_data_length;
|
||||||
const uint8_t* key_control_iv;
|
const uint8_t* key_control_iv;
|
||||||
const uint8_t* key_control;
|
const uint8_t* key_control;
|
||||||
} OEMCrypto_KeyObject_TODO;
|
} OEMCrypto_KeyObject_V10;
|
||||||
|
|
||||||
typedef OEMCryptoResult (*L1_Initialize_t)(void);
|
typedef OEMCryptoResult (*L1_Initialize_t)(void);
|
||||||
typedef OEMCryptoResult (*L1_Terminate_t)(void);
|
typedef OEMCryptoResult (*L1_Terminate_t)(void);
|
||||||
@@ -420,11 +419,11 @@ class Adapter {
|
|||||||
level3_.GenerateDerivedKeys = Level3_GenerateDerivedKeys;
|
level3_.GenerateDerivedKeys = Level3_GenerateDerivedKeys;
|
||||||
level3_.GenerateNonce = Level3_GenerateNonce;
|
level3_.GenerateNonce = Level3_GenerateNonce;
|
||||||
level3_.GenerateSignature = Level3_GenerateSignature;
|
level3_.GenerateSignature = Level3_GenerateSignature;
|
||||||
level3_.LoadKeys_V9_or_V10 = Level3_LoadKeys;
|
level3_.LoadKeys = Level3_LoadKeys;
|
||||||
level3_.RefreshKeys = Level3_RefreshKeys;
|
level3_.RefreshKeys = Level3_RefreshKeys;
|
||||||
level3_.QueryKeyControl = Level3_QueryKeyControl;
|
level3_.QueryKeyControl = Level3_QueryKeyControl;
|
||||||
level3_.SelectKey = Level3_SelectKey;
|
level3_.SelectKey = Level3_SelectKey;
|
||||||
level3_.DecryptCTR_V10 = Level3_DecryptCTR;
|
level3_.DecryptCENC = Level3_DecryptCENC;
|
||||||
level3_.CopyBuffer = Level3_CopyBuffer;
|
level3_.CopyBuffer = Level3_CopyBuffer;
|
||||||
level3_.WrapKeybox = Level3_WrapKeybox;
|
level3_.WrapKeybox = Level3_WrapKeybox;
|
||||||
level3_.InstallKeybox = Level3_InstallKeybox;
|
level3_.InstallKeybox = Level3_InstallKeybox;
|
||||||
@@ -439,6 +438,7 @@ class Adapter {
|
|||||||
level3_.GenerateRSASignature = Level3_GenerateRSASignature;
|
level3_.GenerateRSASignature = Level3_GenerateRSASignature;
|
||||||
level3_.DeriveKeysFromSessionKey = Level3_DeriveKeysFromSessionKey;
|
level3_.DeriveKeysFromSessionKey = Level3_DeriveKeysFromSessionKey;
|
||||||
level3_.APIVersion = Level3_APIVersion;
|
level3_.APIVersion = Level3_APIVersion;
|
||||||
|
level3_.SecurityPatchLevel = Level3_SecurityPatchLevel;
|
||||||
level3_.SecurityLevel = Level3_SecurityLevel;
|
level3_.SecurityLevel = Level3_SecurityLevel;
|
||||||
level3_.GetHDCPCapability = Level3_GetHDCPCapability;
|
level3_.GetHDCPCapability = Level3_GetHDCPCapability;
|
||||||
level3_.SupportsUsageTable = Level3_SupportsUsageTable;
|
level3_.SupportsUsageTable = Level3_SupportsUsageTable;
|
||||||
|
|||||||
Binary file not shown.
@@ -54,7 +54,7 @@ OEMCryptoResult Level3_LoadKeys(OEMCrypto_SESSION /*session*/,
|
|||||||
const uint8_t* /*enc_mac_key_iv*/,
|
const uint8_t* /*enc_mac_key_iv*/,
|
||||||
const uint8_t* /*enc_mac_key*/,
|
const uint8_t* /*enc_mac_key*/,
|
||||||
size_t /*num_keys*/,
|
size_t /*num_keys*/,
|
||||||
const OEMCrypto_KeyObject_V10* /*key_array*/,
|
const OEMCrypto_KeyObject* /*key_array*/,
|
||||||
const uint8_t* /*pst*/,
|
const uint8_t* /*pst*/,
|
||||||
size_t /*pst_length*/) {
|
size_t /*pst_length*/) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
@@ -84,11 +84,12 @@ OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION /*session*/,
|
|||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCryptoResult Level3_DecryptCTR(OEMCrypto_SESSION /*session*/,
|
OEMCryptoResult Level3_DecryptCENC(OEMCrypto_SESSION /*session*/,
|
||||||
const uint8_t* /*data_addr*/, size_t /*data_length*/,
|
const uint8_t* /*data_addr*/, size_t /*data_length*/,
|
||||||
bool /*is_encrypted*/, const uint8_t* /*iv*/,
|
bool /*is_encrypted*/, const uint8_t* /*iv*/,
|
||||||
size_t /*block_offset*/,
|
size_t /*block_offset*/,
|
||||||
const OEMCrypto_DestBufferDesc* /*out_buffer*/,
|
const OEMCrypto_DestBufferDesc* /*out_buffer*/,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* /*pattern*/,
|
||||||
uint8_t /*subsample_flags*/) {
|
uint8_t /*subsample_flags*/) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -26,7 +26,7 @@ namespace wvoec3 {
|
|||||||
#define Level3_WrapKeybox _lcc08
|
#define Level3_WrapKeybox _lcc08
|
||||||
#define Level3_OpenSession _lcc09
|
#define Level3_OpenSession _lcc09
|
||||||
#define Level3_CloseSession _lcc10
|
#define Level3_CloseSession _lcc10
|
||||||
#define Level3_DecryptCTR _lcc11
|
#define Level3_DecryptCENC _lcc11
|
||||||
#define Level3_GenerateDerivedKeys _lcc12
|
#define Level3_GenerateDerivedKeys _lcc12
|
||||||
#define Level3_GenerateSignature _lcc13
|
#define Level3_GenerateSignature _lcc13
|
||||||
#define Level3_GenerateNonce _lcc14
|
#define Level3_GenerateNonce _lcc14
|
||||||
@@ -78,16 +78,6 @@ OEMCryptoResult Level3_GenerateSignature(OEMCrypto_SESSION session,
|
|||||||
size_t message_length,
|
size_t message_length,
|
||||||
uint8_t* signature,
|
uint8_t* signature,
|
||||||
size_t* signature_length);
|
size_t* signature_length);
|
||||||
// TODO(fredgc): move this to oemcrypto_adapter_dynamic.cpp
|
|
||||||
typedef struct {
|
|
||||||
const uint8_t* key_id;
|
|
||||||
size_t key_id_length;
|
|
||||||
const uint8_t* key_data_iv;
|
|
||||||
const uint8_t* key_data;
|
|
||||||
size_t key_data_length;
|
|
||||||
const uint8_t* key_control_iv;
|
|
||||||
const uint8_t* key_control;
|
|
||||||
} OEMCrypto_KeyObject_V10;
|
|
||||||
|
|
||||||
OEMCryptoResult Level3_LoadKeys(OEMCrypto_SESSION session,
|
OEMCryptoResult Level3_LoadKeys(OEMCrypto_SESSION session,
|
||||||
const uint8_t* message,
|
const uint8_t* message,
|
||||||
@@ -97,7 +87,7 @@ OEMCryptoResult Level3_LoadKeys(OEMCrypto_SESSION session,
|
|||||||
const uint8_t* enc_mac_key_iv,
|
const uint8_t* enc_mac_key_iv,
|
||||||
const uint8_t* enc_mac_key,
|
const uint8_t* enc_mac_key,
|
||||||
size_t num_keys,
|
size_t num_keys,
|
||||||
const OEMCrypto_KeyObject_V10* key_array,
|
const OEMCrypto_KeyObject* key_array,
|
||||||
const uint8_t* pst,
|
const uint8_t* pst,
|
||||||
size_t pst_length);
|
size_t pst_length);
|
||||||
OEMCryptoResult Level3_RefreshKeys(OEMCrypto_SESSION session,
|
OEMCryptoResult Level3_RefreshKeys(OEMCrypto_SESSION session,
|
||||||
@@ -115,13 +105,14 @@ OEMCryptoResult Level3_QueryKeyControl(OEMCrypto_SESSION session,
|
|||||||
OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session,
|
OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session,
|
||||||
const uint8_t* key_id,
|
const uint8_t* key_id,
|
||||||
size_t key_id_length);
|
size_t key_id_length);
|
||||||
OEMCryptoResult Level3_DecryptCTR(OEMCrypto_SESSION session,
|
OEMCryptoResult Level3_DecryptCENC(OEMCrypto_SESSION session,
|
||||||
const uint8_t *data_addr,
|
const uint8_t *data_addr,
|
||||||
size_t data_length,
|
size_t data_length,
|
||||||
bool is_encrypted,
|
bool is_encrypted,
|
||||||
const uint8_t *iv,
|
const uint8_t *iv,
|
||||||
size_t block_offset,
|
size_t block_offset,
|
||||||
const OEMCrypto_DestBufferDesc* out_buffer,
|
const OEMCrypto_DestBufferDesc* out_buffer,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||||
uint8_t subsample_flags);
|
uint8_t subsample_flags);
|
||||||
OEMCryptoResult Level3_CopyBuffer(const uint8_t *data_addr,
|
OEMCryptoResult Level3_CopyBuffer(const uint8_t *data_addr,
|
||||||
size_t data_length,
|
size_t data_length,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -605,7 +606,8 @@ OEMCryptoResult SessionContext::LoadKeys(
|
|||||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||||
|
|
||||||
if (!InstallKey(key_id, enc_key_data, key_data_iv, key_control,
|
if (!InstallKey(key_id, enc_key_data, key_data_iv, key_control,
|
||||||
key_control_iv, pstv)) {
|
key_control_iv, pstv,
|
||||||
|
key_array[i].cipher_mode == OEMCrypto_CipherMode_CTR)) {
|
||||||
status = false;
|
status = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -622,11 +624,17 @@ OEMCryptoResult SessionContext::LoadKeys(
|
|||||||
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
|
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
|
||||||
|
|
||||||
if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
|
if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
|
||||||
|
LOGE("Failed to update mac keys.\n");
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (usage_entry_) {
|
if (pst_length > 0) {
|
||||||
|
if (!usage_entry_) {
|
||||||
|
LOGE("Usage table entry not found.\n");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
if (!usage_entry_->VerifyOrSetMacKeys(mac_key_server_, mac_key_client_)) {
|
if (!usage_entry_->VerifyOrSetMacKeys(mac_key_server_, mac_key_client_)) {
|
||||||
|
LOGE("Usage table entry does not match.\n");
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -638,7 +646,8 @@ bool SessionContext::InstallKey(const KeyId& key_id,
|
|||||||
const std::vector<uint8_t>& key_data_iv,
|
const std::vector<uint8_t>& key_data_iv,
|
||||||
const std::vector<uint8_t>& key_control,
|
const std::vector<uint8_t>& key_control,
|
||||||
const std::vector<uint8_t>& key_control_iv,
|
const std::vector<uint8_t>& key_control_iv,
|
||||||
const std::vector<uint8_t>& pst) {
|
const std::vector<uint8_t>& pst,
|
||||||
|
bool ctr_mode) {
|
||||||
// Decrypt encrypted key_data using derived encryption key and offered iv
|
// Decrypt encrypted key_data using derived encryption key and offered iv
|
||||||
std::vector<uint8_t> content_key;
|
std::vector<uint8_t> content_key;
|
||||||
std::vector<uint8_t> key_control_str;
|
std::vector<uint8_t> key_control_str;
|
||||||
@@ -683,8 +692,8 @@ bool SessionContext::InstallKey(const KeyId& key_id,
|
|||||||
LOGE("Anti-rollback hardware is required but hardware not present.");
|
LOGE("Anti-rollback hardware is required but hardware not present.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t minimum_patch_level
|
uint8_t minimum_patch_level =
|
||||||
= (key_control_block.control_bits() & kControlSecurityPatchLevelMask) >>
|
(key_control_block.control_bits() & kControlSecurityPatchLevelMask) >>
|
||||||
kControlSecurityPatchLevelShift;
|
kControlSecurityPatchLevelShift;
|
||||||
if (minimum_patch_level > OEMCrypto_Security_Patch_Level()) {
|
if (minimum_patch_level > OEMCrypto_Security_Patch_Level()) {
|
||||||
LOGE("[InstallKey(): security patch level: %d. Minimum:%d]",
|
LOGE("[InstallKey(): security patch level: %d. Minimum:%d]",
|
||||||
@@ -697,14 +706,13 @@ bool SessionContext::InstallKey(const KeyId& key_id,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Key key(content_key, key_control_block);
|
Key key(content_key, key_control_block, ctr_mode);
|
||||||
session_keys_.Insert(key_id, key);
|
session_keys_.Insert(key_id, key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCryptoResult SessionContext::RefreshKey(
|
OEMCryptoResult SessionContext::RefreshKey(
|
||||||
const KeyId& key_id,
|
const KeyId& key_id, const std::vector<uint8_t>& key_control,
|
||||||
const std::vector<uint8_t>& key_control,
|
|
||||||
const std::vector<uint8_t>& key_control_iv) {
|
const std::vector<uint8_t>& key_control_iv) {
|
||||||
if (key_id.empty()) {
|
if (key_id.empty()) {
|
||||||
// Key control is not encrypted if key id is NULL
|
// Key control is not encrypted if key id is NULL
|
||||||
@@ -1119,8 +1127,12 @@ bool SessionContext::QueryKeyControlBlock(const KeyId& key_id, uint32_t* data) {
|
|||||||
if (LogCategoryEnabled(kLoggingTraceDecryption)){
|
if (LogCategoryEnabled(kLoggingTraceDecryption)){
|
||||||
LOGI(( "Select Key: key_id = " +
|
LOGI(( "Select Key: key_id = " +
|
||||||
wvcdm::b2a_hex(key_id) ).c_str());
|
wvcdm::b2a_hex(key_id) ).c_str());
|
||||||
|
if (content_key) {
|
||||||
LOGI(( "Select Key: key = " +
|
LOGI(( "Select Key: key = " +
|
||||||
wvcdm::b2a_hex(content_key->value()) ).c_str());
|
wvcdm::b2a_hex(content_key->value()) ).c_str());
|
||||||
|
} else {
|
||||||
|
LOGI("Select Key: key = null.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (NULL == content_key) {
|
if (NULL == content_key) {
|
||||||
LOGE("[QueryKeyControlBlock(): No key matches key id]");
|
LOGE("[QueryKeyControlBlock(): No key matches key id]");
|
||||||
@@ -1187,8 +1199,7 @@ CryptoEngine::~CryptoEngine() {
|
|||||||
if (usage_table_) delete usage_table_;
|
if (usage_table_) delete usage_table_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CryptoEngine::Terminate() {
|
void CryptoEngine::Terminate() {}
|
||||||
}
|
|
||||||
|
|
||||||
KeyboxError CryptoEngine::ValidateKeybox() { return keybox().Validate(); }
|
KeyboxError CryptoEngine::ValidateKeybox() { return keybox().Validate(); }
|
||||||
|
|
||||||
@@ -1298,18 +1309,19 @@ bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
|
|||||||
memcpy(iv_buffer, &iv[0], 16);
|
memcpy(iv_buffer, &iv[0], 16);
|
||||||
AES_KEY aes_key;
|
AES_KEY aes_key;
|
||||||
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||||
AES_cbc_encrypt(&message[0], &(decrypted->front()), message.size(),
|
AES_cbc_encrypt(&message[0], &(decrypted->front()), message.size(), &aes_key,
|
||||||
&aes_key, iv_buffer, AES_DECRYPT);
|
iv_buffer, AES_DECRYPT);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCryptoResult SessionContext::DecryptCTR(
|
OEMCryptoResult SessionContext::DecryptCENC(
|
||||||
const uint8_t* iv, size_t block_offset, const uint8_t* cipher_data,
|
const uint8_t* iv, size_t block_offset,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
|
||||||
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
|
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
|
||||||
OEMCryptoBufferType buffer_type) {
|
OEMCryptoBufferType buffer_type) {
|
||||||
// If the data is clear, we do not need a current key selected.
|
// If the data is clear, we do not need a current key selected.
|
||||||
if (!is_encrypted) {
|
if (!is_encrypted) {
|
||||||
if (buffer_type != OEMCrypto_BufferType_Direct){
|
if (buffer_type != OEMCrypto_BufferType_Direct) {
|
||||||
memcpy(reinterpret_cast<uint8_t*>(clear_data), cipher_data,
|
memcpy(reinterpret_cast<uint8_t*>(clear_data), cipher_data,
|
||||||
cipher_data_length);
|
cipher_data_length);
|
||||||
return OEMCrypto_SUCCESS;
|
return OEMCrypto_SUCCESS;
|
||||||
@@ -1375,13 +1387,105 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
|||||||
return OEMCrypto_SUCCESS;
|
return OEMCrypto_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!current_content_key()->ctr_mode()) {
|
||||||
|
if (block_offset > 0) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
return DecryptCBC(key_u8, iv, pattern, cipher_data, cipher_data_length,
|
||||||
|
clear_data);
|
||||||
|
}
|
||||||
|
if (pattern->skip > 0) {
|
||||||
|
return PatternDecryptCTR(key_u8, iv, block_offset, pattern, cipher_data,
|
||||||
|
cipher_data_length, clear_data);
|
||||||
|
}
|
||||||
|
return DecryptCTR(key_u8, iv, block_offset, cipher_data, cipher_data_length,
|
||||||
|
clear_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult SessionContext::DecryptCBC(
|
||||||
|
const uint8_t* key, const uint8_t* initial_iv,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
|
||||||
|
size_t cipher_data_length, uint8_t* clear_data) {
|
||||||
|
AES_KEY aes_key;
|
||||||
|
AES_set_decrypt_key(&key[0], AES_BLOCK_SIZE * 8, &aes_key);
|
||||||
|
uint8_t iv[AES_BLOCK_SIZE];
|
||||||
|
memcpy(iv, &initial_iv[0], AES_BLOCK_SIZE);
|
||||||
|
|
||||||
|
size_t l = 0;
|
||||||
|
size_t pattern_offset = pattern->offset;
|
||||||
|
while (l < cipher_data_length) {
|
||||||
|
size_t size =
|
||||||
|
std::min(cipher_data_length - l, static_cast<size_t>(AES_BLOCK_SIZE));
|
||||||
|
size_t pattern_length = pattern->encrypt + pattern->skip;
|
||||||
|
bool skip_block = (pattern_offset >= pattern->encrypt)
|
||||||
|
&& (pattern_length>0);
|
||||||
|
if (pattern_length > 0) {
|
||||||
|
pattern_offset = (pattern_offset + 1) % pattern_length;
|
||||||
|
}
|
||||||
|
if (skip_block || (size < AES_BLOCK_SIZE)) {
|
||||||
|
memcpy(&clear_data[l], &cipher_data[l], size);
|
||||||
|
} else {
|
||||||
|
uint8_t aes_output[AES_BLOCK_SIZE];
|
||||||
|
AES_decrypt(&cipher_data[l], aes_output, &aes_key);
|
||||||
|
for (size_t n = 0; n < AES_BLOCK_SIZE; n++) {
|
||||||
|
clear_data[l + n] = aes_output[n] ^ iv[n];
|
||||||
|
}
|
||||||
|
memcpy(iv, &cipher_data[l], AES_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
l += size;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult SessionContext::PatternDecryptCTR(
|
||||||
|
const uint8_t* key, const uint8_t* initial_iv, size_t block_offset,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
|
||||||
|
size_t cipher_data_length, uint8_t* clear_data) {
|
||||||
|
AES_KEY aes_key;
|
||||||
|
AES_set_encrypt_key(&key[0], AES_BLOCK_SIZE * 8, &aes_key);
|
||||||
|
uint8_t iv[AES_BLOCK_SIZE];
|
||||||
|
memcpy(iv, &initial_iv[0], AES_BLOCK_SIZE);
|
||||||
|
|
||||||
|
size_t l = 0;
|
||||||
|
size_t pattern_offset = pattern->offset;
|
||||||
|
while (l < cipher_data_length) {
|
||||||
|
size_t size =
|
||||||
|
std::min(cipher_data_length - l, AES_BLOCK_SIZE - block_offset);
|
||||||
|
size_t pattern_length = pattern->encrypt + pattern->skip;
|
||||||
|
bool skip_block = (pattern_offset >= pattern->encrypt)
|
||||||
|
&& (pattern_length>0);
|
||||||
|
if (pattern_length > 0) {
|
||||||
|
pattern_offset = (pattern_offset + 1) % pattern_length;
|
||||||
|
}
|
||||||
|
if (skip_block) {
|
||||||
|
memcpy(&clear_data[l], &cipher_data[l], size);
|
||||||
|
} else {
|
||||||
|
uint8_t aes_output[AES_BLOCK_SIZE];
|
||||||
|
AES_encrypt(iv, aes_output, &aes_key);
|
||||||
|
for (size_t n = 0; n < size; n++) {
|
||||||
|
clear_data[l + n] = aes_output[n + block_offset] ^ cipher_data[l + n];
|
||||||
|
}
|
||||||
|
ctr128_inc64(iv);
|
||||||
|
}
|
||||||
|
l += size;
|
||||||
|
block_offset = 0;
|
||||||
|
}
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a special case of PatternDecryptCTR with no skip pattern. It uses
|
||||||
|
// more optimized versions of openssl's implementation of AES CTR mode.
|
||||||
|
OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
|
||||||
|
const uint8_t* iv,
|
||||||
|
size_t block_offset,
|
||||||
|
const uint8_t* cipher_data,
|
||||||
|
size_t cipher_data_length,
|
||||||
|
uint8_t* clear_data) {
|
||||||
// Local copy (will be modified).
|
// Local copy (will be modified).
|
||||||
// Allocated as 64-bit ints to enforce 64-bit alignment for later access as a
|
// Allocated as 64-bit ints to enforce 64-bit alignment for later access as a
|
||||||
// 64-bit value.
|
// 64-bit value.
|
||||||
uint64_t aes_iv[2];
|
uint64_t aes_iv[2];
|
||||||
assert(sizeof(aes_iv) == AES_BLOCK_SIZE);
|
assert(sizeof(aes_iv) == AES_BLOCK_SIZE);
|
||||||
// The double-cast is needed to comply with strict aliasing rules.
|
// The double-cast is needed to comply with strict aliasing rules.
|
||||||
uint8_t *aes_iv_u8 =
|
uint8_t* aes_iv_u8 =
|
||||||
reinterpret_cast<uint8_t*>(reinterpret_cast<void*>(aes_iv));
|
reinterpret_cast<uint8_t*>(reinterpret_cast<void*>(aes_iv));
|
||||||
memcpy(aes_iv_u8, &iv[0], AES_BLOCK_SIZE);
|
memcpy(aes_iv_u8, &iv[0], AES_BLOCK_SIZE);
|
||||||
|
|
||||||
@@ -1391,7 +1495,6 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
|||||||
// why we implement the CTR loop ourselves.
|
// why we implement the CTR loop ourselves.
|
||||||
size_t l = 0;
|
size_t l = 0;
|
||||||
if (block_offset > 0 && l < cipher_data_length) {
|
if (block_offset > 0 && l < cipher_data_length) {
|
||||||
|
|
||||||
// Encrypt the IV.
|
// Encrypt the IV.
|
||||||
uint8_t ecount_buf[AES_BLOCK_SIZE];
|
uint8_t ecount_buf[AES_BLOCK_SIZE];
|
||||||
|
|
||||||
@@ -1443,8 +1546,8 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
|||||||
remaining = cipher_data_length - l;
|
remaining = cipher_data_length - l;
|
||||||
|
|
||||||
int final;
|
int final;
|
||||||
if (!EVP_DecryptFinal_ex(&ctx, &clear_data[cipher_data_length - remaining],
|
if (!EVP_DecryptFinal_ex(
|
||||||
&final)) {
|
&ctx, &clear_data[cipher_data_length - remaining], & final)) {
|
||||||
LOGE("[DecryptCTR(): EVP_FINAL_ERROR]");
|
LOGE("[DecryptCTR(): EVP_FINAL_ERROR]");
|
||||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,8 @@ class SessionContext {
|
|||||||
size_t message_length,
|
size_t message_length,
|
||||||
const uint8_t* signature,
|
const uint8_t* signature,
|
||||||
size_t signature_length);
|
size_t signature_length);
|
||||||
OEMCryptoResult DecryptCTR(const uint8_t* iv, size_t block_offset,
|
OEMCryptoResult DecryptCENC(const uint8_t* iv, size_t block_offset,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||||
const uint8_t* cipher_data,
|
const uint8_t* cipher_data,
|
||||||
size_t cipher_data_length, bool is_encrypted,
|
size_t cipher_data_length, bool is_encrypted,
|
||||||
uint8_t* clear_data,
|
uint8_t* clear_data,
|
||||||
@@ -142,7 +143,8 @@ class SessionContext {
|
|||||||
const std::vector<uint8_t>& key_data_iv,
|
const std::vector<uint8_t>& key_data_iv,
|
||||||
const std::vector<uint8_t>& key_control,
|
const std::vector<uint8_t>& key_control,
|
||||||
const std::vector<uint8_t>& key_control_iv,
|
const std::vector<uint8_t>& key_control_iv,
|
||||||
const std::vector<uint8_t>& pst);
|
const std::vector<uint8_t>& pst,
|
||||||
|
bool ctr_mode);
|
||||||
bool DecryptRSAKey(const uint8_t* enc_rsa_key,
|
bool DecryptRSAKey(const uint8_t* enc_rsa_key,
|
||||||
size_t enc_rsa_key_length,
|
size_t enc_rsa_key_length,
|
||||||
const uint8_t* wrapped_rsa_key_iv,
|
const uint8_t* wrapped_rsa_key_iv,
|
||||||
@@ -164,7 +166,7 @@ class SessionContext {
|
|||||||
const std::vector<uint8_t>& iv);
|
const std::vector<uint8_t>& iv);
|
||||||
bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
|
bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
|
||||||
bool SelectContentKey(const KeyId& key_id);
|
bool SelectContentKey(const KeyId& key_id);
|
||||||
const Key* current_content_key(void) {return current_content_key_;}
|
const Key* current_content_key(void) { return current_content_key_; }
|
||||||
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
|
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
|
||||||
mac_key_server_ = mac_key_server;
|
mac_key_server_ = mac_key_server;
|
||||||
}
|
}
|
||||||
@@ -196,6 +198,18 @@ class SessionContext {
|
|||||||
bool CheckNonceOrEntry(const KeyControlBlock& key_control_block,
|
bool CheckNonceOrEntry(const KeyControlBlock& key_control_block,
|
||||||
const std::vector<uint8_t>& pst);
|
const std::vector<uint8_t>& pst);
|
||||||
bool IsUsageEntryValid();
|
bool IsUsageEntryValid();
|
||||||
|
OEMCryptoResult DecryptCBC(const uint8_t* key, const uint8_t* iv,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||||
|
const uint8_t* cipher_data,
|
||||||
|
size_t cipher_data_length, uint8_t* clear_data);
|
||||||
|
OEMCryptoResult PatternDecryptCTR(
|
||||||
|
const uint8_t* key, const uint8_t* iv, size_t block_offset,
|
||||||
|
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||||
|
const uint8_t* cipher_data, size_t cipher_data_length,
|
||||||
|
uint8_t* clear_data);
|
||||||
|
OEMCryptoResult DecryptCTR(const uint8_t* key_u8, const uint8_t* iv,
|
||||||
|
size_t block_offset, const uint8_t* cipher_data,
|
||||||
|
size_t cipher_data_length, uint8_t* clear_data);
|
||||||
|
|
||||||
bool valid_;
|
bool valid_;
|
||||||
CryptoEngine* ce_;
|
CryptoEngine* ce_;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "oemcrypto_logging.h"
|
#include "oemcrypto_logging.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
|
|
||||||
|
|
||||||
namespace wvoec_mock {
|
namespace wvoec_mock {
|
||||||
|
|
||||||
bool KeyControlBlock::Validate() {
|
bool KeyControlBlock::Validate() {
|
||||||
@@ -102,9 +101,6 @@ KeyControlBlock::KeyControlBlock(
|
|||||||
Validate();
|
Validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
Key::Key(const std::vector<uint8_t>& key_string, const KeyControlBlock& control)
|
|
||||||
: value_(key_string), control_(control) {}
|
|
||||||
|
|
||||||
void Key::UpdateDuration(const KeyControlBlock& control) {
|
void Key::UpdateDuration(const KeyControlBlock& control) {
|
||||||
control_.set_duration(control.duration());
|
control_.set_duration(control.duration());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,17 +63,22 @@ class KeyControlBlock {
|
|||||||
// AES-128 crypto key, or HMAC signing key.
|
// AES-128 crypto key, or HMAC signing key.
|
||||||
class Key {
|
class Key {
|
||||||
public:
|
public:
|
||||||
Key(const Key& key) : value_(key.value_), control_(key.control_) {}
|
Key(const Key& key) : value_(key.value_), control_(key.control_),
|
||||||
Key(const std::vector<uint8_t>& key_string, const KeyControlBlock& control);
|
ctr_mode_(key.ctr_mode_) {}
|
||||||
|
Key(const std::vector<uint8_t>& key_string, const KeyControlBlock& control,
|
||||||
|
bool ctr_mode) : value_(key_string), control_(control),
|
||||||
|
ctr_mode_(ctr_mode) {};
|
||||||
|
|
||||||
virtual ~Key() {};
|
virtual ~Key() {};
|
||||||
void UpdateDuration(const KeyControlBlock& control);
|
void UpdateDuration(const KeyControlBlock& control);
|
||||||
const std::vector<uint8_t>& value() const { return value_; }
|
const std::vector<uint8_t>& value() const { return value_; }
|
||||||
const KeyControlBlock& control() const { return control_; }
|
const KeyControlBlock& control() const { return control_; }
|
||||||
|
bool ctr_mode() const { return ctr_mode_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<uint8_t> value_;
|
std::vector<uint8_t> value_;
|
||||||
KeyControlBlock control_;
|
KeyControlBlock control_;
|
||||||
|
bool ctr_mode_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvoec_mock
|
} // namespace wvoec_mock
|
||||||
|
|||||||
@@ -4,19 +4,19 @@
|
|||||||
//
|
//
|
||||||
#include "OEMCryptoCENC.h"
|
#include "OEMCryptoCENC.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <openssl/cmac.h>
|
#include <openssl/cmac.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "oemcrypto_engine_mock.h"
|
#include "oemcrypto_engine_mock.h"
|
||||||
#include "oemcrypto_logging.h"
|
#include "oemcrypto_logging.h"
|
||||||
@@ -382,12 +382,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
|||||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT -range check %d]", i);
|
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT -range check %d]", i);
|
||||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
}
|
}
|
||||||
if (key_array[i].cipher_mode != OEMCrypto_CipherMode_CTR) {
|
|
||||||
LOGE("[OEMCrypto_LoadKeys(): CBC Mode not yet implemented]");
|
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return session_ctx->LoadKeys(message, message_length, signature,
|
return session_ctx->LoadKeys(message, message_length, signature,
|
||||||
signature_length, enc_mac_key_iv, enc_mac_keys,
|
signature_length, enc_mac_key_iv, enc_mac_keys,
|
||||||
num_keys, key_array, pst, pst_length);
|
num_keys, key_array, pst, pst_length);
|
||||||
@@ -643,7 +638,8 @@ OEMCryptoResult OEMCrypto_DecryptCENC(OEMCrypto_SESSION session,
|
|||||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
return session_ctx->DecryptCTR(iv, block_offset, data_addr, data_length,
|
return session_ctx->DecryptCENC(iv, block_offset, pattern,
|
||||||
|
data_addr, data_length,
|
||||||
is_encrypted, destination,
|
is_encrypted, destination,
|
||||||
out_buffer->type);
|
out_buffer->type);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -111,4 +111,12 @@ TEST_F(OEMCryptoAndroidMNCTest, QueryKeyControlImplemented) {
|
|||||||
OEMCrypto_QueryKeyControl(0, NULL, 0, NULL, NULL));
|
OEMCrypto_QueryKeyControl(0, NULL, 0, NULL, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These tests are required for N Android devices.
|
||||||
|
class OEMCryptoAndroidNYCTest : public OEMCryptoAndroidMNCTest {};
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoAndroidNYCTest, MinVersionNumber11) {
|
||||||
|
uint32_t version = OEMCrypto_APIVersion();
|
||||||
|
ASSERT_GE(version, 11u);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
Reference in New Issue
Block a user