diff --git a/rpcs3/Crypto/unedat.cpp b/rpcs3/Crypto/unedat.cpp index 65641919cb..dd632bbb9a 100644 --- a/rpcs3/Crypto/unedat.cpp +++ b/rpcs3/Crypto/unedat.cpp @@ -1,135 +1,135 @@ #include "stdafx.h" #include "unedat.h" -void generate_key(int crypto_mode, int version, unsigned char *key_final, unsigned char *iv_final, unsigned char *key, unsigned char *iv) -{ - int mode = (int) (crypto_mode & 0xF0000000); - switch (mode) { - case 0x10000000: - // Encrypted ERK. - // Decrypt the key with EDAT_KEY + EDAT_IV and copy the original IV. - aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, key, key_final, 0x10); - memcpy(iv_final, iv, 0x10); - break; - case 0x20000000: - // Default ERK. - // Use EDAT_KEY and EDAT_IV. - memcpy(key_final, version ? EDAT_KEY_1 : EDAT_KEY_0, 0x10); - memcpy(iv_final, EDAT_IV, 0x10); - break; - case 0x00000000: - // Unencrypted ERK. - // Use the original key and iv. - memcpy(key_final, key, 0x10); - memcpy(iv_final, iv, 0x10); - break; - }; -} - -void generate_hash(int hash_mode, int version, unsigned char *hash_final, unsigned char *hash) -{ - int mode = (int) (hash_mode & 0xF0000000); - switch (mode) { - case 0x10000000: - // Encrypted HASH. - // Decrypt the hash with EDAT_KEY + EDAT_IV. - aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, hash, hash_final, 0x10); - break; - case 0x20000000: - // Default HASH. - // Use EDAT_HASH. - memcpy(hash_final, version ? EDAT_HASH_1 : EDAT_HASH_0, 0x10); - break; - case 0x00000000: - // Unencrypted ERK. - // Use the original hash. - memcpy(hash_final, hash, 0x10); - break; - }; -} +void generate_key(int crypto_mode, int version, unsigned char *key_final, unsigned char *iv_final, unsigned char *key, unsigned char *iv) +{ + int mode = (int) (crypto_mode & 0xF0000000); + switch (mode) { + case 0x10000000: + // Encrypted ERK. + // Decrypt the key with EDAT_KEY + EDAT_IV and copy the original IV. + aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, key, key_final, 0x10); + memcpy(iv_final, iv, 0x10); + break; + case 0x20000000: + // Default ERK. + // Use EDAT_KEY and EDAT_IV. + memcpy(key_final, version ? EDAT_KEY_1 : EDAT_KEY_0, 0x10); + memcpy(iv_final, EDAT_IV, 0x10); + break; + case 0x00000000: + // Unencrypted ERK. + // Use the original key and iv. + memcpy(key_final, key, 0x10); + memcpy(iv_final, iv, 0x10); + break; + }; +} -bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsigned char *out, int lenght, unsigned char *key, unsigned char *iv, unsigned char *hash, unsigned char *test_hash) -{ - // Setup buffers for key, iv and hash. - unsigned char key_final[0x10] = {}; - unsigned char iv_final[0x10] = {}; - unsigned char hash_final_10[0x10] = {}; - unsigned char hash_final_14[0x14] = {}; - - // Generate crypto key and hash. - generate_key(crypto_mode, version, key_final, iv_final, key, iv); - if ((hash_mode & 0xFF) == 0x01) - generate_hash(hash_mode, version, hash_final_14, hash); - else - generate_hash(hash_mode, version, hash_final_10, hash); - - if ((crypto_mode & 0xFF) == 0x01) // No algorithm. - { - memcpy(out, in, lenght); - } - else if ((crypto_mode & 0xFF) == 0x02) // AES128-CBC - { - aescbc128_decrypt(key_final, iv_final, in, out, lenght); - } - else - { - ConLog.Error("EDAT: Unknown crypto algorithm!\n"); - return false; - } - - if ((hash_mode & 0xFF) == 0x01) // 0x14 SHA1-HMAC - { - return hmac_hash_compare(hash_final_14, 0x14, in, lenght, test_hash); - } - else if ((hash_mode & 0xFF) == 0x02) // 0x10 AES-CMAC - { - return cmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); - } - else if ((hash_mode & 0xFF) == 0x04) //0x10 SHA1-HMAC - { - return hmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); - } - else - { - ConLog.Error("EDAT: Unknown hashing algorithm!\n"); - return false; - } -} - -unsigned char* dec_section(unsigned char* metadata) -{ - unsigned char *dec = new unsigned char[0x10]; - dec[0x00] = (metadata[0xC] ^ metadata[0x8] ^ metadata[0x10]); - dec[0x01] = (metadata[0xD] ^ metadata[0x9] ^ metadata[0x11]); - dec[0x02] = (metadata[0xE] ^ metadata[0xA] ^ metadata[0x12]); - dec[0x03] = (metadata[0xF] ^ metadata[0xB] ^ metadata[0x13]); - dec[0x04] = (metadata[0x4] ^ metadata[0x8] ^ metadata[0x14]); - dec[0x05] = (metadata[0x5] ^ metadata[0x9] ^ metadata[0x15]); - dec[0x06] = (metadata[0x6] ^ metadata[0xA] ^ metadata[0x16]); - dec[0x07] = (metadata[0x7] ^ metadata[0xB] ^ metadata[0x17]); - dec[0x08] = (metadata[0xC] ^ metadata[0x0] ^ metadata[0x18]); - dec[0x09] = (metadata[0xD] ^ metadata[0x1] ^ metadata[0x19]); - dec[0x0A] = (metadata[0xE] ^ metadata[0x2] ^ metadata[0x1A]); - dec[0x0B] = (metadata[0xF] ^ metadata[0x3] ^ metadata[0x1B]); - dec[0x0C] = (metadata[0x4] ^ metadata[0x0] ^ metadata[0x1C]); - dec[0x0D] = (metadata[0x5] ^ metadata[0x1] ^ metadata[0x1D]); - dec[0x0E] = (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]); - dec[0x0F] = (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]); +void generate_hash(int hash_mode, int version, unsigned char *hash_final, unsigned char *hash) +{ + int mode = (int) (hash_mode & 0xF0000000); + switch (mode) { + case 0x10000000: + // Encrypted HASH. + // Decrypt the hash with EDAT_KEY + EDAT_IV. + aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, hash, hash_final, 0x10); + break; + case 0x20000000: + // Default HASH. + // Use EDAT_HASH. + memcpy(hash_final, version ? EDAT_HASH_1 : EDAT_HASH_0, 0x10); + break; + case 0x00000000: + // Unencrypted ERK. + // Use the original hash. + memcpy(hash_final, hash, 0x10); + break; + }; +} + +bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsigned char *out, int lenght, unsigned char *key, unsigned char *iv, unsigned char *hash, unsigned char *test_hash) +{ + // Setup buffers for key, iv and hash. + unsigned char key_final[0x10] = {}; + unsigned char iv_final[0x10] = {}; + unsigned char hash_final_10[0x10] = {}; + unsigned char hash_final_14[0x14] = {}; + + // Generate crypto key and hash. + generate_key(crypto_mode, version, key_final, iv_final, key, iv); + if ((hash_mode & 0xFF) == 0x01) + generate_hash(hash_mode, version, hash_final_14, hash); + else + generate_hash(hash_mode, version, hash_final_10, hash); + + if ((crypto_mode & 0xFF) == 0x01) // No algorithm. + { + memcpy(out, in, lenght); + } + else if ((crypto_mode & 0xFF) == 0x02) // AES128-CBC + { + aescbc128_decrypt(key_final, iv_final, in, out, lenght); + } + else + { + ConLog.Error("EDAT: Unknown crypto algorithm!\n"); + return false; + } + + if ((hash_mode & 0xFF) == 0x01) // 0x14 SHA1-HMAC + { + return hmac_hash_compare(hash_final_14, 0x14, in, lenght, test_hash); + } + else if ((hash_mode & 0xFF) == 0x02) // 0x10 AES-CMAC + { + return cmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); + } + else if ((hash_mode & 0xFF) == 0x04) //0x10 SHA1-HMAC + { + return hmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); + } + else + { + ConLog.Error("EDAT: Unknown hashing algorithm!\n"); + return false; + } +} + +unsigned char* dec_section(unsigned char* metadata) +{ + unsigned char *dec = new unsigned char[0x10]; + dec[0x00] = (metadata[0xC] ^ metadata[0x8] ^ metadata[0x10]); + dec[0x01] = (metadata[0xD] ^ metadata[0x9] ^ metadata[0x11]); + dec[0x02] = (metadata[0xE] ^ metadata[0xA] ^ metadata[0x12]); + dec[0x03] = (metadata[0xF] ^ metadata[0xB] ^ metadata[0x13]); + dec[0x04] = (metadata[0x4] ^ metadata[0x8] ^ metadata[0x14]); + dec[0x05] = (metadata[0x5] ^ metadata[0x9] ^ metadata[0x15]); + dec[0x06] = (metadata[0x6] ^ metadata[0xA] ^ metadata[0x16]); + dec[0x07] = (metadata[0x7] ^ metadata[0xB] ^ metadata[0x17]); + dec[0x08] = (metadata[0xC] ^ metadata[0x0] ^ metadata[0x18]); + dec[0x09] = (metadata[0xD] ^ metadata[0x1] ^ metadata[0x19]); + dec[0x0A] = (metadata[0xE] ^ metadata[0x2] ^ metadata[0x1A]); + dec[0x0B] = (metadata[0xF] ^ metadata[0x3] ^ metadata[0x1B]); + dec[0x0C] = (metadata[0x4] ^ metadata[0x0] ^ metadata[0x1C]); + dec[0x0D] = (metadata[0x5] ^ metadata[0x1] ^ metadata[0x1D]); + dec[0x0E] = (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]); + dec[0x0F] = (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]); return dec; } -unsigned char* get_block_key(int block, NPD_HEADER *npd) -{ - unsigned char empty_key[0x10] = {}; - unsigned char *src_key = (npd->version <= 1) ? empty_key : npd->dev_hash; - unsigned char *dest_key = new unsigned char[0x10]; - memcpy(dest_key, src_key, 0xC); - dest_key[0xC] = (block >> 24 & 0xFF); - dest_key[0xD] = (block >> 16 & 0xFF); - dest_key[0xE] = (block >> 8 & 0xFF); - dest_key[0xF] = (block & 0xFF); +unsigned char* get_block_key(int block, NPD_HEADER *npd) +{ + unsigned char empty_key[0x10] = {}; + unsigned char *src_key = (npd->version <= 1) ? empty_key : npd->dev_hash; + unsigned char *dest_key = new unsigned char[0x10]; + memcpy(dest_key, src_key, 0xC); + dest_key[0xC] = (block >> 24 & 0xFF); + dest_key[0xD] = (block >> 16 & 0xFF); + dest_key[0xE] = (block >> 8 & 0xFF); + dest_key[0xF] = (block & 0xFF); return dest_key; -} +} // EDAT/SDAT functions. int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, unsigned char* crypt_key, bool verbose) @@ -301,20 +301,17 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np return 0; } -int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFile *f, bool verbose) +static bool check_flags(EDAT_SDAT_HEADER *edat, NPD_HEADER *npd) { - f->Seek(0); - unsigned char *header = new unsigned char[0xA0]; - unsigned char *tmp = new unsigned char[0xA0]; - unsigned char *hash_result = new unsigned char[0x10]; + if (edat == nullptr || npd == nullptr) + return false; - // Check NPD version and EDAT flags. - if ((npd->version == 0) || (npd->version == 1)) + if (npd->version == 0 || npd->version == 1) { if (edat->flags & 0x7EFFFFFE) { ConLog.Error("EDAT: Bad header flags!\n"); - return 1; + return false; } } else if (npd->version == 2) @@ -322,93 +319,113 @@ int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFi if (edat->flags & 0x7EFFFFE0) { ConLog.Error("EDAT: Bad header flags!\n"); - return 1; + return false; } } - else if ((npd->version == 3) || (npd->version == 4)) + else if (npd->version == 3 || npd->version == 4) { if (edat->flags & 0x7EFFFFC0) { ConLog.Error("EDAT: Bad header flags!\n"); - return 1; + return false; } } - else + else if (npd->version > 4) { - ConLog.Error("EDAT: Unknown version!\n"); + ConLog.Error("EDAT: Unknown version - %d\n", npd->version); + return false; + } + + return true; +} + +int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFile *f, bool verbose) +{ + f->Seek(0); + unsigned char *header = new unsigned char[0xA0]; + unsigned char *tmp = new unsigned char[0xA0]; + unsigned char *hash_result = new unsigned char[0x10]; + + // Check NPD version and EDAT flags. + if (!check_flags(edat, npd)) + { + delete[] header; + delete[] tmp; + delete[] hash_result; + return 1; - } - - // Read in the file header. - f->Read(header, 0xA0); - f->Read(hash_result, 0x10); - - // Setup the hashing mode and the crypto mode used in the file. - int crypto_mode = 0x1; - int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002; - if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0) - { - ConLog.Warning("EDAT: DEBUG data detected!\n"); - hash_mode |= 0x01000000; - } - - // Setup header key and iv buffers. - unsigned char header_key[0x10] = {}; - unsigned char header_iv[0x10] = {}; - - // Test the header hash (located at offset 0xA0). - if (!crypto(hash_mode, crypto_mode, (npd->version == 4), header, tmp, 0xA0, header_key, header_iv, key, hash_result)) - { - if (verbose) - ConLog.Warning("EDAT: Header hash is invalid!\n"); - } - - // Parse the metadata info. - int metadata_section_size = 0x10; - if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0)) - { - ConLog.Warning("EDAT: COMPRESSED data detected!\n"); - metadata_section_size = 0x20; - } - - int block_num = (int) ((edat->file_size + edat->block_size - 1) / edat->block_size); - int bytes_read = 0; - int metadata_offset = 0x100; - - long bytes_to_read = metadata_section_size * block_num; - while (bytes_to_read > 0) - { - // Locate the metadata blocks. - int block_size = (0x3C00 > bytes_to_read) ? (int) bytes_to_read : 0x3C00; // 0x3C00 is the maximum block size. - f->Seek(metadata_offset + bytes_read); - unsigned char *data = new unsigned char[block_size]; - - // Read in the metadata. - tmp = new unsigned char[block_size]; - f->Read(data, block_size); - - // Check the generated hash against the metadata hash located at offset 0x90 in the header. - memset(hash_result, 0, 0x10); - f->Seek(0x90); - f->Read(hash_result, 0x10); - - // Generate the hash for this block. - if (!crypto(hash_mode, crypto_mode, (npd->version == 4), data, tmp, block_size, header_key, header_iv, key, hash_result)) - { - if (verbose) - ConLog.Warning("EDAT: Metadata hash from block 0x%08x is invalid!\n", metadata_offset + bytes_read); - } - - // Adjust sizes. - bytes_read += block_size; - bytes_to_read -= block_size; - - delete[] data; + } + + // Read in the file header. + f->Read(header, 0xA0); + f->Read(hash_result, 0x10); + + // Setup the hashing mode and the crypto mode used in the file. + int crypto_mode = 0x1; + int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002; + if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0) + { + ConLog.Warning("EDAT: DEBUG data detected!\n"); + hash_mode |= 0x01000000; + } + + // Setup header key and iv buffers. + unsigned char header_key[0x10] = {}; + unsigned char header_iv[0x10] = {}; + + // Test the header hash (located at offset 0xA0). + if (!crypto(hash_mode, crypto_mode, (npd->version == 4), header, tmp, 0xA0, header_key, header_iv, key, hash_result)) + { + if (verbose) + ConLog.Warning("EDAT: Header hash is invalid!\n"); + } + + // Parse the metadata info. + int metadata_section_size = 0x10; + if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0)) + { + ConLog.Warning("EDAT: COMPRESSED data detected!\n"); + metadata_section_size = 0x20; + } + + int block_num = (int) ((edat->file_size + edat->block_size - 1) / edat->block_size); + int bytes_read = 0; + int metadata_offset = 0x100; + + long bytes_to_read = metadata_section_size * block_num; + while (bytes_to_read > 0) + { + // Locate the metadata blocks. + int block_size = (0x3C00 > bytes_to_read) ? (int) bytes_to_read : 0x3C00; // 0x3C00 is the maximum block size. + f->Seek(metadata_offset + bytes_read); + unsigned char *data = new unsigned char[block_size]; + + // Read in the metadata. + tmp = new unsigned char[block_size]; + f->Read(data, block_size); + + // Check the generated hash against the metadata hash located at offset 0x90 in the header. + memset(hash_result, 0, 0x10); + f->Seek(0x90); + f->Read(hash_result, 0x10); + + // Generate the hash for this block. + if (!crypto(hash_mode, crypto_mode, (npd->version == 4), data, tmp, block_size, header_key, header_iv, key, hash_result)) + { + if (verbose) + ConLog.Warning("EDAT: Metadata hash from block 0x%08x is invalid!\n", metadata_offset + bytes_read); + } + + // Adjust sizes. + bytes_read += block_size; + bytes_to_read -= block_size; + + delete[] data; } // Cleanup. - delete[] header; - delete[] tmp; + delete[] header; + delete[] tmp; delete[] hash_result; return 0; @@ -501,6 +518,8 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un if(memcmp(NPD->magic, npd_magic, 4)) { ConLog.Error("EDAT: File has invalid NPD header."); + delete NPD; + delete EDAT; return 1; } @@ -556,6 +575,8 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un if (!test) { ConLog.Error("EDAT: A valid RAP file is needed!"); + delete NPD; + delete EDAT; return 1; } } @@ -670,4 +691,4 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi input.Close(); output.Close(); return 0; -} +}