Combine Decrypt Unit Tests.
This commit is contained in:
@@ -71,6 +71,7 @@ static const size_t KEY_ID_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 AES_128_BLOCK_SIZE = 16;
|
||||
static const size_t MAC_KEY_SIZE = 32;
|
||||
static const size_t KEYBOX_KEY_DATA_SIZE = 72;
|
||||
static const size_t SRM_REQUIREMENT_SIZE = 12;
|
||||
|
||||
@@ -226,7 +226,7 @@ OEMCryptoResult CryptoEngine::SetDestination(
|
||||
default:
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
size_t max_allowed = max_output_size();
|
||||
size_t max_allowed = max_sample_size();
|
||||
if (max_allowed > 0 &&
|
||||
(max_allowed < max_length || max_allowed < data_length)) {
|
||||
LOGE("Output too large (or buffer too small).");
|
||||
|
||||
@@ -154,14 +154,14 @@ class CryptoEngine {
|
||||
// been applied to the device that fixes a security bug.
|
||||
virtual uint8_t config_security_patch_level() { return 0; }
|
||||
|
||||
// If 0 no restriction, otherwise it's the max buffer for DecryptCENC.
|
||||
// This is the same as the max subsample size, not the sample or frame size.
|
||||
virtual size_t max_buffer_size() { return 1024 * 100; } // 100 KiB.
|
||||
// If 0 no restriction, otherwise it's the max subsample size for
|
||||
// DecryptCENC. This is not the same as the max sample or buffer size.
|
||||
virtual size_t max_subsample_size() { return 1024 * 100; } // 100 KiB
|
||||
|
||||
// If 0 no restriction, otherwise it's the max output buffer for DecryptCENC
|
||||
// and CopyBuffer. This is the same as the max frame or sample size, not the
|
||||
// subsample size.
|
||||
virtual size_t max_output_size() { return 0; }
|
||||
// If 0 no restriction, otherwise it's the max sample size for DecryptCENC.
|
||||
// This is the same as the max input and output buffer size for DecryptCENC
|
||||
// and CopyBuffer. It is not the same as the max subsample size.
|
||||
virtual size_t max_sample_size() { return 1024 * 1024; } // 1 MiB
|
||||
|
||||
virtual bool srm_update_supported() { return false; }
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
#include "OEMCryptoCENC.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
@@ -51,6 +52,41 @@ uint32_t unaligned_dereference_uint32(const void* unaligned_ptr) {
|
||||
return value;
|
||||
}
|
||||
|
||||
void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
|
||||
switch (dest_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
dest_buffer->buffer.clear.address += bytes;
|
||||
dest_buffer->buffer.clear.address_length -= bytes;
|
||||
break;
|
||||
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
dest_buffer->buffer.secure.offset += bytes;
|
||||
break;
|
||||
|
||||
case OEMCrypto_BufferType_Direct:
|
||||
// Nothing to do for this buffer type.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Advance an IV according to ISO-CENC's CTR modes. The lower half of the IV is
|
||||
// split off and treated as an unsigned 64-bit integer, then incremented by the
|
||||
// number of complete crypto blocks decrypted. The resulting value is then
|
||||
// copied back into the IV over the previous lower half.
|
||||
void advance_iv_ctr(uint8_t (*subsample_iv)[wvoec::KEY_IV_SIZE], size_t bytes) {
|
||||
uint64_t counter;
|
||||
assert(sizeof(*subsample_iv) == wvoec::KEY_IV_SIZE);
|
||||
assert(sizeof(counter) * 2 == sizeof(*subsample_iv));
|
||||
static const size_t half_iv_size = wvoec::KEY_IV_SIZE / 2;
|
||||
memcpy(&counter, &(*subsample_iv)[half_iv_size], half_iv_size);
|
||||
|
||||
size_t increment =
|
||||
bytes / wvoec::AES_128_BLOCK_SIZE; // The truncation here is intentional
|
||||
counter = wvcdm::htonll64(wvcdm::ntohll64(counter) + increment);
|
||||
|
||||
memcpy(&(*subsample_iv)[half_iv_size], &counter, half_iv_size);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvoec_ref {
|
||||
@@ -579,40 +615,21 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_SelectKey(
|
||||
return session_ctx->SelectContentKey(key_id_str, cipher_mode);
|
||||
}
|
||||
|
||||
OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC_V15(
|
||||
OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length,
|
||||
bool is_encrypted, const uint8_t* iv, size_t block_offset,
|
||||
OEMCrypto_DestBufferDesc* out_buffer_descriptor,
|
||||
const OEMCrypto_CENCEncryptPatternDesc_V15* pattern,
|
||||
uint8_t subsample_flags) {
|
||||
OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC(
|
||||
OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples,
|
||||
size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern) {
|
||||
if (crypto_engine == nullptr) {
|
||||
LOGE("OEMCrypto_DecryptCENC: OEMCrypto Not Initialized.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (data_addr == nullptr || data_length == 0 || iv == nullptr ||
|
||||
out_buffer_descriptor == nullptr) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
if (samples == nullptr || samples_length == 0) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): No samples]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (crypto_engine->max_buffer_size() > 0 &&
|
||||
data_length > crypto_engine->max_buffer_size()) {
|
||||
// For testing reasons only, pretend that this integration only supports
|
||||
// the minimum possible buffer size.
|
||||
LOGE("[OEMCrypto_DecryptCENC(): OEMCrypto_ERROR_BUFFER_TOO_LARGE]");
|
||||
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
|
||||
if (pattern == nullptr) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): No pattern]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
OEMCryptoResult status = crypto_engine->SetDestination(
|
||||
*out_buffer_descriptor, data_length, subsample_flags);
|
||||
if (status != OEMCrypto_SUCCESS) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): destination status: %d]", status);
|
||||
return status;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
if (!crypto_engine->ValidRootOfTrust()) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
#endif
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (session_ctx == nullptr || !session_ctx->isValid()) {
|
||||
@@ -620,13 +637,107 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC_V15(
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
OEMCryptoResult result = session_ctx->DecryptCENC_V15(
|
||||
iv, block_offset, pattern, data_addr, data_length, is_encrypted,
|
||||
crypto_engine->destination(), out_buffer_descriptor->type,
|
||||
subsample_flags);
|
||||
if (result != OEMCrypto_SUCCESS) return result;
|
||||
return crypto_engine->PushDestination(*out_buffer_descriptor,
|
||||
subsample_flags);
|
||||
// Iterate through all the samples and validate them before doing any decrypt
|
||||
for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) {
|
||||
const OEMCrypto_SampleDescription& sample = samples[sample_index];
|
||||
|
||||
if (sample.buffers.input_data == nullptr ||
|
||||
sample.buffers.input_data_length == 0) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (crypto_engine->max_sample_size() > 0 &&
|
||||
sample.buffers.input_data_length > crypto_engine->max_sample_size()) {
|
||||
// For testing reasons only, pretend that this integration only supports
|
||||
// the given buffer size.
|
||||
LOGE("[OEMCrypto_DecryptCENC(): Sample too large]");
|
||||
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
|
||||
}
|
||||
|
||||
// Iterate through all the subsamples and sum their lengths
|
||||
size_t subsample_length_tally = 0;
|
||||
for (size_t subsample_index = 0; subsample_index < sample.subsamples_length;
|
||||
++subsample_index) {
|
||||
const OEMCrypto_SubSampleDescription& subsample =
|
||||
sample.subsamples[subsample_index];
|
||||
const size_t length =
|
||||
subsample.num_bytes_clear + subsample.num_bytes_encrypted;
|
||||
if (crypto_engine->max_subsample_size() > 0 &&
|
||||
length > crypto_engine->max_subsample_size()) {
|
||||
// For testing reasons only, pretend that this integration only supports
|
||||
// the given buffer size.
|
||||
LOGE("[OEMCrypto_DecryptCENC(): Subsample too large]");
|
||||
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
|
||||
}
|
||||
subsample_length_tally += length;
|
||||
}
|
||||
if (subsample_length_tally != sample.buffers.input_data_length) {
|
||||
LOGE(
|
||||
"[OEMCrypto_DecryptCENC(): Sample and subsample lengths do not "
|
||||
"match.]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through all the samples and decrypt each one
|
||||
for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) {
|
||||
const OEMCrypto_SampleDescription& sample = samples[sample_index];
|
||||
|
||||
// Iterate through all the subsamples and decrypt each one
|
||||
const uint8_t* subsample_source = sample.buffers.input_data;
|
||||
OEMCrypto_DestBufferDesc subsample_dest = sample.buffers.output_descriptor;
|
||||
uint8_t subsample_iv[wvoec::KEY_IV_SIZE];
|
||||
assert(sizeof(sample.iv) == wvoec::KEY_IV_SIZE);
|
||||
assert(sizeof(subsample_iv) == wvoec::KEY_IV_SIZE);
|
||||
memcpy(&subsample_iv[0], &sample.iv[0], wvoec::KEY_IV_SIZE);
|
||||
for (size_t subsample_index = 0; subsample_index < sample.subsamples_length;
|
||||
++subsample_index) {
|
||||
const OEMCrypto_SubSampleDescription& subsample =
|
||||
sample.subsamples[subsample_index];
|
||||
const size_t subsample_length =
|
||||
subsample.num_bytes_clear + subsample.num_bytes_encrypted;
|
||||
|
||||
OEMCryptoResult result = crypto_engine->SetDestination(
|
||||
subsample_dest, subsample_length, subsample.subsample_flags);
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): SetDestination status: %d]", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!crypto_engine->ValidRootOfTrust()) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
#endif
|
||||
|
||||
result = session_ctx->DecryptSubsample(
|
||||
subsample, subsample_source, crypto_engine->destination(),
|
||||
subsample_dest.type, subsample_iv, pattern);
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): DecryptSubsample status: %d]", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = crypto_engine->PushDestination(subsample_dest,
|
||||
subsample.subsample_flags);
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
LOGE("[OEMCrypto_DecryptCENC(): PushDestination status: %d]", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Advance the source buffer, the dest buffer, and (if necessary) the IV
|
||||
subsample_source += subsample_length;
|
||||
advance_dest_buffer(&subsample_dest, subsample_length);
|
||||
if (subsample.num_bytes_encrypted > 0 &&
|
||||
session_ctx->current_content_key()->ctr_mode()) {
|
||||
advance_iv_ctr(&subsample_iv,
|
||||
subsample.block_offset + subsample.num_bytes_encrypted);
|
||||
}
|
||||
} // Subsample loop
|
||||
} // Sample loop
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyBuffer(
|
||||
@@ -641,8 +752,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyBuffer(
|
||||
LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (crypto_engine->max_buffer_size() > 0 &&
|
||||
data_length > crypto_engine->max_buffer_size()) {
|
||||
if (crypto_engine->max_sample_size() > 0 &&
|
||||
data_length > crypto_engine->max_sample_size()) {
|
||||
// For testing reasons only, pretend that this integration only supports
|
||||
// the minimum possible buffer size.
|
||||
LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_BUFFER_TOO_LARGE]");
|
||||
|
||||
@@ -1484,15 +1484,29 @@ bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
|
||||
return true;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::DecryptCENC_V15(
|
||||
const uint8_t* iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc_V15* pattern,
|
||||
const uint8_t* cipher_data, size_t cipher_data_length, bool is_encrypted,
|
||||
OEMCryptoResult SessionContext::DecryptSubsample(
|
||||
const OEMCrypto_SubSampleDescription& subsample, const uint8_t* cipher_data,
|
||||
uint8_t* clear_data, OEMCryptoBufferType buffer_type,
|
||||
uint8_t subsample_flags) {
|
||||
OEMCryptoResult result =
|
||||
ChooseDecrypt(iv, block_offset, pattern, cipher_data, cipher_data_length,
|
||||
is_encrypted, clear_data, buffer_type);
|
||||
const uint8_t iv[wvoec::KEY_IV_SIZE],
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
|
||||
// Handle the clear portion of the subsample.
|
||||
if (subsample.num_bytes_clear > 0) {
|
||||
if (buffer_type != OEMCrypto_BufferType_Direct) {
|
||||
memmove(clear_data, cipher_data, subsample.num_bytes_clear);
|
||||
}
|
||||
// For the reference implementation, we quietly drop the clear direct video.
|
||||
}
|
||||
|
||||
// Handle the encrypted portion of the subsample.
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
if (subsample.num_bytes_encrypted > 0) {
|
||||
const uint8_t* source = cipher_data + subsample.num_bytes_clear;
|
||||
uint8_t* dest = clear_data + subsample.num_bytes_clear;
|
||||
result = ChooseDecrypt(iv, subsample.block_offset, pattern, source,
|
||||
subsample.num_bytes_encrypted, dest, buffer_type);
|
||||
}
|
||||
|
||||
// Compute hash for FDPT.
|
||||
if (compute_hash_) {
|
||||
if (current_content_key() == nullptr ||
|
||||
(current_content_key()->control().control_bits() &
|
||||
@@ -1503,12 +1517,13 @@ OEMCryptoResult SessionContext::DecryptCENC_V15(
|
||||
current_hash_ = 0;
|
||||
current_frame_number_ = 0;
|
||||
} else {
|
||||
if (OEMCrypto_FirstSubsample & subsample_flags) {
|
||||
if (OEMCrypto_FirstSubsample & subsample.subsample_flags) {
|
||||
current_hash_ = wvcrc32Init();
|
||||
}
|
||||
current_hash_ =
|
||||
wvcrc32Cont(clear_data, cipher_data_length, current_hash_);
|
||||
if (OEMCrypto_LastSubsample & subsample_flags) {
|
||||
current_hash_ = wvcrc32Cont(
|
||||
clear_data, subsample.num_bytes_clear + subsample.num_bytes_encrypted,
|
||||
current_hash_);
|
||||
if (OEMCrypto_LastSubsample & subsample.subsample_flags) {
|
||||
if (current_hash_ != given_hash_) {
|
||||
LOGE("CRC for frame %d is %08x, should be %08x\n",
|
||||
current_frame_number_, current_hash_, given_hash_);
|
||||
@@ -1522,25 +1537,17 @@ OEMCryptoResult SessionContext::DecryptCENC_V15(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the result of the previous ChooseDecrypt() call after computing the
|
||||
// hash.
|
||||
return result;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::ChooseDecrypt(
|
||||
const uint8_t* iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc_V15* 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) {
|
||||
memmove(reinterpret_cast<uint8_t*>(clear_data), cipher_data,
|
||||
cipher_data_length);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
// For reference implementation, we quietly drop the clear direct video.
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, uint8_t* clear_data,
|
||||
OEMCryptoBufferType buffer_type) {
|
||||
// Check there is a content key
|
||||
if (current_content_key() == nullptr) {
|
||||
LOGE("[DecryptCTR(): OEMCrypto_ERROR_NO_CONTENT_KEY]");
|
||||
@@ -1565,41 +1572,42 @@ OEMCryptoResult SessionContext::ChooseDecrypt(
|
||||
}
|
||||
|
||||
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,
|
||||
if (block_offset > 0 || pattern->encrypt == 0) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
return PatternDecryptCBC(key_u8, iv, pattern, cipher_data,
|
||||
cipher_data_length, clear_data);
|
||||
} else {
|
||||
if (pattern->skip != 0 || pattern->encrypt != 0) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
return DecryptCTR(key_u8, iv, block_offset, 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(
|
||||
OEMCryptoResult SessionContext::PatternDecryptCBC(
|
||||
const uint8_t* key, const uint8_t* initial_iv,
|
||||
const OEMCrypto_CENCEncryptPatternDesc_V15* pattern,
|
||||
const uint8_t* cipher_data, size_t cipher_data_length,
|
||||
uint8_t* clear_data) {
|
||||
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];
|
||||
uint8_t next_iv[AES_BLOCK_SIZE];
|
||||
memcpy(iv, &initial_iv[0], AES_BLOCK_SIZE);
|
||||
|
||||
const size_t pattern_length = pattern->encrypt + pattern->skip;
|
||||
if (pattern_length <= 0) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
|
||||
size_t l = 0;
|
||||
// TODO(b/135285640): remove this.
|
||||
size_t pattern_offset = 0;
|
||||
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;
|
||||
}
|
||||
bool skip_block = (pattern_offset >= pattern->encrypt);
|
||||
pattern_offset = (pattern_offset + 1) % pattern_length;
|
||||
// TODO(b/140503351): The (size < AES_BLOCK_SIZE) check is not correct for
|
||||
// patterns where (pattern.encrypt > 1).
|
||||
if (skip_block || (size < AES_BLOCK_SIZE)) {
|
||||
memmove(&clear_data[l], &cipher_data[l], size);
|
||||
} else {
|
||||
@@ -1618,46 +1626,6 @@ OEMCryptoResult SessionContext::DecryptCBC(
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::PatternDecryptCTR(
|
||||
const uint8_t* key, const uint8_t* initial_iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc_V15* 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;
|
||||
// TODO(b/135285640): remove this.
|
||||
size_t pattern_offset = 0;
|
||||
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) {
|
||||
memmove(&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,
|
||||
|
||||
@@ -96,12 +96,11 @@ class SessionContext {
|
||||
virtual bool ValidateMessage(const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
OEMCryptoResult DecryptCENC_V15(
|
||||
const uint8_t* iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc_V15* pattern,
|
||||
const uint8_t* cipher_data, size_t cipher_data_length, bool is_encrypted,
|
||||
uint8_t* clear_data, OEMCryptoBufferType buffer_type,
|
||||
uint8_t subsample_flags);
|
||||
OEMCryptoResult DecryptSubsample(
|
||||
const OEMCrypto_SubSampleDescription& subsample,
|
||||
const uint8_t* cipher_data, uint8_t* clear_data,
|
||||
OEMCryptoBufferType buffer_type, const uint8_t iv[wvoec::KEY_IV_SIZE],
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||
|
||||
OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer,
|
||||
size_t buffer_length, const uint8_t* iv,
|
||||
@@ -237,19 +236,14 @@ class SessionContext {
|
||||
OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control);
|
||||
// Check that the usage entry status is valid for offline use.
|
||||
OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control);
|
||||
OEMCryptoResult ChooseDecrypt(
|
||||
const uint8_t* iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc_V15* pattern,
|
||||
const uint8_t* cipher_data, size_t cipher_data_length, bool is_encrypted,
|
||||
uint8_t* clear_data, OEMCryptoBufferType buffer_type);
|
||||
OEMCryptoResult DecryptCBC(
|
||||
OEMCryptoResult ChooseDecrypt(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,
|
||||
OEMCryptoBufferType buffer_type);
|
||||
OEMCryptoResult PatternDecryptCBC(
|
||||
const uint8_t* key, const uint8_t* iv,
|
||||
const OEMCrypto_CENCEncryptPatternDesc_V15* 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_V15* pattern,
|
||||
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,
|
||||
|
||||
177
oemcrypto/test/oec_decrypt_fallback_chain.cpp
Normal file
177
oemcrypto/test/oec_decrypt_fallback_chain.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include "oec_decrypt_fallback_chain.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "oemcrypto_types.h"
|
||||
#include "string_conversions.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
|
||||
switch (dest_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
dest_buffer->buffer.clear.address += bytes;
|
||||
dest_buffer->buffer.clear.address_length -= bytes;
|
||||
break;
|
||||
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
dest_buffer->buffer.secure.offset += bytes;
|
||||
break;
|
||||
|
||||
case OEMCrypto_BufferType_Direct:
|
||||
// Nothing to do for this buffer type.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void advance_iv_ctr(uint8_t (*subsample_iv)[wvoec::KEY_IV_SIZE], size_t bytes) {
|
||||
uint64_t counter;
|
||||
constexpr size_t half_iv_size = wvoec::KEY_IV_SIZE / 2;
|
||||
memcpy(&counter, &(*subsample_iv)[half_iv_size], half_iv_size);
|
||||
|
||||
size_t increment =
|
||||
bytes / wvoec::AES_128_BLOCK_SIZE; // The truncation here is intentional
|
||||
counter = wvcdm::htonll64(wvcdm::ntohll64(counter) + increment);
|
||||
|
||||
memcpy(&(*subsample_iv)[half_iv_size], &counter, half_iv_size);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
// Decrypts the given array of samples. Handles fallback behavior correctly if
|
||||
// the OEMCrypto implementation does not accept multiple samples.
|
||||
OEMCryptoResult DecryptFallbackChain::Decrypt(
|
||||
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription* samples,
|
||||
size_t samples_length, OEMCryptoCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
|
||||
OEMCryptoResult sts =
|
||||
OEMCrypto_DecryptCENC(session_id, samples, samples_length, pattern);
|
||||
|
||||
// No need for a fallback. Abort early.
|
||||
if (sts != OEMCrypto_ERROR_BUFFER_TOO_LARGE) return sts;
|
||||
|
||||
// Fall back to decrypting individual samples.
|
||||
for (size_t i = 0; i < samples_length; ++i) {
|
||||
sts = DecryptSample(session_id, samples[i], cipher_mode, pattern);
|
||||
if (sts != OEMCrypto_SUCCESS) return sts;
|
||||
}
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
// Decrypts the given sample. Handles fallback behavior correctly if the
|
||||
// OEMCrypto implementation does not accept full samples.
|
||||
OEMCryptoResult DecryptFallbackChain::DecryptSample(
|
||||
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
|
||||
OEMCryptoCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
|
||||
OEMCryptoResult sts = OEMCrypto_DecryptCENC(session_id, &sample, 1, pattern);
|
||||
|
||||
// No need for a fallback. Abort early.
|
||||
if (sts != OEMCrypto_ERROR_BUFFER_TOO_LARGE) return sts;
|
||||
|
||||
// Fall back to decrypting individual subsamples.
|
||||
OEMCrypto_SampleDescription fake_sample = sample;
|
||||
for (size_t i = 0; i < sample.subsamples_length; ++i) {
|
||||
const OEMCrypto_SubSampleDescription& subsample = sample.subsamples[i];
|
||||
|
||||
size_t length = subsample.num_bytes_clear + subsample.num_bytes_encrypted;
|
||||
fake_sample.buffers.input_data_length = length;
|
||||
fake_sample.subsamples = &subsample;
|
||||
fake_sample.subsamples_length = 1;
|
||||
|
||||
sts = DecryptSubsample(session_id, fake_sample, pattern);
|
||||
if (sts != OEMCrypto_SUCCESS) return sts;
|
||||
|
||||
fake_sample.buffers.input_data += length;
|
||||
advance_dest_buffer(&fake_sample.buffers.output_descriptor, length);
|
||||
if (cipher_mode == OEMCrypto_CipherMode_CTR) {
|
||||
advance_iv_ctr(&fake_sample.iv,
|
||||
subsample.block_offset + subsample.num_bytes_encrypted);
|
||||
}
|
||||
}
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
// Decrypts the given subsample. Handles fallback behavior correctly if the
|
||||
// OEMCrypto implementation does not accept full subsamples.
|
||||
OEMCryptoResult DecryptFallbackChain::DecryptSubsample(
|
||||
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
|
||||
OEMCryptoResult sts = OEMCrypto_DecryptCENC(session_id, &sample, 1, pattern);
|
||||
|
||||
// No need for a fallback. Abort early.
|
||||
if (sts != OEMCrypto_ERROR_BUFFER_TOO_LARGE) return sts;
|
||||
|
||||
// Fall back to decrypting individual subsample halves.
|
||||
const OEMCrypto_SubSampleDescription& subsample = sample.subsamples[0];
|
||||
OEMCrypto_SampleDescription fake_sample = sample;
|
||||
OEMCrypto_SubSampleDescription fake_subsample;
|
||||
fake_sample.subsamples = &fake_subsample;
|
||||
fake_sample.subsamples_length = 1;
|
||||
|
||||
if (subsample.num_bytes_clear > 0) {
|
||||
fake_sample.buffers.input_data_length = subsample.num_bytes_clear;
|
||||
fake_subsample.num_bytes_clear = subsample.num_bytes_clear;
|
||||
fake_subsample.num_bytes_encrypted = 0;
|
||||
fake_subsample.block_offset = 0;
|
||||
|
||||
fake_subsample.subsample_flags = 0;
|
||||
if (subsample.subsample_flags & OEMCrypto_FirstSubsample)
|
||||
fake_subsample.subsample_flags |= OEMCrypto_FirstSubsample;
|
||||
if (subsample.subsample_flags & OEMCrypto_LastSubsample &&
|
||||
subsample.num_bytes_encrypted == 0)
|
||||
fake_subsample.subsample_flags |= OEMCrypto_LastSubsample;
|
||||
|
||||
sts = DecryptSubsampleHalf(session_id, fake_sample, pattern);
|
||||
if (sts != OEMCrypto_SUCCESS) return sts;
|
||||
|
||||
// Advance the buffers for the other half, in case they're needed.
|
||||
fake_sample.buffers.input_data += subsample.num_bytes_clear;
|
||||
advance_dest_buffer(&fake_sample.buffers.output_descriptor,
|
||||
subsample.num_bytes_clear);
|
||||
}
|
||||
|
||||
if (subsample.num_bytes_encrypted > 0) {
|
||||
fake_sample.buffers.input_data_length = subsample.num_bytes_encrypted;
|
||||
fake_subsample.num_bytes_clear = 0;
|
||||
fake_subsample.num_bytes_encrypted = subsample.num_bytes_encrypted;
|
||||
fake_subsample.block_offset = subsample.block_offset;
|
||||
|
||||
fake_subsample.subsample_flags = 0;
|
||||
if (subsample.subsample_flags & OEMCrypto_FirstSubsample &&
|
||||
subsample.num_bytes_clear == 0)
|
||||
fake_subsample.subsample_flags |= OEMCrypto_FirstSubsample;
|
||||
if (subsample.subsample_flags & OEMCrypto_LastSubsample)
|
||||
fake_subsample.subsample_flags |= OEMCrypto_LastSubsample;
|
||||
|
||||
sts = DecryptSubsampleHalf(session_id, fake_sample, pattern);
|
||||
if (sts != OEMCrypto_SUCCESS) return sts;
|
||||
}
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
// Decrypts the given subsample half. There is no fallback behavior after this;
|
||||
// an OEMCrypto_ERROR_BUFFER_TOO_LARGE produced here will be returned to the
|
||||
// caller.
|
||||
OEMCryptoResult DecryptFallbackChain::DecryptSubsampleHalf(
|
||||
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern) {
|
||||
return OEMCrypto_DecryptCENC(session_id, &sample, 1, pattern);
|
||||
// In a real CDM, you would want some fallback here to handle the case where
|
||||
// the buffer is too big for the OEMCrypto implementation. But in the case of
|
||||
// the tests, we won't be passing a buffer that's too big unless we are trying
|
||||
// to test that failure condition, so there's no need to handle that case
|
||||
// here.
|
||||
}
|
||||
|
||||
} // namespace wvoec
|
||||
59
oemcrypto/test/oec_decrypt_fallback_chain.h
Normal file
59
oemcrypto/test/oec_decrypt_fallback_chain.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#ifndef CDM_OEC_DECRYPT_FALLBACK_CHAIN_H_
|
||||
#define CDM_OEC_DECRYPT_FALLBACK_CHAIN_H_
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "disallow_copy_and_assign.h"
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
// This class groups static methods relating to providing proper fallback
|
||||
// behavior when calling DecryptCENC in OEMCrypto v16. Outside code can leverage
|
||||
// this behavior by passing the samples to be decrypted to Decrypt(), which will
|
||||
// set off the chain of fallback functions as needed.
|
||||
//
|
||||
// The behavior of this class is pathological. For each block of data, it will
|
||||
// greedily try every possible way of passing data to OEMCrypto until one works.
|
||||
// In the order tried, the ways to send data are:
|
||||
// 1) Multiple Samples at once
|
||||
// 2) Individual Samples one at a time
|
||||
// 3) Individual Subsamples one at a time
|
||||
// 4) Individual Half-Subsamples one at a time
|
||||
// On a device that only accepts half-subsamples, the way OEMCrypto v15 did,
|
||||
// this results in many needless roundtrips to OEMCrypto. This would be
|
||||
// inefficient behavior for a real CDM, but for the sake of testing, we want to
|
||||
// use the maximal way the OEMCrypto implementation will accept the data. And,
|
||||
// for implementations that do not accept multiple samples or subsamples per
|
||||
// call, we want to test that they correctly reject larger calls.
|
||||
class DecryptFallbackChain {
|
||||
public:
|
||||
static OEMCryptoResult Decrypt(
|
||||
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription* samples,
|
||||
size_t samples_length, OEMCryptoCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||
|
||||
private:
|
||||
static OEMCryptoResult DecryptSample(
|
||||
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
|
||||
OEMCryptoCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||
|
||||
static OEMCryptoResult DecryptSubsample(
|
||||
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||
|
||||
static OEMCryptoResult DecryptSubsampleHalf(
|
||||
OEMCrypto_SESSION session_id, const OEMCrypto_SampleDescription& sample,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||
|
||||
// There is no reason to have an instance of this class.
|
||||
DecryptFallbackChain() = delete;
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(DecryptFallbackChain);
|
||||
};
|
||||
|
||||
} // namespace wvoec
|
||||
|
||||
#endif // CDM_OEC_DECRYPT_FALLBACK_CHAIN_H_
|
||||
@@ -51,6 +51,8 @@ void DeleteX509Stack(STACK_OF(X509)* stack) {
|
||||
sk_X509_pop_free(stack, X509_free);
|
||||
}
|
||||
|
||||
constexpr size_t kTestSubsampleSectionSize = 256;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvoec {
|
||||
@@ -60,6 +62,39 @@ int GetRandBytes(unsigned char* buf, int num) {
|
||||
return RAND_bytes(buf, num);
|
||||
}
|
||||
|
||||
// Does the boilerplate to fill out sample and subsample descriptions for
|
||||
// decrypting a single contiguous block of encrypted data to clear memory, which
|
||||
// is a common operation for tests. Generates a random IV which can be used to
|
||||
// encrypt the input buffer.
|
||||
void GenerateSimpleSampleDescription(
|
||||
const uint8_t* input_data, size_t input_data_length, uint8_t* output_buffer,
|
||||
size_t output_buffer_length, OEMCrypto_SampleDescription* sample,
|
||||
OEMCrypto_SubSampleDescription* subsample) {
|
||||
ASSERT_NE(nullptr, sample);
|
||||
ASSERT_NE(nullptr, subsample);
|
||||
|
||||
// Generate test data
|
||||
EXPECT_EQ(1, GetRandBytes(&sample->iv[0], KEY_IV_SIZE));
|
||||
|
||||
// Describe the test data
|
||||
sample->buffers.input_data = input_data;
|
||||
sample->buffers.input_data_length = input_data_length;
|
||||
subsample->num_bytes_clear = 0;
|
||||
subsample->num_bytes_encrypted = input_data_length;
|
||||
subsample->subsample_flags =
|
||||
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample;
|
||||
subsample->block_offset = 0;
|
||||
sample->subsamples = subsample;
|
||||
sample->subsamples_length = 1;
|
||||
|
||||
// Describe the output
|
||||
OEMCrypto_DestBufferDesc& out_buffer_descriptor =
|
||||
sample->buffers.output_descriptor;
|
||||
out_buffer_descriptor.type = OEMCrypto_BufferType_Clear;
|
||||
out_buffer_descriptor.buffer.clear.address = output_buffer;
|
||||
out_buffer_descriptor.buffer.clear.address_length = output_buffer_length;
|
||||
}
|
||||
|
||||
// Increment counter for AES-CTR. The CENC spec specifies we increment only
|
||||
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This
|
||||
// is different from the BoringSSL implementation, so we implement the CTR loop
|
||||
@@ -1445,43 +1480,35 @@ void Session::TestDecryptCTR(bool select_key_first,
|
||||
}
|
||||
}
|
||||
|
||||
vector<uint8_t> unencryptedData(256);
|
||||
for (size_t i = 0; i < unencryptedData.size(); i++)
|
||||
unencryptedData[i] = i % 256;
|
||||
EXPECT_EQ(1, GetRandBytes(unencryptedData.data(), unencryptedData.size()));
|
||||
vector<uint8_t> encryptionIv(KEY_IV_SIZE);
|
||||
EXPECT_EQ(1, GetRandBytes(encryptionIv.data(), KEY_IV_SIZE));
|
||||
vector<uint8_t> encryptedData(unencryptedData.size());
|
||||
EncryptCTR(unencryptedData, license_.keys[key_index].key_data,
|
||||
encryptionIv.data(), &encryptedData);
|
||||
// Create test sample description
|
||||
vector<uint8_t> unencrypted_data(kTestSubsampleSectionSize);
|
||||
vector<uint8_t> encrypted_data(unencrypted_data.size());
|
||||
vector<uint8_t> output_buffer(unencrypted_data.size());
|
||||
OEMCrypto_SampleDescription sample_description;
|
||||
OEMCrypto_SubSampleDescription subsample_description;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription(
|
||||
encrypted_data.data(), encrypted_data.size(), output_buffer.data(),
|
||||
output_buffer.size(), &sample_description, &subsample_description));
|
||||
|
||||
// Generate test data
|
||||
EXPECT_EQ(1, GetRandBytes(unencrypted_data.data(), unencrypted_data.size()));
|
||||
EncryptCTR(unencrypted_data, license_.keys[key_index].key_data,
|
||||
&sample_description.iv[0], &encrypted_data);
|
||||
|
||||
// Create the pattern description (always 0,0 for CTR)
|
||||
OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0};
|
||||
|
||||
// Describe the output
|
||||
vector<uint8_t> outputBuffer(256);
|
||||
OEMCrypto_DestBufferDesc out_buffer_descriptor;
|
||||
out_buffer_descriptor.type = OEMCrypto_BufferType_Clear;
|
||||
out_buffer_descriptor.buffer.clear.address = outputBuffer.data();
|
||||
out_buffer_descriptor.buffer.clear.address_length = outputBuffer.size();
|
||||
OEMCrypto_CENCEncryptPatternDesc pattern;
|
||||
pattern.encrypt = 0;
|
||||
pattern.skip = 0;
|
||||
// Decrypt the data
|
||||
#if 1 // TODO(b/135285640): Until the DecryptCENC is fixed, we
|
||||
// just copy the truth data to the outputBuffer, and claim success.
|
||||
sts = expected_result;
|
||||
if (expected_result == OEMCrypto_SUCCESS) outputBuffer = unencryptedData;
|
||||
#else
|
||||
sts = OEMCrypto_DecryptCENC(
|
||||
session_id(), encryptedData.data(), encryptedData.size(), true,
|
||||
encryptionIv.data(), 0, &out_buffer_descriptor, &pattern,
|
||||
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample);
|
||||
#endif
|
||||
sts = OEMCrypto_DecryptCENC(session_id(), &sample_description, 1, &pattern);
|
||||
|
||||
// We only have a few errors that we test are reported.
|
||||
if (expected_result == OEMCrypto_SUCCESS) { // No error.
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
ASSERT_EQ(unencryptedData, outputBuffer);
|
||||
ASSERT_EQ(unencrypted_data, output_buffer);
|
||||
} else {
|
||||
ASSERT_NO_FATAL_FAILURE(TestDecryptResult(expected_result, sts));
|
||||
ASSERT_NE(unencryptedData, outputBuffer);
|
||||
ASSERT_NE(unencrypted_data, output_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,13 @@ struct EntitledContentKeyData {
|
||||
// returns 1 on success, -1 if not supported, or 0 if other failure.
|
||||
int GetRandBytes(unsigned char* buf, int num);
|
||||
|
||||
void GenerateSimpleSampleDescription(const uint8_t* input_data,
|
||||
size_t input_data_length,
|
||||
uint8_t* output_buffer,
|
||||
size_t output_buffer_length,
|
||||
OEMCrypto_SampleDescription* sample,
|
||||
OEMCrypto_SubSampleDescription* subsample);
|
||||
|
||||
// Increment counter for AES-CTR. The CENC spec specifies we increment only
|
||||
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This
|
||||
// is different from the OpenSSL implementation, so we implement the CTR loop
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@
|
||||
{
|
||||
'sources': [
|
||||
'oec_device_features.cpp',
|
||||
'oec_decrypt_fallback_chain.cpp',
|
||||
'oec_key_deriver.cpp',
|
||||
'oec_session_util.cpp',
|
||||
'oemcrypto_session_tests_helper.cpp',
|
||||
|
||||
Reference in New Issue
Block a user