mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-28 15:00:36 +00:00
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:
parent
b990f6c39a
commit
92fe0910fe
1 changed files with 72 additions and 0 deletions
72
Misc/PKX.cs
72
Misc/PKX.cs
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue