Fix some memory leaks in unedat.cpp.

This commit is contained in:
lioncash 2014-03-31 08:56:24 -04:00
parent 01dbb8eb9a
commit e47e37a8d2

View file

@ -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;
}
}