diff --git a/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h b/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h index d92d2986..6141c03e 100644 --- a/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h +++ b/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h @@ -13,6 +13,9 @@ enum SecurityLevel { kLevelDefault, kLevel3 }; If one level is not available, the other will be used instead. */ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session, SecurityLevel level); +OEMCryptoResult OEMCrypto_CopyBuffer( + SecurityLevel level, const uint8_t* data_addr, size_t data_length, + OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags); OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox, size_t keyBoxLength, SecurityLevel level); diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index d36245bd..4ecbad6b 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -637,18 +637,6 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { if (!SetDestinationBufferType()) return UNKNOWN_ERROR; } - AutoLock auto_lock(crypto_lock_); - // Check if key needs to be selected - if (params.is_encrypted) { - if (key_id_ != *params.key_id) { - if (SelectKey(*params.key_id)) { - key_id_ = *params.key_id; - } else { - return NEED_KEY; - } - } - } - OEMCrypto_DestBufferDesc buffer_descriptor; buffer_descriptor.type = params.is_secure ? destination_buffer_type_ : OEMCrypto_BufferType_Clear; @@ -672,10 +660,26 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { break; } - OEMCryptoResult sts = OEMCrypto_DecryptCTR( - oec_session_id_, params.encrypt_buffer, params.encrypt_length, - params.is_encrypted, &(*params.iv).front(), params.block_offset, - &buffer_descriptor, params.subsample_flags); + OEMCryptoResult sts; + if (params.is_encrypted) { + AutoLock auto_lock(crypto_lock_); + // Check if key needs to be selected + if (key_id_ != *params.key_id) { + if (SelectKey(*params.key_id)) { + key_id_ = *params.key_id; + } else { + return NEED_KEY; + } + } + sts = OEMCrypto_DecryptCTR( + oec_session_id_, params.encrypt_buffer, params.encrypt_length, + params.is_encrypted, &(*params.iv).front(), params.block_offset, + &buffer_descriptor, params.subsample_flags); + } else { + sts = OEMCrypto_CopyBuffer(requested_security_level_, + params.encrypt_buffer, params.encrypt_length, + &buffer_descriptor, params.subsample_flags); + } switch (sts) { case OEMCrypto_SUCCESS: diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 91b9a555..e1a0f713 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -322,6 +322,7 @@ class Adapter { LOOKUP(GetHDCPCapability_V9, OEMCrypto_GetHDCPCapability_V9); } else { LOOKUP(QueryKeyControl, OEMCrypto_QueryKeyControl); + LOOKUP(CopyBuffer, OEMCrypto_CopyBuffer); LOOKUP(GetHDCPCapability, OEMCrypto_GetHDCPCapability); LOOKUP(IsAntiRollbackHwPresent, OEMCrypto_IsAntiRollbackHwPresent); LOOKUP(GetNumberOfOpenSessions, OEMCrypto_GetNumberOfOpenSessions); @@ -488,6 +489,16 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session, return kAdapter->OpenSession(session, level); } +OEMCryptoResult OEMCrypto_CopyBuffer( + SecurityLevel level, const uint8_t* data_addr, size_t data_length, + OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) { + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + const FunctionPointers* fcn = kAdapter->get(level); + if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; + if (fcn->version < 10) return OEMCrypto_ERROR_NOT_IMPLEMENTED; + return fcn->CopyBuffer(data_addr, data_length, out_buffer, subsample_flags); +} + OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox, size_t keyBoxLength, SecurityLevel level) { @@ -587,7 +598,6 @@ OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(SecurityLevel level, if (fcn->version < 10) return OEMCrypto_ERROR_NOT_IMPLEMENTED; return fcn->GetMaxNumberOfSessions(maximum); } - } // namespace wvcdm extern "C" OEMCryptoResult OEMCrypto_Initialize(void) { @@ -710,6 +720,13 @@ extern "C" OEMCryptoResult OEMCrypto_DecryptCTR( subsample_flags); } +extern "C" OEMCryptoResult OEMCrypto_CopyBuffer( + const uint8_t* data_addr, size_t data_length, + OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) { + return OEMCrypto_CopyBuffer(kLevelDefault, data_addr, data_length, out_buffer, + subsample_flags); +} + extern "C" OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t* keybox, size_t keyBoxLength, uint8_t* wrappedKeybox, diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp index bd815392..f93f4540 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp @@ -1065,15 +1065,13 @@ bool SessionContext::DecryptMessage(const std::vector& 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(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(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; } diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h index 6f9aca04..77df84f0 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h @@ -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, diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp index cb1b2c62..f8806ee3 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp @@ -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(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(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" diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index 6754324c..660983f5 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -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 //