diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp index 88c67879..6a3b85cd 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp @@ -51,12 +51,67 @@ void PrintTo(const vector& value, ostream* os) { } } // namespace std -namespace { -constexpr size_t kTestSubsampleSectionSize = 256; -} // namespace - namespace wvoec { +namespace { + +constexpr size_t kTestSubsampleSectionSize = 256; + +// Encrypt a block of data using CTR mode. +void EncryptCTR(const vector& in_buffer, const uint8_t* key, + const uint8_t* starting_iv, vector* out_buffer) { + ASSERT_NE(nullptr, key); + ASSERT_NE(nullptr, starting_iv); + ASSERT_NE(nullptr, out_buffer); + AES_KEY aes_key; + AES_set_encrypt_key(key, AES_BLOCK_SIZE * 8, &aes_key); + out_buffer->resize(in_buffer.size()); + + uint8_t iv[AES_BLOCK_SIZE]; // Current iv. + + memcpy(iv, &starting_iv[0], AES_BLOCK_SIZE); + size_t l = 0; // byte index into encrypted subsample. + while (l < in_buffer.size()) { + uint8_t aes_output[AES_BLOCK_SIZE]; + AES_encrypt(iv, aes_output, &aes_key); + for (size_t n = 0; n < AES_BLOCK_SIZE && l < in_buffer.size(); n++, l++) { + (*out_buffer)[l] = aes_output[n] ^ in_buffer[l]; + } + ctr128_inc64(1, iv); + } +} + +// Uses OEMCrypto to decrypt some random data in 'cenc' mode. This function +// assumes that the correct key is already selected in the session. It requires +// the plaintext of that key so that it can encrypt the test data. It resizes +// the provided vectors and fills them with the expected and actual decrypt +// results. Returns the result of OEMCrypto_DecryptCENC(). +OEMCryptoResult DecryptCTR(OEMCrypto_SESSION session_id, const uint8_t* key, + vector* expected_data, + vector* actual_data) { + vector encrypted_data(kTestSubsampleSectionSize); + expected_data->resize(encrypted_data.size()); + actual_data->resize(encrypted_data.size()); + + // Create test sample description + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + GenerateSimpleSampleDescription(encrypted_data, *actual_data, + &sample_description, &subsample_description); + + // Generate test data + EXPECT_EQ(GetRandBytes(expected_data->data(), expected_data->size()), 1); + EncryptCTR(*expected_data, key, &sample_description.iv[0], &encrypted_data); + + // Create the pattern description (always 0,0 for 'cenc') + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + // Decrypt the data + return OEMCrypto_DecryptCENC(session_id, &sample_description, 1, &pattern); +} + +} // namespace + int GetRandBytes(unsigned char* buf, int num) { // returns 1 on success, -1 if not supported, or 0 if other failure. return RAND_bytes(buf, num); @@ -947,7 +1002,8 @@ void EntitledMessage::LoadKeys(OEMCryptoResult expected_sts) { if (expected_sts != OEMCrypto_SUCCESS) { return; } - VerifyEntitlementTestKeys(); + VerifyKCBs(); + VerifyDecrypt(); } OEMCryptoResult EntitledMessage::LoadKeys(const vector& message) { @@ -994,11 +1050,11 @@ void EntitledMessage::EncryptContentKey() { } } -// This function verifies that the key control block reported by OEMCrypto agree -// with the truth key control block. Failures in this function probably +// This function verifies that the key control blocks reported by OEMCrypto +// agree with the truth key control block. Failures in this function probably // indicate the OEMCrypto_LoadEntitledKeys did not correctly process the key // control block. -void EntitledMessage::VerifyEntitlementTestKeys() { +void EntitledMessage::VerifyKCBs() { for (unsigned int i = 0; i < num_keys_; i++) { EntitledContentKeyData* key_data = &entitled_key_data_[i]; const size_t entitlement_key_index = key_data->key_index; @@ -1025,6 +1081,28 @@ void EntitledMessage::VerifyEntitlementTestKeys() { } } +void EntitledMessage::VerifyDecrypt() { + const OEMCrypto_SESSION session_id = + license_messages_->session()->session_id(); + + // Loop through all the keys and try decrypt with each one. + for (unsigned int i = 0; i < num_keys_; i++) { + const EntitledContentKeyData* const key_data = &entitled_key_data_[i]; + + OEMCryptoResult result = OEMCrypto_SelectKey( + session_id, key_data->content_key_id, key_data->content_key_id_length, + OEMCrypto_CipherMode_CTR); + ASSERT_EQ(result, OEMCrypto_SUCCESS) << "For key " << i; + + vector expected_data; + vector actual_data; + result = DecryptCTR(session_id, key_data->content_key_data, &expected_data, + &actual_data); + EXPECT_EQ(result, OEMCrypto_SUCCESS) << "For key " << i; + EXPECT_EQ(actual_data, expected_data) << "For key " << i; + } +} + void RenewalRoundTrip::VerifyRequestSignature( const vector& data, const vector& generated_signature, size_t core_message_length) { @@ -1294,30 +1372,6 @@ void Session::GenerateDerivedKeysFromSessionKey() { key_deriver_.DeriveKeys(session_key.data(), mac_context, enc_context); } -void Session::EncryptCTR(const vector& in_buffer, const uint8_t* key, - const uint8_t* starting_iv, - vector* out_buffer) { - ASSERT_NE(nullptr, key); - ASSERT_NE(nullptr, starting_iv); - ASSERT_NE(nullptr, out_buffer); - AES_KEY aes_key; - AES_set_encrypt_key(key, AES_BLOCK_SIZE * 8, &aes_key); - out_buffer->resize(in_buffer.size()); - - uint8_t iv[AES_BLOCK_SIZE]; // Current iv. - - memcpy(iv, &starting_iv[0], AES_BLOCK_SIZE); - size_t l = 0; // byte index into encrypted subsample. - while (l < in_buffer.size()) { - uint8_t aes_output[AES_BLOCK_SIZE]; - AES_encrypt(iv, aes_output, &aes_key); - for (size_t n = 0; n < AES_BLOCK_SIZE && l < in_buffer.size(); n++, l++) { - (*out_buffer)[l] = aes_output[n] ^ in_buffer[l]; - } - ctr128_inc64(1, iv); - } -} - void Session::TestDecryptCTR(bool select_key_first, OEMCryptoResult expected_result, int key_index) { OEMCryptoResult select_result = OEMCrypto_SUCCESS; @@ -1328,27 +1382,12 @@ void Session::TestDecryptCTR(bool select_key_first, license_.keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR); } - // Create test sample description - vector unencrypted_data(kTestSubsampleSectionSize); - vector encrypted_data(unencrypted_data.size()); - vector output_buffer(unencrypted_data.size()); - OEMCrypto_SampleDescription sample_description; - OEMCrypto_SubSampleDescription subsample_description; - - GenerateSimpleSampleDescription(encrypted_data, output_buffer, - &sample_description, &subsample_description); - - // Generate test data - EXPECT_EQ(GetRandBytes(unencrypted_data.data(), unencrypted_data.size()), 1); - 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}; - - // Decrypt the data + vector unencrypted_data; + vector output_buffer; const OEMCryptoResult decrypt_result = - OEMCrypto_DecryptCENC(session_id(), &sample_description, 1, &pattern); + DecryptCTR(session_id(), license_.keys[key_index].key_data, + &unencrypted_data, &output_buffer); + // We only have a few errors that we test are reported. ASSERT_NO_FATAL_FAILURE( TestDecryptResult(expected_result, select_result, decrypt_result)) diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.h b/libwvdrmengine/oemcrypto/test/oec_session_util.h index 272e85e1..d2bde5e8 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.h +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.h @@ -476,8 +476,6 @@ class EntitledMessage { void set_num_keys(uint32_t num_keys) { num_keys_ = num_keys; } uint32_t num_keys() const { return num_keys_; } void SetEntitlementKeyId(unsigned int index, const std::string& key_id); - // Verify that key control blocks of the loaded keys. - void VerifyEntitlementTestKeys(); OEMCrypto_EntitledContentKeyObject* entitled_key_array(); // Returns entitled_key_data_ which is used as input message buffer to // load entitled content keys API. @@ -487,6 +485,11 @@ class EntitledMessage { private: // Find the offset of the give pointer, relative to |entitled_key_data_|. OEMCrypto_Substring FindSubstring(const void* ptr, size_t size); + // Verify that key control blocks of the loaded keys matches their entitlement + // key. + void VerifyKCBs(); + // Verify that decryption with the entitled keys works. + void VerifyDecrypt(); LicenseRoundTrip* license_messages_; uint32_t num_keys_; @@ -528,9 +531,6 @@ class Session { // Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey // and also fill out enc_key_, mac_key_server_, and mac_key_client_. void GenerateDerivedKeysFromSessionKey(); - // Encrypt a block of data using CTR mode. - void EncryptCTR(const vector& in_buffer, const uint8_t* key, - const uint8_t* starting_iv, vector* out_buffer); // Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption. void TestDecryptCTR(bool select_key_first = true, OEMCryptoResult expected_result = OEMCrypto_SUCCESS,