/* * Copyright (C) 2011 Google, Inc. All Rights Reserved * Requires gtest "mm $ANDROID/external/gtest" before mm in this directory. */ #include #include #include #include #include #include #include #include #include #include #define LOG_TAG "WV.TestOEMCrypto" #include #include #include "OEMCryptoDASH.h" // Unit Test 1: The header file must compile. #include "MockOEMCrypto.h" #include "gtest/gtest.h" using namespace wvdrm; // Make an array of bytes from the string in Hexidecimal. uint8_t * makeArray(const char *hex, size_t *length=NULL) { size_t hex_length = strlen(hex); uint8_t* array = new uint8_t[hex_length/2]; size_t hex_index = 0; size_t array_index = 0; while( hex_index < hex_length) { // skip spaces and dashes. if ((hex[hex_index] == '-') || (hex[hex_index] == ' ')) { hex_index++; } else { unsigned int value; sscanf(hex +hex_index, "%02x", &value); array[array_index] = value; hex_index += 2; array_index += 1; } } if (length != NULL) *length = array_index; return array; } class OEMCryptoTest : public testing::Test { protected: virtual void SetUp() { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()) << "OEMCrypto_Initialize failed."; } virtual void TearDown() { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate()) << "OEMCrypto_Terminate failed."; } public: }; TEST_F(OEMCryptoTest, MockOEMCrypto_isKeyboxValid) { ASSERT_EQ(OEMCrypto_IsKeyboxValid(), OEMCrypto_SUCCESS); } TEST_F(OEMCryptoTest, MockOEMCrypto_GenerateDerivedKeys) { OEMCrypto_SESSION session; // This is the Eureka test key. static const uint8_t device_key[16] = { 0x89, 0xc0, 0x85, 0x0c, 0xbd, 0xcd, 0xa9, 0x62, 0xdc, 0x33, 0x2f, 0x96, 0x0e, 0x11, 0xcc, 0x67, }; memcpy(MockOEMCrypto::sSingleton->mKeybox.mKey, device_key, 16); // This data was captured from a successful licence request using the Eureka // test data. I'm just going to borrow it. uint32_t mac_length = 0; const uint8_t *mac_context = makeArray("41555448454e5449434154494f4e00" // AUTHENTICATION "0a4c0800124800000002000001241f34" "4db9dff087f01d917910f39b60dc7797" "cd97789ee82516dc07a478cb70b8c08c" "299293150aa8e01d2dc9808c98daa16e" "40a0e55dfe3618c7584dd3c7be42122c" "122a0a10303132333435363738394142" "4344454610011a146d79436f6f6c5265" "71756573742c20447564652118012000" "00000100", &mac_length); uint32_t enc_length = 0; const uint8_t *enc_context = makeArray("454e4352595054494f4e00" // ENCRYPTION "0a4c0800124800000002000001241f34" "4db9dff087f01d917910f39b60dc7797" "cd97789ee82516dc07a478cb70b8c08c" "299293150aa8e01d2dc9808c98daa16e" "40a0e55dfe3618c7584dd3c7be42122c" "122a0a10303132333435363738394142" "4344454610011a146d79436f6f6c5265" "71756573742c20447564652118012000" "00000080", &enc_length); uint32_t key_length = 0; const uint8_t* mac_key = makeArray("d53c018d4a4d2cdb19685d1764845a87" "7474dc020a2d19225d385ce2176bd61c", &key_length); EXPECT_EQ(32, (int)key_length) << "The mac key has the wrong length."; const uint8_t* enc_key = makeArray("9713d57529b9f0a84fa06371af92b791", &key_length); EXPECT_EQ(16, (int)key_length) << "The encrypt key has the wrong length"; EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session)) << "OpenSession not successful."; MockSession* ms = MockOEMCrypto::sSingleton->findSession(session); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GenerateDerivedKeys(session, mac_context, mac_length, enc_context, enc_length)) << "GenerateDerivedKeys failed."; EXPECT_EQ(0, memcmp(ms->mEncryptKey, enc_key, 16)); EXPECT_EQ(0, memcmp(ms->mMacKey, mac_key, 32)); // printf("\n--------------------------\n"); // printf("enc is: "); // for(int i=0; i < 16; i++) printf(" %02x", ms->encrypt_key[i]); // printf("\n"); // printf("should: "); // for(int i=0; i < 16; i++) printf(" %02x", enc_key[i]); // printf("\n"); // printf("\n--------------------------\n"); // printf("mac is: "); // for(int i=0; i < 32; i++) printf(" %02x", ms->mac_key[i]); // printf("\n"); // printf("should: "); // for(int i=0; i < 32; i++) printf(" %02x", mac_key[i]); // printf("\n"); // printf("\n--------------------------\n"); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session)) << "OEMCrypto_CloseSesion failed."; EXPECT_EQ(OEMCrypto_ERROR_INVALID_SESSION, OEMCrypto_CloseSession(session)) << "Can only close session once. "; } TEST_F(OEMCryptoTest, MockOEMCrypto_GenerateSignature) { OEMCrypto_SESSION session; // session = 0xdeadbeef; size_t message_length = 0; const uint8_t* message = makeArray("0a300a146d79436f6f6c526571756573" "742c2044756465211208ec2316261123" "b47c1a0a507572636861736573212001" "28001204080118011a3612103cb829f7" "c0241dc1434982d9e059ae0d1a20015f" "6157446481b9a32823c2657c9c464fe2" "e6115e96963f1d3c484ce95bff1e2001" "1a2e0a066b657920696412104e793f3b" "ef67bc83f7deacfbf1e9d3851a101308" "fb0835bda16782f902f5c49644d52002" "209580ff8505", &message_length); uint8_t signature[32]; uint32_t signature_length = 32; EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session)); // MockSession *ms = MockOEMCrypto::sSingleton->findSession(session); // TODO: enter some test vectors. EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GenerateSignature(session, message, message_length, signature, &signature_length)) << "Generate signature failed."; EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session)) << "OEMCrypto_CloseSesion failed."; delete [] message; } /* Test a single call to decryptCTR. */ TEST_F(OEMCryptoTest, MockOEMCrypto_DecryptContent) { OEMCrypto_SESSION session; // session = 0xdeadbeef; // This is the test content from iStreamPlanet. size_t keyid_length = 0; const uint8_t* keyid = makeArray("60061e01-7e57-5e57-ce57-d00d1ed00d1e", &keyid_length); EXPECT_EQ(16, (int)keyid_length) << "Key ID setup incorrectly."; size_t key_length = 0; const uint8_t* key = makeArray("1a 8a 20 95 e4 de b2 d2 9e c8 16 ac 7b ae 20 82", &keyid_length); EXPECT_EQ(16, (int)keyid_length) << "Key setup incorrectly."; uint8_t * iv = makeArray("000102030405060708090a0b0c0d0e0f"); uint8_t ecount[16]; uint8_t ivec[16]; unsigned int num = 0; memset(ecount, 0, 16); memcpy(ivec, iv, 16); AES_KEY aes_key; AES_set_encrypt_key(key, 128, &aes_key); int bytes_read, bytes_written; const size_t count = 751; // a nice big number, but not too round. unsigned char indata[count]; unsigned char outdata[count]; memset(indata, 0xAA, count); AES_ctr128_encrypt(indata, outdata, count, &aes_key, ivec, ecount, &num); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session)) << "OEMCrypto_OpenSession failed."; // TODO: turn on clear keys. Or rather, allow clear keys to be turned off. EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session, key, keyid_length)) << "OEMCrypto_SelectKey failed."; OEMCrypto_DestBufferDesc out_buffer; out_buffer.type = OEMCrypto_BufferType_Clear; out_buffer.buffer.clear.address = new uint8_t[count]; out_buffer.buffer.clear.max_length = count; memset(out_buffer.buffer.clear.address, 0, count); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_DecryptCTR(session, outdata, count, true, iv, 0, // offset=0 &out_buffer)) << "OEMCrypto_DecryptCTR"; EXPECT_EQ(0, memcmp(indata,out_buffer.buffer.clear.address, count)) << "Final result was wrong."; // printf("\n--------------------------\n"); // printf("ivec : "); // for(int i=0; i < 16; i++) printf(" %02x", ivec[i]); // printf("\n"); // printf("count: "); // for(int i=0; i < 16; i++) printf(" %02x", ecount[i]); // printf(" num=%d\n", num); // printf("Input: "); // for(int i=0; i < 16; i++) printf(" %02x", indata[i]); // printf("\n"); // printf("Outpt: "); // for(int i=0; i < 16; i++) printf(" %02x", out_buffer.buffer.clear.address[i]); // printf("\n"); // printf("Encry: "); // for(int i=0; i < 16; i++) printf(" %02x", outdata[i]); // printf("\n"); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session)) << "OEMCrypto_CloseSesion failed."; delete [] out_buffer.buffer.clear.address; delete [] keyid; delete [] key; } TEST_F(OEMCryptoTest, MockOEMCrypto_LoadKeys) { OEMCrypto_SESSION session; EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session)); MockSession* ms = MockOEMCrypto::sSingleton->findSession(session); uint32_t key_length = 0; const uint8_t* mac_key = makeArray("d53c018d4a4d2cdb19685d1764845a87" "7474dc020a2d19225d385ce2176bd61c", &key_length); EXPECT_EQ(32, (int)key_length); const uint8_t* enc_key = makeArray("9713d57529b9f0a84fa06371af92b791", &key_length); EXPECT_EQ(16, (int)key_length); memcpy(ms->mEncryptKey, enc_key, 16); memcpy(ms->mMacKey, mac_key, 32); uint32_t message_length = 0; const uint8_t* message = makeArray("0a300a146d79436f6f6c526571756573" "742c2044756465211208ec2316261123" "b47c1a0a507572636861736573212001" "28001204080118011a3612103cb829f7" "c0241dc1434982d9e059ae0d1a20015f" "6157446481b9a32823c2657c9c464fe2" "e6115e96963f1d3c484ce95bff1e2001" "1a2e0a066b657920696412104e793f3b" "ef67bc83f7deacfbf1e9d3851a101308" "fb0835bda16782f902f5c49644d52002" "209580ff8505", &message_length); uint32_t signature_length = 0; const uint8_t* signature = makeArray("7941857a3a42dd46992dc585e8e3ac01" "5ff491bd190921e5f4212074795575fd", &signature_length); uint8_t* enc_mac_key_iv = makeArray("3cb829f7c0241dc1434982d9e059ae0d", &key_length); EXPECT_EQ(16, (int)key_length); uint8_t* enc_mac_key = makeArray("015f6157446481b9a32823c2657c9c46" "4fe2e6115e96963f1d3c484ce95bff1e", &key_length); EXPECT_EQ(32, (int)key_length); uint8_t* content_key = makeArray("30313233343536373839616263646566", &key_length); uint32_t num_keys = 1; OEMCrypto_KeyObject key_array[1]; OEMCrypto_KeyControl control; memcpy( control.mVerification, "kctl", 4); control.mDuration = htonl(60*60*24); // 1 day. EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GenerateNonce(session, &control.mNonce)) << "OEMCrypto_GenerateNonce"; control.mControl = htonl(0); EXPECT_EQ(16, (int)sizeof(control)); AES_KEY aes_key; AES_set_encrypt_key( content_key, 128, &aes_key); uint8_t iv[16]; uint8_t enc_key_control[16]; memset( iv, 0, 16); AES_cbc_encrypt((uint8_t *) &control, enc_key_control, 16, &aes_key, iv, AES_ENCRYPT); memset( iv, 0, 16); key_array[0].key_id = makeArray("00000000000000000000000000000000", &(key_array[0].key_id_length)); key_array[0].key_data_iv = makeArray("4e793f3bef67bc83f7deacfbf1e9d385"); // given. key_array[0].key_data = makeArray("1308fb0835bda16782f902f5c49644d5"); // given. key_array[0].key_control_iv = iv; key_array[0].key_control = enc_key_control; // printf("\n--------------------------\n"); // printf(" iv: "); // for(int i=0; i < 16; i++) printf(" %02x", key_array[0].key_control_iv[i]); // printf("\n"); // printf(" con: "); // uint8_t *buffer = (uint8_t *) &control; // for(int i=0; i < 16; i++) printf(" %02x", buffer[i]); // printf("\n"); // printf("e con: "); // for(int i=0; i < 16; i++) printf(" %02x", key_array[0].key_control[i]); // printf("\n"); // printf("u key: "); // for(int i=0; i < 16; i++) printf(" %02x", content_key[i]); // printf("\n"); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(session, message, message_length, signature, signature_length, enc_mac_key_iv, enc_mac_key, num_keys, key_array)) << "OEMCrypto_LoadKeys"; uint8_t* new_mac_key = makeArray("faa85bcdd67395e65566c4b891f8a2f0" "2ff983dbad9a4cb44518e8235a4dbb5f", &key_length); EXPECT_EQ(0, memcmp(ms->mMacKey, new_mac_key, 32)) << "New Mac key was not decrypted."; // printf("\n--------------------------\n"); // printf(" mac: "); // for(int i=0; i < 32; i++) printf(" %02x", ms->mac_key[i]); // printf("\n"); // printf("new mac: "); // for(int i=0; i < 32; i++) printf(" %02x", new_mac_key[i]); // printf("\n"); EXPECT_EQ(1, (int)ms->mKeys.size()); if (ms->mKeys.size() > 0) { EXPECT_EQ(0, memcmp( ms->mKeys[0].mKeyData, content_key, 16)) << "Key data was not loaded correctly"; } EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session)) << "OEMCrypto_CloseSesion failed."; } TEST_F(OEMCryptoTest, MockOEMCrypto_RefreshKeys) { OEMCrypto_SESSION session; // session = 0xdeadbeef; const uint8_t* message = NULL; uint32_t message_length = 0; const uint8_t* signature = NULL; uint32_t signature_length = 0; uint32_t num_keys = 0; const OEMCrypto_KeyRefreshObject* key_array = NULL; EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session)); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_RefreshKeys(session, message, message_length, signature, signature_length, num_keys, key_array)) << "OEMCrypto_RefreshKeys"; EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session)) << "OEMCrypto_CloseSesion failed."; } /***********************************************************************/ /***********************************************************************/ // TODO: This test is just a stub. We will fix it in a future CL. /***********************************************************************/ /***********************************************************************/ TEST_F(OEMCryptoTest, MockOEMCrypto_FullVideoTest) { uint8_t *keybox = (uint8_t*)"pointer to some valid keybox data"; uint32_t keyBoxLength = strlen((char*)keybox); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_InstallKeybox(keybox, keyBoxLength)); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); uint8_t deviceID[32] = "0123456789012345"; uint32_t idLength = 16; EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetDeviceID(deviceID, &idLength)); for (uint32_t i = 0; i < idLength; i++) printf("%c", deviceID[i]); printf("\n"); uint8_t* keyData; uint32_t keyDataLength = 72; keyData = (uint8_t*)malloc(keyDataLength); //not really but we will malloc it for the stub work memset(keyData, 0, keyDataLength); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetKeyData(keyData, &keyDataLength)); for (uint32_t i = 0; i < keyDataLength; i++) { if ((i % 15) == 0) printf("\n"); printf("0x%02x ", keyData[i]); } printf("\n"); printf("request an EMM\n"); delete keyData; OEMCrypto_SESSION session; // session = 0xdeadbeef; EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session)); // EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_EnterSecurePlayback()); const uint8_t* emmKey = (const uint8_t*)"0123456789012345"; const uint32_t emmKeyLength = 16; // EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_SetEntitlementKey(emmKey, emmKeyLength)); const uint8_t* ecm = (const uint8_t*)"01234567890123450123456789012345"; const uint32_t length = 32; uint32_t flags; // EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_DeriveControlWord(ecm, length, &flags)); const uint8_t* contentKey = (const uint8_t*)"0123456789012345"; const uint32_t contentKeyLength = 16; const uint8_t* control = (const uint8_t*)"abcd"; const uint32_t controlLength = 4; // EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_SetContentKey(session, contentKey, contentKeyLength, control, controlLength)); { const uint8_t* iv = (const uint8_t*)"0123456789012345"; const uint8_t* input = (const uint8_t*)"some nicely encrypted video data"; const uint32_t inputLength = strlen((char*)input); uint32_t output_handle = 0xdeadbeef; uint32_t output_offset = 0; uint32_t outputLength; // EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_DecryptVideo(iv, input, inputLength, output_handle, output_offset, &outputLength)); } { const uint8_t* iv = (const uint8_t*)"0123456789012345"; const uint8_t* input = (const uint8_t*)"some nicely encrypted audio data"; const uint32_t inputLength = strlen((char*)input); uint8_t *output; uint32_t outputLength; // EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_DecryptAudio(iv, input, inputLength, output, &outputLength)); } // EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_ExitSecurePlayback()); EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session)) << "OEMCrypto_CloseSesion failed."; }