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:
@@ -7,6 +7,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
@@ -605,7 +606,8 @@ OEMCryptoResult SessionContext::LoadKeys(
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@@ -622,11 +624,17 @@ OEMCryptoResult SessionContext::LoadKeys(
|
||||
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
|
||||
|
||||
if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
|
||||
LOGE("Failed to update mac keys.\n");
|
||||
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_)) {
|
||||
LOGE("Usage table entry does not match.\n");
|
||||
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_control,
|
||||
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
|
||||
std::vector<uint8_t> content_key;
|
||||
std::vector<uint8_t> key_control_str;
|
||||
@@ -678,18 +687,18 @@ bool SessionContext::InstallKey(const KeyId& key_id,
|
||||
return false;
|
||||
}
|
||||
if ((key_control_block.control_bits() &
|
||||
kControlRequireAntiRollbackHardware) &&
|
||||
kControlRequireAntiRollbackHardware) &&
|
||||
!ce_->is_anti_rollback_hw_present()) {
|
||||
LOGE("Anti-rollback hardware is required but hardware not present.");
|
||||
return false;
|
||||
}
|
||||
uint8_t minimum_patch_level
|
||||
= (key_control_block.control_bits() & kControlSecurityPatchLevelMask) >>
|
||||
uint8_t minimum_patch_level =
|
||||
(key_control_block.control_bits() & kControlSecurityPatchLevelMask) >>
|
||||
kControlSecurityPatchLevelShift;
|
||||
if (minimum_patch_level > OEMCrypto_Security_Patch_Level()) {
|
||||
LOGE("[InstallKey(): security patch level: %d. Minimum:%d]",
|
||||
OEMCrypto_Security_Patch_Level(), minimum_patch_level);
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckNonceOrEntry(key_control_block, pst)) {
|
||||
@@ -697,14 +706,13 @@ bool SessionContext::InstallKey(const KeyId& key_id,
|
||||
return false;
|
||||
}
|
||||
|
||||
Key key(content_key, key_control_block);
|
||||
Key key(content_key, key_control_block, ctr_mode);
|
||||
session_keys_.Insert(key_id, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::RefreshKey(
|
||||
const KeyId& key_id,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const KeyId& key_id, const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv) {
|
||||
if (key_id.empty()) {
|
||||
// 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)){
|
||||
LOGI(( "Select Key: key_id = " +
|
||||
wvcdm::b2a_hex(key_id) ).c_str());
|
||||
LOGI(( "Select Key: key = " +
|
||||
wvcdm::b2a_hex(content_key->value()) ).c_str());
|
||||
if (content_key) {
|
||||
LOGI(( "Select Key: key = " +
|
||||
wvcdm::b2a_hex(content_key->value()) ).c_str());
|
||||
} else {
|
||||
LOGI("Select Key: key = null.");
|
||||
}
|
||||
}
|
||||
if (NULL == content_key) {
|
||||
LOGE("[QueryKeyControlBlock(): No key matches key id]");
|
||||
@@ -1187,8 +1199,7 @@ CryptoEngine::~CryptoEngine() {
|
||||
if (usage_table_) delete usage_table_;
|
||||
}
|
||||
|
||||
void CryptoEngine::Terminate() {
|
||||
}
|
||||
void CryptoEngine::Terminate() {}
|
||||
|
||||
KeyboxError CryptoEngine::ValidateKeybox() { return keybox().Validate(); }
|
||||
|
||||
@@ -1271,16 +1282,16 @@ bool CryptoEngine::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
|
||||
return false;
|
||||
}
|
||||
switch (RSA_check_key(rsa_key_)) {
|
||||
case 1: // valid.
|
||||
return true;
|
||||
case 0: // not valid.
|
||||
LOGE("[LoadPkcs8RsaKey(): rsa key not valid]");
|
||||
dump_openssl_error();
|
||||
return false;
|
||||
default: // -1 == check failed.
|
||||
LOGE("[LoadPkcs8RsaKey(): error checking rsa key]");
|
||||
dump_openssl_error();
|
||||
return false;
|
||||
case 1: // valid.
|
||||
return true;
|
||||
case 0: // not valid.
|
||||
LOGE("[LoadPkcs8RsaKey(): rsa key not valid]");
|
||||
dump_openssl_error();
|
||||
return false;
|
||||
default: // -1 == check failed.
|
||||
LOGE("[LoadPkcs8RsaKey(): error checking rsa key]");
|
||||
dump_openssl_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1298,18 +1309,19 @@ bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
|
||||
memcpy(iv_buffer, &iv[0], 16);
|
||||
AES_KEY aes_key;
|
||||
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(&message[0], &(decrypted->front()), message.size(),
|
||||
&aes_key, iv_buffer, AES_DECRYPT);
|
||||
AES_cbc_encrypt(&message[0], &(decrypted->front()), message.size(), &aes_key,
|
||||
iv_buffer, AES_DECRYPT);
|
||||
return true;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::DecryptCTR(
|
||||
const uint8_t* iv, size_t block_offset, const uint8_t* cipher_data,
|
||||
OEMCryptoResult SessionContext::DecryptCENC(
|
||||
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,
|
||||
OEMCryptoBufferType buffer_type) {
|
||||
// If the data is clear, we do not need a current key selected.
|
||||
if (!is_encrypted) {
|
||||
if (buffer_type != OEMCrypto_BufferType_Direct){
|
||||
if (buffer_type != OEMCrypto_BufferType_Direct) {
|
||||
memcpy(reinterpret_cast<uint8_t*>(clear_data), cipher_data,
|
||||
cipher_data_length);
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -1375,13 +1387,105 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
||||
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).
|
||||
// Allocated as 64-bit ints to enforce 64-bit alignment for later access as a
|
||||
// 64-bit value.
|
||||
uint64_t aes_iv[2];
|
||||
assert(sizeof(aes_iv) == AES_BLOCK_SIZE);
|
||||
// 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));
|
||||
memcpy(aes_iv_u8, &iv[0], AES_BLOCK_SIZE);
|
||||
|
||||
@@ -1391,7 +1495,6 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
||||
// why we implement the CTR loop ourselves.
|
||||
size_t l = 0;
|
||||
if (block_offset > 0 && l < cipher_data_length) {
|
||||
|
||||
// Encrypt the IV.
|
||||
uint8_t ecount_buf[AES_BLOCK_SIZE];
|
||||
|
||||
@@ -1402,7 +1505,7 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
||||
}
|
||||
AES_encrypt(aes_iv_u8, ecount_buf, &aes_key);
|
||||
for (int n = block_offset; n < AES_BLOCK_SIZE && l < cipher_data_length;
|
||||
++n, ++l) {
|
||||
++n, ++l) {
|
||||
clear_data[l] = cipher_data[l] ^ ecount_buf[n];
|
||||
}
|
||||
ctr128_inc64(aes_iv_u8);
|
||||
@@ -1443,8 +1546,8 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
||||
remaining = cipher_data_length - l;
|
||||
|
||||
int final;
|
||||
if (!EVP_DecryptFinal_ex(&ctx, &clear_data[cipher_data_length - remaining],
|
||||
&final)) {
|
||||
if (!EVP_DecryptFinal_ex(
|
||||
&ctx, &clear_data[cipher_data_length - remaining], & final)) {
|
||||
LOGE("[DecryptCTR(): EVP_FINAL_ERROR]");
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user