Merge pull request #147 from lioncash/mem-leaks

Fix some memleaks in unedat.cpp
This commit is contained in:
Alexandro Sánchez Bach 2014-03-31 21:41:24 +02:00
commit fa4473de49

View file

@ -1,135 +1,135 @@
#include "stdafx.h" #include "stdafx.h"
#include "unedat.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) 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); int mode = (int) (crypto_mode & 0xF0000000);
switch (mode) { switch (mode) {
case 0x10000000: case 0x10000000:
// Encrypted ERK. // Encrypted ERK.
// Decrypt the key with EDAT_KEY + EDAT_IV and copy the original IV. // 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); aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, key, key_final, 0x10);
memcpy(iv_final, iv, 0x10); memcpy(iv_final, iv, 0x10);
break; break;
case 0x20000000: case 0x20000000:
// Default ERK. // Default ERK.
// Use EDAT_KEY and EDAT_IV. // Use EDAT_KEY and EDAT_IV.
memcpy(key_final, version ? EDAT_KEY_1 : EDAT_KEY_0, 0x10); memcpy(key_final, version ? EDAT_KEY_1 : EDAT_KEY_0, 0x10);
memcpy(iv_final, EDAT_IV, 0x10); memcpy(iv_final, EDAT_IV, 0x10);
break; break;
case 0x00000000: case 0x00000000:
// Unencrypted ERK. // Unencrypted ERK.
// Use the original key and iv. // Use the original key and iv.
memcpy(key_final, key, 0x10); memcpy(key_final, key, 0x10);
memcpy(iv_final, iv, 0x10); memcpy(iv_final, iv, 0x10);
break; 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;
};
}
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) void generate_hash(int hash_mode, int version, unsigned char *hash_final, unsigned char *hash)
{ {
// Setup buffers for key, iv and hash. int mode = (int) (hash_mode & 0xF0000000);
unsigned char key_final[0x10] = {}; switch (mode) {
unsigned char iv_final[0x10] = {}; case 0x10000000:
unsigned char hash_final_10[0x10] = {}; // Encrypted HASH.
unsigned char hash_final_14[0x14] = {}; // Decrypt the hash with EDAT_KEY + EDAT_IV.
aescbc128_decrypt(version ? EDAT_KEY_1 : EDAT_KEY_0, EDAT_IV, hash, hash_final, 0x10);
// Generate crypto key and hash. break;
generate_key(crypto_mode, version, key_final, iv_final, key, iv); case 0x20000000:
if ((hash_mode & 0xFF) == 0x01) // Default HASH.
generate_hash(hash_mode, version, hash_final_14, hash); // Use EDAT_HASH.
else memcpy(hash_final, version ? EDAT_HASH_1 : EDAT_HASH_0, 0x10);
generate_hash(hash_mode, version, hash_final_10, hash); break;
case 0x00000000:
if ((crypto_mode & 0xFF) == 0x01) // No algorithm. // Unencrypted ERK.
{ // Use the original hash.
memcpy(out, in, lenght); memcpy(hash_final, hash, 0x10);
} break;
else if ((crypto_mode & 0xFF) == 0x02) // AES128-CBC };
{ }
aescbc128_decrypt(key_final, iv_final, in, out, lenght);
} bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsigned char *out, int length, unsigned char *key, unsigned char *iv, unsigned char *hash, unsigned char *test_hash)
else {
{ // Setup buffers for key, iv and hash.
ConLog.Error("EDAT: Unknown crypto algorithm!\n"); unsigned char key_final[0x10] = {};
return false; unsigned char iv_final[0x10] = {};
} unsigned char hash_final_10[0x10] = {};
unsigned char hash_final_14[0x14] = {};
if ((hash_mode & 0xFF) == 0x01) // 0x14 SHA1-HMAC
{ // Generate crypto key and hash.
return hmac_hash_compare(hash_final_14, 0x14, in, lenght, test_hash); generate_key(crypto_mode, version, key_final, iv_final, key, iv);
} if ((hash_mode & 0xFF) == 0x01)
else if ((hash_mode & 0xFF) == 0x02) // 0x10 AES-CMAC generate_hash(hash_mode, version, hash_final_14, hash);
{ else
return cmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); generate_hash(hash_mode, version, hash_final_10, hash);
}
else if ((hash_mode & 0xFF) == 0x04) //0x10 SHA1-HMAC if ((crypto_mode & 0xFF) == 0x01) // No algorithm.
{ {
return hmac_hash_compare(hash_final_10, 0x10, in, lenght, test_hash); memcpy(out, in, length);
} }
else else if ((crypto_mode & 0xFF) == 0x02) // AES128-CBC
{ {
ConLog.Error("EDAT: Unknown hashing algorithm!\n"); aescbc128_decrypt(key_final, iv_final, in, out, length);
return false; }
} else
} {
ConLog.Error("EDAT: Unknown crypto algorithm!\n");
unsigned char* dec_section(unsigned char* metadata) return false;
{ }
unsigned char *dec = new unsigned char[0x10];
dec[0x00] = (metadata[0xC] ^ metadata[0x8] ^ metadata[0x10]); if ((hash_mode & 0xFF) == 0x01) // 0x14 SHA1-HMAC
dec[0x01] = (metadata[0xD] ^ metadata[0x9] ^ metadata[0x11]); {
dec[0x02] = (metadata[0xE] ^ metadata[0xA] ^ metadata[0x12]); return hmac_hash_compare(hash_final_14, 0x14, in, length, test_hash);
dec[0x03] = (metadata[0xF] ^ metadata[0xB] ^ metadata[0x13]); }
dec[0x04] = (metadata[0x4] ^ metadata[0x8] ^ metadata[0x14]); else if ((hash_mode & 0xFF) == 0x02) // 0x10 AES-CMAC
dec[0x05] = (metadata[0x5] ^ metadata[0x9] ^ metadata[0x15]); {
dec[0x06] = (metadata[0x6] ^ metadata[0xA] ^ metadata[0x16]); return cmac_hash_compare(hash_final_10, 0x10, in, length, test_hash);
dec[0x07] = (metadata[0x7] ^ metadata[0xB] ^ metadata[0x17]); }
dec[0x08] = (metadata[0xC] ^ metadata[0x0] ^ metadata[0x18]); else if ((hash_mode & 0xFF) == 0x04) //0x10 SHA1-HMAC
dec[0x09] = (metadata[0xD] ^ metadata[0x1] ^ metadata[0x19]); {
dec[0x0A] = (metadata[0xE] ^ metadata[0x2] ^ metadata[0x1A]); return hmac_hash_compare(hash_final_10, 0x10, in, length, test_hash);
dec[0x0B] = (metadata[0xF] ^ metadata[0x3] ^ metadata[0x1B]); }
dec[0x0C] = (metadata[0x4] ^ metadata[0x0] ^ metadata[0x1C]); else
dec[0x0D] = (metadata[0x5] ^ metadata[0x1] ^ metadata[0x1D]); {
dec[0x0E] = (metadata[0x6] ^ metadata[0x2] ^ metadata[0x1E]); ConLog.Error("EDAT: Unknown hashing algorithm!\n");
dec[0x0F] = (metadata[0x7] ^ metadata[0x3] ^ metadata[0x1F]); 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; return dec;
} }
unsigned char* get_block_key(int block, NPD_HEADER *npd) unsigned char* get_block_key(int block, NPD_HEADER *npd)
{ {
unsigned char empty_key[0x10] = {}; unsigned char empty_key[0x10] = {};
unsigned char *src_key = (npd->version <= 1) ? empty_key : npd->dev_hash; unsigned char *src_key = (npd->version <= 1) ? empty_key : npd->dev_hash;
unsigned char *dest_key = new unsigned char[0x10]; unsigned char *dest_key = new unsigned char[0x10];
memcpy(dest_key, src_key, 0xC); memcpy(dest_key, src_key, 0xC);
dest_key[0xC] = (block >> 24 & 0xFF); dest_key[0xC] = (block >> 24 & 0xFF);
dest_key[0xD] = (block >> 16 & 0xFF); dest_key[0xD] = (block >> 16 & 0xFF);
dest_key[0xE] = (block >> 8 & 0xFF); dest_key[0xE] = (block >> 8 & 0xFF);
dest_key[0xF] = (block & 0xFF); dest_key[0xF] = (block & 0xFF);
return dest_key; return dest_key;
} }
// EDAT/SDAT functions. // EDAT/SDAT functions.
int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, unsigned char* crypt_key, bool verbose) int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, unsigned char* crypt_key, bool verbose)
@ -147,13 +147,12 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
unsigned char empty_iv[0x10] = {}; unsigned char empty_iv[0x10] = {};
// Decrypt the metadata. // Decrypt the metadata.
int i; for (int i = 0; i < block_num; i++)
for (i = 0; i < block_num; i++)
{ {
in->Seek(metadata_offset + i * metadata_section_size); in->Seek(metadata_offset + i * metadata_section_size);
unsigned char hash_result[0x10]; unsigned char hash_result[0x10];
long offset; long offset;
int lenght; int length = 0;
int compression_end = 0; int compression_end = 0;
if ((edat->flags & EDAT_COMPRESSED_FLAG) != 0) if ((edat->flags & EDAT_COMPRESSED_FLAG) != 0)
@ -164,7 +163,7 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
// If the data is compressed, decrypt the metadata. // If the data is compressed, decrypt the metadata.
unsigned char *result = dec_section(metadata); unsigned char *result = dec_section(metadata);
offset = ((swap32(*(int*)&result[0]) << 4) | (swap32(*(int*)&result[4]))); offset = ((swap32(*(int*)&result[0]) << 4) | (swap32(*(int*)&result[4])));
lenght = swap32(*(int*)&result[8]); length = swap32(*(int*)&result[8]);
compression_end = swap32(*(int*)&result[12]); compression_end = swap32(*(int*)&result[12]);
delete[] result; delete[] result;
@ -173,44 +172,43 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
else if ((edat->flags & EDAT_FLAG_0x20) != 0) else if ((edat->flags & EDAT_FLAG_0x20) != 0)
{ {
// If FLAG 0x20, the metadata precedes each data block. // If FLAG 0x20, the metadata precedes each data block.
in->Seek(metadata_offset + i * metadata_section_size + lenght); in->Seek(metadata_offset + i * metadata_section_size + length);
unsigned char metadata[0x20]; unsigned char metadata[0x20];
in->Read(metadata, 0x20); in->Read(metadata, 0x20);
// If FLAG 0x20 is set, apply custom xor. // If FLAG 0x20 is set, apply custom xor.
int j; for (int j = 0; j < 0x10; j++) {
for (j = 0; j < 0x10; j++) {
hash_result[j] = (unsigned char)(metadata[j] ^ metadata[j+0x10]); hash_result[j] = (unsigned char)(metadata[j] ^ metadata[j+0x10]);
} }
offset = metadata_offset + i * edat->block_size + (i + 1) * metadata_section_size; offset = metadata_offset + i * edat->block_size + (i + 1) * metadata_section_size;
lenght = edat->block_size; length = edat->block_size;
if ((i == (block_num - 1)) && (edat->file_size % edat->block_size)) if ((i == (block_num - 1)) && (edat->file_size % edat->block_size))
lenght = (int) (edat->file_size % edat->block_size); length = (int) (edat->file_size % edat->block_size);
} }
else else
{ {
in->Read(hash_result, 0x10); in->Read(hash_result, 0x10);
offset = metadata_offset + i * edat->block_size + block_num * metadata_section_size; offset = metadata_offset + i * edat->block_size + block_num * metadata_section_size;
lenght = edat->block_size; length = edat->block_size;
if ((i == (block_num - 1)) && (edat->file_size % edat->block_size)) if ((i == (block_num - 1)) && (edat->file_size % edat->block_size))
lenght = (int) (edat->file_size % edat->block_size); length = (int) (edat->file_size % edat->block_size);
} }
// Locate the real data. // Locate the real data.
int pad_lenght = lenght; int pad_length = length;
lenght = (int) ((pad_lenght + 0xF) & 0xFFFFFFF0); length = (int) ((pad_length + 0xF) & 0xFFFFFFF0);
in->Seek(offset); in->Seek(offset);
// Setup buffers for decryption and read the data. // Setup buffers for decryption and read the data.
enc_data = new unsigned char[lenght]; enc_data = new unsigned char[length];
dec_data = new unsigned char[lenght]; dec_data = new unsigned char[length];
unsigned char key_result[0x10]; unsigned char key_result[0x10];
unsigned char hash[0x10]; unsigned char hash[0x10];
in->Read(enc_data, lenght); in->Read(enc_data, length);
// Generate a key for the current block. // Generate a key for the current block.
b_key = get_block_key(i, npd); b_key = get_block_key(i, npd);
@ -245,14 +243,14 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
crypto_mode |= 0x01000000; crypto_mode |= 0x01000000;
hash_mode |= 0x01000000; hash_mode |= 0x01000000;
// Simply copy the data without the header or the footer. // Simply copy the data without the header or the footer.
memcpy(dec_data, enc_data, lenght); memcpy(dec_data, enc_data, length);
} }
else else
{ {
// IV is null if NPD version is 1 or 0. // IV is null if NPD version is 1 or 0.
iv = (npd->version <= 1) ? empty_iv : npd->digest; iv = (npd->version <= 1) ? empty_iv : npd->digest;
// Call main crypto routine on this data block. // Call main crypto routine on this data block.
crypto(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, lenght, key_result, iv, hash, hash_result); crypto(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, length, key_result, iv, hash, hash_result);
} }
// Apply additional compression if needed and write the decrypted data. // Apply additional compression if needed and write the decrypted data.
@ -270,7 +268,7 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
if (verbose) if (verbose)
{ {
ConLog.Write("EDAT: Compressed block size: %d\n", pad_lenght); ConLog.Write("EDAT: Compressed block size: %d\n", pad_length);
ConLog.Write("EDAT: Decompressed block size: %d\n", res); ConLog.Write("EDAT: Decompressed block size: %d\n", res);
} }
@ -291,7 +289,7 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
} }
else else
{ {
out->Write(dec_data, pad_lenght); out->Write(dec_data, pad_length);
} }
delete[] enc_data; delete[] enc_data;
@ -301,20 +299,17 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
return 0; 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); if (edat == nullptr || npd == nullptr)
unsigned char *header = new unsigned char[0xA0]; return false;
unsigned char *tmp = new unsigned char[0xA0];
unsigned char *hash_result = new unsigned char[0x10];
// Check NPD version and EDAT flags. if (npd->version == 0 || npd->version == 1)
if ((npd->version == 0) || (npd->version == 1))
{ {
if (edat->flags & 0x7EFFFFFE) if (edat->flags & 0x7EFFFFFE)
{ {
ConLog.Error("EDAT: Bad header flags!\n"); ConLog.Error("EDAT: Bad header flags!\n");
return 1; return false;
} }
} }
else if (npd->version == 2) else if (npd->version == 2)
@ -322,93 +317,113 @@ int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFi
if (edat->flags & 0x7EFFFFE0) if (edat->flags & 0x7EFFFFE0)
{ {
ConLog.Error("EDAT: Bad header flags!\n"); 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) if (edat->flags & 0x7EFFFFC0)
{ {
ConLog.Error("EDAT: Bad header flags!\n"); 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; return 1;
} }
// Read in the file header. // Read in the file header.
f->Read(header, 0xA0); f->Read(header, 0xA0);
f->Read(hash_result, 0x10); f->Read(hash_result, 0x10);
// Setup the hashing mode and the crypto mode used in the file. // Setup the hashing mode and the crypto mode used in the file.
int crypto_mode = 0x1; int crypto_mode = 0x1;
int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002; int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002;
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0) if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
{ {
ConLog.Warning("EDAT: DEBUG data detected!\n"); ConLog.Warning("EDAT: DEBUG data detected!\n");
hash_mode |= 0x01000000; hash_mode |= 0x01000000;
} }
// Setup header key and iv buffers. // Setup header key and iv buffers.
unsigned char header_key[0x10] = {}; unsigned char header_key[0x10] = {};
unsigned char header_iv[0x10] = {}; unsigned char header_iv[0x10] = {};
// Test the header hash (located at offset 0xA0). // 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 (!crypto(hash_mode, crypto_mode, (npd->version == 4), header, tmp, 0xA0, header_key, header_iv, key, hash_result))
{ {
if (verbose) if (verbose)
ConLog.Warning("EDAT: Header hash is invalid!\n"); ConLog.Warning("EDAT: Header hash is invalid!\n");
} }
// Parse the metadata info. // Parse the metadata info.
int metadata_section_size = 0x10; int metadata_section_size = 0x10;
if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0)) if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0))
{ {
ConLog.Warning("EDAT: COMPRESSED data detected!\n"); ConLog.Warning("EDAT: COMPRESSED data detected!\n");
metadata_section_size = 0x20; metadata_section_size = 0x20;
} }
int block_num = (int) ((edat->file_size + edat->block_size - 1) / edat->block_size); int block_num = (int) ((edat->file_size + edat->block_size - 1) / edat->block_size);
int bytes_read = 0; int bytes_read = 0;
int metadata_offset = 0x100; int metadata_offset = 0x100;
long bytes_to_read = metadata_section_size * block_num; long bytes_to_read = metadata_section_size * block_num;
while (bytes_to_read > 0) while (bytes_to_read > 0)
{ {
// Locate the metadata blocks. // Locate the metadata blocks.
int block_size = (0x3C00 > bytes_to_read) ? (int) bytes_to_read : 0x3C00; // 0x3C00 is the maximum block size. int block_size = (0x3C00 > bytes_to_read) ? (int) bytes_to_read : 0x3C00; // 0x3C00 is the maximum block size.
f->Seek(metadata_offset + bytes_read); f->Seek(metadata_offset + bytes_read);
unsigned char *data = new unsigned char[block_size]; unsigned char *data = new unsigned char[block_size];
// Read in the metadata. // Read in the metadata.
tmp = new unsigned char[block_size]; tmp = new unsigned char[block_size];
f->Read(data, block_size); f->Read(data, block_size);
// Check the generated hash against the metadata hash located at offset 0x90 in the header. // Check the generated hash against the metadata hash located at offset 0x90 in the header.
memset(hash_result, 0, 0x10); memset(hash_result, 0, 0x10);
f->Seek(0x90); f->Seek(0x90);
f->Read(hash_result, 0x10); f->Read(hash_result, 0x10);
// Generate the hash for this block. // 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 (!crypto(hash_mode, crypto_mode, (npd->version == 4), data, tmp, block_size, header_key, header_iv, key, hash_result))
{ {
if (verbose) if (verbose)
ConLog.Warning("EDAT: Metadata hash from block 0x%08x is invalid!\n", metadata_offset + bytes_read); ConLog.Warning("EDAT: Metadata hash from block 0x%08x is invalid!\n", metadata_offset + bytes_read);
} }
// Adjust sizes. // Adjust sizes.
bytes_read += block_size; bytes_read += block_size;
bytes_to_read -= block_size; bytes_to_read -= block_size;
delete[] data; delete[] data;
} }
// Cleanup. // Cleanup.
delete[] header; delete[] header;
delete[] tmp; delete[] tmp;
delete[] hash_result; delete[] hash_result;
return 0; return 0;
@ -501,6 +516,8 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un
if(memcmp(NPD->magic, npd_magic, 4)) if(memcmp(NPD->magic, npd_magic, 4))
{ {
ConLog.Error("EDAT: File has invalid NPD header."); ConLog.Error("EDAT: File has invalid NPD header.");
delete NPD;
delete EDAT;
return 1; return 1;
} }
@ -556,6 +573,8 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un
if (!test) if (!test)
{ {
ConLog.Error("EDAT: A valid RAP file is needed!"); ConLog.Error("EDAT: A valid RAP file is needed!");
delete NPD;
delete EDAT;
return 1; return 1;
} }
} }
@ -670,4 +689,4 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi
input.Close(); input.Close();
output.Close(); output.Close();
return 0; return 0;
} }