Add 4th gen crypto (+PGT specific optional arg)

PGT files are encrypted with the PK4's checksum instead of the PID;
however, the shuffle value is still determined by the PID.
This commit is contained in:
Kurt 2015-12-26 15:55:25 -08:00
parent b990f6c39a
commit 92fe0910fe

View file

@ -495,6 +495,7 @@ namespace PKHeX
ekx = shuffleArray(ekx, sv);
uint seed = pv;
// Encrypt Blocks with RNG Seed
for (int i = 8; i < 232; i += 2)
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekx, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(ekx, i);
@ -572,6 +573,77 @@ namespace PKHeX
return pid;
}
// Past Gen Manipulation
internal static byte[] shuffleG4Array(byte[] data, uint sv)
{
byte[] sdata = new byte[PK4.SIZE_PARTY];
Array.Copy(data, sdata, 8); // Copy unshuffled bytes
// Shuffle Away!
for (int block = 0; block < 4; block++)
Array.Copy(data, 8 + 32 * blockPosition[block][sv], sdata, 8 + 32 * block, 32);
// Fill the Battle Stats back
if (data.Length > 136)
Array.Copy(data, 136, sdata, 136, 100);
return sdata;
}
internal static byte[] decryptG4Array(byte[] ekm, uint seed = 0x10000)
{
byte[] pkm = (byte[])ekm.Clone();
uint pv = BitConverter.ToUInt32(pkm, 0);
uint sv = (((pv & 0x3E000) >> 0xD) % 24);
seed = seed > 0xFFFF ? pv : seed;
// Decrypt Blocks with RNG Seed
for (int i = 8; i < 136; i += 2)
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(pkm, i);
// Deshuffle
pkm = shuffleG4Array(pkm, sv);
// Decrypt the Party Stats
seed = pv;
if (pkm.Length <= 136) return pkm;
for (int i = 136; i < 236; i += 2)
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(pkm, i);
return pkm;
}
internal static byte[] encryptG4Array(byte[] pkm, uint seed = 0x10000)
{
// Shuffle
uint pv = BitConverter.ToUInt32(pkm, 0);
uint sv = (((pv & 0x3E000) >> 0xD) % 24);
byte[] ekm = (byte[])pkm.Clone();
// If I unshuffle 11 times, the 12th (decryption) will always decrypt to ABCD.
// 2 x 3 x 4 = 12 (possible unshuffle loops -> total iterations)
for (int i = 0; i < 11; i++)
ekm = shuffleArray(ekm, sv);
seed = seed > 0xFFFF ? pv : seed;
// Encrypt Blocks with RNG Seed
for (int i = 8; i < 136; i += 2)
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(ekm, i);
// If no party stats, return.
if (ekm.Length <= 136) return ekm;
// Encrypt the Party Stats
seed = pv;
for (int i = 136; i < 236; i += 2)
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(ekm, i);
// Done
return ekm;
}
// SAV Manipulation
/// <summary>Calculates the CRC16-CCITT checksum over an input byte array.</summary>
/// <param name="chunk">Input byte array</param>