Clear Content Copy
Copy from Widevine repository of http://go/wvgerrit/13841 This CL adds a nonblocking CopyBuffer to OEMCrypto, its unit tests, and plumbs it up to the cdm CryptoSession and CdmEngine. b/19543782 Change-Id: I4c88bd2f8d7f67ecccb549c1934b7c0da15a8429
This commit is contained in:
@@ -1065,15 +1065,13 @@ bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
|
||||
OEMCryptoResult SessionContext::DecryptCTR(
|
||||
const uint8_t* iv, size_t block_offset, const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
|
||||
BufferType buffer_type) {
|
||||
OEMCryptoBufferType buffer_type) {
|
||||
// If the data is clear, we do not need a current key selected.
|
||||
if (!is_encrypted) {
|
||||
if (buffer_type != kBufferTypeDirect) {
|
||||
memcpy(reinterpret_cast<uint8_t*>(clear_data), cipher_data,
|
||||
cipher_data_length);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
// For reference implementation, we quietly drop the clear direct video.
|
||||
if (buffer_type == OEMCrypto_BufferType_Direct)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
memcpy(reinterpret_cast<uint8_t*>(clear_data), cipher_data,
|
||||
cipher_data_length);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1084,7 +1082,7 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
||||
}
|
||||
const KeyControlBlock& control = current_content_key()->control();
|
||||
if (control.control_bits() & kControlDataPathSecure) {
|
||||
if (!ce_->closed_platform() && buffer_type == kBufferTypeClear) {
|
||||
if (!ce_->closed_platform() && buffer_type == OEMCrypto_BufferType_Clear) {
|
||||
LOGE("[DecryptCTR(): Secure key with insecure buffer]");
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
@@ -1129,12 +1127,12 @@ OEMCryptoResult SessionContext::DecryptCTR(
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
|
||||
if (buffer_type == kBufferTypeDirect) {
|
||||
if (buffer_type == OEMCrypto_BufferType_Direct) {
|
||||
// For reference implementation, we quietly drop the decrypted direct video.
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
if (buffer_type == kBufferTypeSecure) {
|
||||
if (buffer_type == OEMCrypto_BufferType_Secure) {
|
||||
// For reference implementation, we also quietly drop secure data.
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
enum BufferType {
|
||||
kBufferTypeClear,
|
||||
kBufferTypeSecure,
|
||||
kBufferTypeDirect
|
||||
};
|
||||
|
||||
class SessionContext;
|
||||
class CryptoEngine;
|
||||
class UsageTable;
|
||||
@@ -117,7 +111,8 @@ class SessionContext {
|
||||
OEMCryptoResult DecryptCTR(const uint8_t* iv, size_t block_offset,
|
||||
const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, bool is_encrypted,
|
||||
uint8_t* clear_data, BufferType buffer_type);
|
||||
uint8_t* clear_data,
|
||||
OEMCryptoBufferType buffer_type);
|
||||
|
||||
OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer,
|
||||
size_t buffer_length, const uint8_t* iv,
|
||||
|
||||
@@ -522,6 +522,40 @@ OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult SetDestination(OEMCrypto_DestBufferDesc* out_buffer,
|
||||
size_t data_length, uint8_t** destination,
|
||||
size_t* max_length) {
|
||||
switch (out_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
*destination = out_buffer->buffer.clear.address;
|
||||
*max_length = out_buffer->buffer.clear.max_length;
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
*destination =
|
||||
reinterpret_cast<uint8_t*>(out_buffer->buffer.secure.handle)
|
||||
+ out_buffer->buffer.secure.offset;
|
||||
*max_length = out_buffer->buffer.secure.max_length;
|
||||
break;
|
||||
default:
|
||||
case OEMCrypto_BufferType_Direct:
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (out_buffer->type != OEMCrypto_BufferType_Direct
|
||||
&& *max_length < data_length) {
|
||||
LOGE("[SetDestination(): OEMCrypto_ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
|
||||
if ((out_buffer->type != OEMCrypto_BufferType_Direct)
|
||||
&& (*destination == NULL)) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
const uint8_t* data_addr,
|
||||
@@ -535,33 +569,16 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
LOGI("-- OEMCryptoResult OEMCrypto_DecryptCTR"
|
||||
"(OEMCrypto_SESSION session,\n");
|
||||
}
|
||||
wvoec_mock::BufferType buffer_type = kBufferTypeDirect;
|
||||
if (data_addr == NULL || data_length == 0 ||
|
||||
iv == NULL || out_buffer == NULL) {
|
||||
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
uint8_t* destination = NULL;
|
||||
size_t max_length = 0;
|
||||
switch (out_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
buffer_type = kBufferTypeClear;
|
||||
destination = out_buffer->buffer.clear.address;
|
||||
max_length = out_buffer->buffer.clear.max_length;
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
buffer_type = kBufferTypeSecure;
|
||||
destination =
|
||||
reinterpret_cast<uint8_t*>(out_buffer->buffer.secure.handle)
|
||||
+ out_buffer->buffer.secure.offset;
|
||||
max_length = out_buffer->buffer.secure.max_length;
|
||||
break;
|
||||
default:
|
||||
case OEMCrypto_BufferType_Direct:
|
||||
buffer_type = kBufferTypeDirect;
|
||||
destination = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (buffer_type != kBufferTypeDirect && max_length < data_length) {
|
||||
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
OEMCryptoResult sts = SetDestination(out_buffer, data_length, &destination,
|
||||
&max_length);
|
||||
if (sts != OEMCrypto_SUCCESS) return sts;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
@@ -576,14 +593,31 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
if (data_addr == NULL || data_length == 0 ||
|
||||
iv == NULL || out_buffer == NULL) {
|
||||
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return session_ctx->DecryptCTR(iv, block_offset, data_addr, data_length,
|
||||
is_encrypted, destination,
|
||||
out_buffer->type);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_CopyBuffer(const uint8_t *data_addr,
|
||||
size_t data_length,
|
||||
OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags) {
|
||||
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||
LOGI("-- OEMCryptoResult OEMCrypto_CopyBuffer(..)\n");
|
||||
}
|
||||
if (data_addr == NULL || out_buffer == NULL) {
|
||||
LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
uint8_t* destination = NULL;
|
||||
size_t max_length = 0;
|
||||
OEMCryptoResult sts = SetDestination(out_buffer, data_length, &destination,
|
||||
&max_length);
|
||||
if (sts != OEMCrypto_SUCCESS) return sts;
|
||||
|
||||
return session_ctx->DecryptCTR(iv, block_offset, data_addr, data_length,
|
||||
is_encrypted, destination, buffer_type);
|
||||
memcpy(destination, data_addr, data_length);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
|
||||
@@ -1928,6 +1928,41 @@ TEST_F(OEMCryptoClientTest, GenerateDerivedKeys) {
|
||||
s.GenerateDerivedKeys();
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoClientTest, ClearCopyTest) {
|
||||
const int kDataSize = 256;
|
||||
uint8_t input_buffer[kDataSize];
|
||||
OEMCrypto_GetRandom(input_buffer, sizeof(input_buffer));
|
||||
uint8_t output_buffer[kDataSize];
|
||||
OEMCrypto_DestBufferDesc dest_buffer;
|
||||
dest_buffer.type = OEMCrypto_BufferType_Clear;
|
||||
dest_buffer.buffer.clear.address = output_buffer;
|
||||
dest_buffer.buffer.clear.max_length = sizeof(output_buffer);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_CopyBuffer(input_buffer, sizeof(input_buffer),
|
||||
&dest_buffer, OEMCrypto_FirstSubsample
|
||||
| OEMCrypto_LastSubsample));
|
||||
ASSERT_EQ(0, memcmp(input_buffer, output_buffer, sizeof(input_buffer)));
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
|
||||
OEMCrypto_CopyBuffer(NULL, sizeof(input_buffer),
|
||||
&dest_buffer, OEMCrypto_FirstSubsample
|
||||
| OEMCrypto_LastSubsample));
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
|
||||
OEMCrypto_CopyBuffer(input_buffer, sizeof(input_buffer),
|
||||
NULL, OEMCrypto_FirstSubsample
|
||||
| OEMCrypto_LastSubsample));
|
||||
dest_buffer.buffer.clear.address = NULL;
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
|
||||
OEMCrypto_CopyBuffer(input_buffer, sizeof(input_buffer),
|
||||
&dest_buffer, OEMCrypto_FirstSubsample
|
||||
| OEMCrypto_LastSubsample));
|
||||
dest_buffer.buffer.clear.address = output_buffer;
|
||||
dest_buffer.buffer.clear.max_length = sizeof(output_buffer) - 1;
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
||||
OEMCrypto_CopyBuffer(input_buffer, sizeof(input_buffer),
|
||||
&dest_buffer, OEMCrypto_FirstSubsample
|
||||
| OEMCrypto_LastSubsample));
|
||||
}
|
||||
|
||||
//
|
||||
// AddKey Tests
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user