diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index eae0fd31..2b398184 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -807,7 +807,6 @@ class Adapter { LOOKUP( 9, 12, UpdateUsageTable, OEMCrypto_UpdateUsageTable); LOOKUP_ALL( 8, WrapKeybox, OEMCrypto_WrapKeybox); LOOKUP_ALL(15, SupportsDecryptHash, OEMCrypto_SupportsDecryptHash); - LOOKUP_ALL(15, InitializeDecryptHash, OEMCrypto_InitializeDecryptHash); LOOKUP_ALL(15, SetDecryptHash, OEMCrypto_SetDecryptHash); LOOKUP_ALL(15, GetHashErrorCode, OEMCrypto_GetHashErrorCode); // clang-format on @@ -2376,17 +2375,6 @@ extern "C" uint32_t OEMCrypto_SupportsDecryptHash(){ return OEMCrypto_SupportsDecryptHash(kLevelDefault); } -extern "C" OEMCryptoResult OEMCrypto_InitializeDecryptHash( - OEMCrypto_SESSION session) { - if (!gAdapter.get()) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - LevelSession pair = gAdapter->GetSession(session); - if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; - if (pair.fcn->InitializeDecryptHash == NULL) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - return pair.fcn->InitializeDecryptHash(pair.session); -} - extern "C" OEMCryptoResult OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, uint32_t frame_number, const uint8_t* hash, diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp index 4140125d..bb5ca174 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp @@ -535,7 +535,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( OEMCryptoResult result = session_ctx->DecryptCENC( iv, block_offset, pattern, data_addr, data_length, is_encrypted, - crypto_engine->destination(), out_buffer->type); + crypto_engine->destination(), out_buffer->type, subsample_flags); if (result != OEMCrypto_SUCCESS) return result; return crypto_engine->PushDestination(out_buffer, subsample_flags); } @@ -1621,20 +1621,6 @@ OEMCRYPTO_API uint32_t OEMCrypto_SupportsDecryptHash() { return OEMCrypto_CRC_Clear_Buffer; } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_InitializeDecryptHash( - OEMCrypto_SESSION session) { - if (!crypto_engine) { - LOGE("OEMCrypto_InitializeDecryptHash: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (!session_ctx || !session_ctx->isValid()) { - LOGE("[OEMCrypto_InitializeDecryptHash(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return session_ctx->InitializeDecryptHash(); -} - OEMCRYPTO_API OEMCryptoResult OEMCrypto_SetDecryptHash( OEMCrypto_SESSION session, uint32_t frame_number, const uint8_t* hash, size_t hash_length) { diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp index f31fe7f5..5653abfc 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp @@ -1168,7 +1168,6 @@ OEMCryptoResult SessionContext::SelectContentKey( LOGE("No key matches key id"); return OEMCrypto_ERROR_NO_CONTENT_KEY; } - compute_hash_ = false; content_key->set_ctr_mode(cipher_mode == OEMCrypto_CipherMode_CTR); current_content_key_ = content_key; const KeyControlBlock& control = current_content_key()->control(); @@ -1285,7 +1284,7 @@ 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) { + 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); @@ -1293,13 +1292,30 @@ OEMCryptoResult SessionContext::DecryptCENC( if (current_content_key() == NULL || (current_content_key()->control().control_bits() & wvoec::kControlAllowHashVerification) == 0) { - // This should not happen: this check should already have occured in - // InitializeDecryptHash or the hash should have been discarded in - // SelectContentKey. But it doesn't hurt to double check. LOGE("[DecryptCENC(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; + hash_error_ = OEMCrypto_ERROR_UNKNOWN_FAILURE; + compute_hash_ = false; + current_hash_ = 0; + current_frame_number_ = 0; + } else { + if (OEMCrypto_FirstSubsample & subsample_flags) { + current_hash_ = wvcrc32Init(); + } + current_hash_ = + wvcrc32Cont(clear_data, cipher_data_length, current_hash_); + if (OEMCrypto_LastSubsample & 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_); + // Update bad_frame_number_ only if this is the first bad frame. + if (hash_error_ == OEMCrypto_SUCCESS) { + bad_frame_number_ = current_frame_number_; + hash_error_ = OEMCrypto_ERROR_BAD_HASH; + } + } + compute_hash_ = false; + } } - current_hash_ = wvcrc32Cont(clear_data, cipher_data_length, current_hash_); } return result; } @@ -1526,36 +1542,9 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8, return OEMCrypto_SUCCESS; } -OEMCryptoResult SessionContext::InitializeDecryptHash() { - // Check there is a content key, and it is allowed. - if (current_content_key() == NULL || - (current_content_key()->control().control_bits() & - wvoec::kControlAllowHashVerification) == 0) { - LOGE("[InitializeDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); - compute_hash_ = false; - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - compute_hash_ = true; - current_hash_ = wvcrc32Init(); - return OEMCrypto_SUCCESS; -} - OEMCryptoResult SessionContext::SetDecryptHash(uint32_t frame_number, const uint8_t* hash, size_t hash_length) { - // Check there is a content key, and it is allowed. - if (current_content_key() == NULL || - (current_content_key()->control().control_bits() & - wvoec::kControlAllowHashVerification) == 0) { - LOGE("[SetDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!compute_hash_) { - // This would happen if somebody computes the hash, and then changes keys. - LOGE("[SetDecryptHash(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - compute_hash_ = false; if (hash_length < sizeof(uint32_t)) { LOGE("[SetDecryptHash(): short buffer]"); return OEMCrypto_ERROR_SHORT_BUFFER; @@ -1564,15 +1553,9 @@ OEMCryptoResult SessionContext::SetDecryptHash(uint32_t frame_number, LOGE("[SetDecryptHash(): long buffer]"); return OEMCrypto_ERROR_BUFFER_TOO_LARGE; } - uint32_t given_hash = *reinterpret_cast(hash); - if (current_hash_ != given_hash) { - LOGE("CRC for frame %d is %08x, should be %08x\n", frame_number, - current_hash_, given_hash); - // Update bad_frame_number_ only if this is the first bad frame. - if (hash_error_ == OEMCrypto_SUCCESS) bad_frame_number_ = frame_number; - hash_error_ = OEMCrypto_ERROR_BAD_HASH; - } - // Return success if the hash was compared, even if there was an error. + compute_hash_ = true; + current_frame_number_ = frame_number; + given_hash_ = *reinterpret_cast(hash); return OEMCrypto_SUCCESS; } diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.h index 9d65c4f3..3522abe2 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.h @@ -102,7 +102,8 @@ class SessionContext { const uint8_t* cipher_data, size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data, - OEMCryptoBufferType buffer_type); + OEMCryptoBufferType buffer_type, + uint8_t subsample_flags); OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer, size_t buffer_length, const uint8_t* iv, @@ -152,7 +153,6 @@ class SessionContext { virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data); virtual OEMCryptoResult SelectContentKey(const KeyId& key_id, OEMCryptoCipherMode cipher_mode); - virtual OEMCryptoResult InitializeDecryptHash(); virtual OEMCryptoResult SetDecryptHash(uint32_t frame_number, const uint8_t* hash, size_t hash_length); @@ -258,7 +258,9 @@ class SessionContext { // These are used when doing full decrypt path testing. bool compute_hash_; // True if the current frame needs a hash. uint32_t current_hash_; // Running CRC hash of frame. - uint32_t bad_frame_number_; // Frame number with bad hash. + uint32_t given_hash_; // True CRC hash of frame. + uint32_t current_frame_number_; // Current frame for CRC hash. + uint32_t bad_frame_number_; // Frame number with bad hash. OEMCryptoResult hash_error_; // Error code for first bad frame. CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext); diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index f11b8163..409ec181 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -1721,21 +1721,27 @@ INSTANTIATE_TEST_CASE_P(TestRefreshEachKeys, SessionTestRefreshKeyTest, // If the license does not allow a hash, then we should not compute one. TEST_F(OEMCryptoSessionTests, HashForbiddenAPI15) { + uint32_t hash_type = OEMCrypto_SupportsDecryptHash(); + // If hash is not supported, or is vendor defined, don't try to test it. + if (hash_type != OEMCrypto_CRC_Clear_Buffer) return; Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); - // Either failure, or not supported is allowed. - ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_InitializeDecryptHash(s.session_id())); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id, - s.license().keys[0].key_id_length, - OEMCrypto_CipherMode_CTR)); - // Still not allowed. - ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_InitializeDecryptHash(s.session_id())); + uint32_t frame_number = 1; + uint32_t hash = 42; + // It is OK to set the hash before loading the keys + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_SetDecryptHash(s.session_id(), frame_number, + reinterpret_cast(&hash), + sizeof(hash))); + // It is OK to select the key and decrypt. + ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR()); + // But the error code should be bad. + ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, + OEMCrypto_GetHashErrorCode(s.session_id(), &frame_number)); } // @@ -1944,14 +1950,18 @@ class OEMCryptoSessionTestsDecryptTests s.license().keys[0].cipher_mode = cipher_mode_; ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); + if (global_features.supports_crc) { + uint32_t hash = + wvcrc32(unencryptedData.data(), unencryptedData.size()); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_SetDecryptHash( + s.session_id(), 1, reinterpret_cast(&hash), + sizeof(hash))); + } sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id, s.license().keys[0].key_id_length, cipher_mode_); ASSERT_EQ(OEMCrypto_SUCCESS, sts); - if (global_features.supports_crc) { - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_InitializeDecryptHash(s.session_id())); - } // We decrypt each subsample. vector output_buffer(total_size_ + 16, 0xaa); const uint8_t *input_buffer = NULL; @@ -2021,12 +2031,6 @@ class OEMCryptoSessionTestsDecryptTests output_buffer.resize(total_size_); EXPECT_EQ(unencryptedData, output_buffer); if (global_features.supports_crc) { - uint32_t hash = - wvoec::wvcrc32(unencryptedData.data(), unencryptedData.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_SetDecryptHash( - s.session_id(), 1, reinterpret_cast(&hash), - sizeof(hash))); uint32_t frame; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetHashErrorCode(s.session_id(), &frame));