internal static string verifyG6SHA(byte[] savefile, bool oras)
{
string rv = "";
int invalid1 = 0;
// Verify Hashes
#region hash table data
uint[] hashtabledata = {
0x2020, 0x203F, 0x2000, 0x200,
0x2040, 0x2FFF, 0x2020, 0x1000,
0x3000, 0x3FFF, 0x2040, 0x1000,
0x4000, 0x4FFF, 0x2060, 0x1000,
0x5000, 0x5FFF, 0x2080, 0x1000,
0x6000, 0x6FFF, 0x20A0, 0x1000,
0x7000, 0x7FFF, 0x20C0, 0x1000,
0x8000, 0x8FFF, 0x20E0, 0x1000,
0x9000, 0x9FFF, 0x2100, 0x1000,
0xA000, 0xAFFF, 0x2120, 0x1000,
0xB000, 0xBFFF, 0x2140, 0x1000,
0xC000, 0xCFFF, 0x2160, 0x1000,
0xD000, 0xDFFF, 0x2180, 0x1000,
0xE000, 0xEFFF, 0x21A0, 0x1000,
0xF000, 0xFFFF, 0x21C0, 0x1000,
0x10000, 0x10FFF, 0x21E0, 0x1000,
0x11000, 0x11FFF, 0x2200, 0x1000,
0x12000, 0x12FFF, 0x2220, 0x1000,
0x13000, 0x13FFF, 0x2240, 0x1000,
0x14000, 0x14FFF, 0x2260, 0x1000,
0x15000, 0x15FFF, 0x2280, 0x1000,
0x16000, 0x16FFF, 0x22A0, 0x1000,
0x17000, 0x17FFF, 0x22C0, 0x1000,
0x18000, 0x18FFF, 0x22E0, 0x1000,
0x19000, 0x19FFF, 0x2300, 0x1000,
0x1A000, 0x1AFFF, 0x2320, 0x1000,
0x1B000, 0x1BFFF, 0x2340, 0x1000,
0x1C000, 0x1CFFF, 0x2360, 0x1000,
0x1D000, 0x1DFFF, 0x2380, 0x1000,
0x1E000, 0x1EFFF, 0x23A0, 0x1000,
0x1F000, 0x1FFFF, 0x23C0, 0x1000,
0x20000, 0x20FFF, 0x23E0, 0x1000,
0x21000, 0x21FFF, 0x2400, 0x1000,
0x22000, 0x22FFF, 0x2420, 0x1000,
0x23000, 0x23FFF, 0x2440, 0x1000,
0x24000, 0x24FFF, 0x2460, 0x1000,
0x25000, 0x25FFF, 0x2480, 0x1000,
0x26000, 0x26FFF, 0x24A0, 0x1000,
0x27000, 0x27FFF, 0x24C0, 0x1000,
0x28000, 0x28FFF, 0x24E0, 0x1000,
0x29000, 0x29FFF, 0x2500, 0x1000,
0x2A000, 0x2AFFF, 0x2520, 0x1000,
0x2B000, 0x2BFFF, 0x2540, 0x1000,
0x2C000, 0x2CFFF, 0x2560, 0x1000,
0x2D000, 0x2DFFF, 0x2580, 0x1000,
0x2E000, 0x2EFFF, 0x25A0, 0x1000,
0x2F000, 0x2FFFF, 0x25C0, 0x1000,
0x30000, 0x30FFF, 0x25E0, 0x1000,
0x31000, 0x31FFF, 0x2600, 0x1000,
0x32000, 0x32FFF, 0x2620, 0x1000,
0x33000, 0x33FFF, 0x2640, 0x1000,
0x34000, 0x34FFF, 0x2660, 0x1000,
0x35000, 0x35FFF, 0x2680, 0x1000,
0x36000, 0x36FFF, 0x26A0, 0x1000,
0x37000, 0x37FFF, 0x26C0, 0x1000,
0x38000, 0x38FFF, 0x26E0, 0x1000,
0x39000, 0x39FFF, 0x2700, 0x1000,
0x3A000, 0x3AFFF, 0x2720, 0x1000,
0x3B000, 0x3BFFF, 0x2740, 0x1000,
0x3C000, 0x3CFFF, 0x2760, 0x1000,
0x3D000, 0x3DFFF, 0x2780, 0x1000,
0x3E000, 0x3EFFF, 0x27A0, 0x1000,
0x3F000, 0x3FFFF, 0x27C0, 0x1000,
0x40000, 0x40FFF, 0x27E0, 0x1000,
0x41000, 0x41FFF, 0x2800, 0x1000,
0x42000, 0x42FFF, 0x2820, 0x1000,
0x43000, 0x43FFF, 0x2840, 0x1000,
0x44000, 0x44FFF, 0x2860, 0x1000,
0x45000, 0x45FFF, 0x2880, 0x1000,
0x46000, 0x46FFF, 0x28A0, 0x1000,
0x47000, 0x47FFF, 0x28C0, 0x1000,
0x48000, 0x48FFF, 0x28E0, 0x1000,
0x49000, 0x49FFF, 0x2900, 0x1000,
0x4A000, 0x4AFFF, 0x2920, 0x1000,
0x4B000, 0x4BFFF, 0x2940, 0x1000,
0x4C000, 0x4CFFF, 0x2960, 0x1000,
0x4D000, 0x4DFFF, 0x2980, 0x1000,
0x4E000, 0x4EFFF, 0x29A0, 0x1000,
0x4F000, 0x4FFFF, 0x29C0, 0x1000,
0x50000, 0x50FFF, 0x29E0, 0x1000,
0x51000, 0x51FFF, 0x2A00, 0x1000,
0x52000, 0x52FFF, 0x2A20, 0x1000,
0x53000, 0x53FFF, 0x2A40, 0x1000,
0x54000, 0x54FFF, 0x2A60, 0x1000,
0x55000, 0x55FFF, 0x2A80, 0x1000,
0x56000, 0x56FFF, 0x2AA0, 0x1000,
0x57000, 0x57FFF, 0x2AC0, 0x1000,
0x58000, 0x58FFF, 0x2AE0, 0x1000,
0x59000, 0x59FFF, 0x2B00, 0x1000,
0x5A000, 0x5AFFF, 0x2B20, 0x1000,
0x5B000, 0x5BFFF, 0x2B40, 0x1000,
0x5C000, 0x5CFFF, 0x2B60, 0x1000,
0x5D000, 0x5DFFF, 0x2B80, 0x1000,
0x5E000, 0x5EFFF, 0x2BA0, 0x1000,
0x5F000, 0x5FFFF, 0x2BC0, 0x1000,
0x60000, 0x60FFF, 0x2BE0, 0x1000,
0x61000, 0x61FFF, 0x2C00, 0x1000,
0x62000, 0x62FFF, 0x2C20, 0x1000,
0x63000, 0x63FFF, 0x2C40, 0x1000,
0x64000, 0x64FFF, 0x2C60, 0x1000,
0x65000, 0x65FFF, 0x2C80, 0x1000,
0x66000, 0x66FFF, 0x2CA0, 0x1000,
0x67000, 0x67FFF, 0x2CC0, 0x1000,
0x68000, 0x68FFF, 0x2CE0, 0x1000,
0x69000, 0x69FFF, 0x2D00, 0x1000,
0x6A000, 0x6AFFF, 0x2D20, 0x1000,
};
#endregion
SHA256 mySHA256 = SHA256.Create();
for (int i = 0; i < hashtabledata.Length / 4; i++)
{
uint start = hashtabledata[0 + 4 * i];
uint length = hashtabledata[1 + 4 * i] - hashtabledata[0 + 4 * i];
uint offset = hashtabledata[2 + 4 * i];
uint blocksize = hashtabledata[3 + 4 * i];
byte[] zeroarray = new byte[blocksize];
Array.Copy(savefile, start, zeroarray, 0, length + 1);
byte[] hashValue = mySHA256.ComputeHash(zeroarray);
byte[] actualhash = new byte[0x20];
Array.Copy(savefile, offset, actualhash, 0, 0x20);
if (hashValue.SequenceEqual(actualhash)) continue;
invalid1++;
rv += "Invalid: " + hashtabledata[2 + 4 * i].ToString("X5") + " @ " + hashtabledata[0 + 4 * i].ToString("X5") + "-" + hashtabledata[1 + 4 * i].ToString("X5") + Environment.NewLine;
}
rv += "1st SAV: " + (106 - invalid1) + "/" + 106 + Environment.NewLine;
// Check The Second Half of Hashes
int invalid2 = 0;
for (int i = 0; i < hashtabledata.Length; i += 4)
{
hashtabledata[i + 0] += 0x7F000;
hashtabledata[i + 1] += 0x7F000;
hashtabledata[i + 2] += 0x7F000;
}
// Problem with save2 saves is that 0x3000-0x4FFF doesn't use save2 data. Probably different when hashed, but different when stored.
for (int i = 2; i < 4; i++)
{
hashtabledata[i * 4 + 0] -= 0x7F000;
hashtabledata[i * 4 + 1] -= 0x7F000;
}
for (int i = 0; i < hashtabledata.Length / 4; i++)
{
uint start = hashtabledata[0 + 4 * i];
uint length = hashtabledata[1 + 4 * i] - hashtabledata[0 + 4 * i];
uint offset = hashtabledata[2 + 4 * i];
uint blocksize = hashtabledata[3 + 4 * i];
byte[] zeroarray = new byte[blocksize];
Array.Copy(savefile, start, zeroarray, 0, length + 1);
byte[] hashValue = mySHA256.ComputeHash(zeroarray);
byte[] actualhash = new byte[0x20];
Array.Copy(savefile, offset, actualhash, 0, 0x20);
if (hashValue.SequenceEqual(actualhash)) continue;
invalid2++;
rv += "Invalid: " + hashtabledata[2 + 4 * i].ToString("X5") + " @ " + hashtabledata[0 + 4 * i].ToString("X5") + "-" + hashtabledata[1 + 4 * i].ToString("X5") + Environment.NewLine;
}
rv += "2nd SAV: " + (106 - invalid2) + "/" + 106 + Environment.NewLine;
if (invalid1 + invalid2 == (2 * 106))
rv = "None of the IVFC hashes are valid." + Environment.NewLine;
// Check the Upper Level IVFC Hashes
{
byte[] zeroarray = new byte[0x200];
Array.Copy(savefile, 0x2000, zeroarray, 0, 0x20);
byte[] hashValue = mySHA256.ComputeHash(zeroarray);
byte[] actualhash = new byte[0x20];
Array.Copy(savefile, 0x43C, actualhash, 0, 0x20);
if (!hashValue.SequenceEqual(actualhash))
rv += "Invalid: " + 0x2000.ToString("X5") + " @ " + 0x43C.ToString("X3") + Environment.NewLine;
}
{
byte[] zeroarray = new byte[0x200];
Array.Copy(savefile, 0x81000, zeroarray, 0, 0x20);
byte[] hashValue = mySHA256.ComputeHash(zeroarray);
byte[] actualhash = new byte[0x20];
Array.Copy(savefile, 0x30C, actualhash, 0, 0x20);
if (!hashValue.SequenceEqual(actualhash))
rv += "Invalid: " + 0x81000.ToString("X5") + " @ " + 0x30C.ToString("X3") + Environment.NewLine;
}
{
byte[] difihash1 = new byte[0x12C];
byte[] difihash2 = new byte[0x12C];
Array.Copy(savefile, 0x330, difihash1, 0, 0x12C);
Array.Copy(savefile, 0x200, difihash2, 0, 0x12C);
byte[] hashValue1 = mySHA256.ComputeHash(difihash1);
byte[] hashValue2 = mySHA256.ComputeHash(difihash2);
byte[] actualhash = new byte[0x20];
Array.Copy(savefile, 0x16C, actualhash, 0, 0x20);
if (hashValue1.SequenceEqual(actualhash))
rv += "Active DIFI partition is Save 1.";
else if (hashValue2.SequenceEqual(actualhash))
rv += "Active DIFI partition is Save 2.";
else
rv += "ERROR: NO ACTIVE DIFI HASH MATCH";
}
return rv;
}
internal static byte[] writeG6CHK(byte[] savefile, bool oras, int savegame)