mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-09-15 07:57:24 -05:00
pkm crypto Refactoring r2
condense repeated logic, reduce overall operations removes 1 array alloc for pkm encryption (shuffle clones the array, so don't clone->clone) removes 1 array alloc for pkm decryption (mutate encrypted array), be aware that no current use cases input an encrypted region and expect the reference to stay encrypted (always was a temp array). remove duplicate bounds checks (early return & for loop)
This commit is contained in:
@@ -24,7 +24,7 @@ public BK4(byte[] decryptedData = null, string ident = null)
|
||||
{
|
||||
Data = decryptedData ?? new byte[SIZE_PARTY];
|
||||
uint sv = ((PID & 0x3E000) >> 0xD) % 24;
|
||||
Data = PKX.ShuffleArray45(Data, sv);
|
||||
Data = PKX.ShuffleArray(Data, sv, PKX.SIZE_4BLOCK);
|
||||
Identifier = ident;
|
||||
if (Sanity != 0 && Species <= MaxSpeciesID && !ChecksumValid) // We can only hope
|
||||
RefreshChecksum();
|
||||
@@ -388,7 +388,7 @@ protected override ushort CalculateChecksum()
|
||||
protected override byte[] Encrypt()
|
||||
{
|
||||
RefreshChecksum();
|
||||
return PKX.ShuffleArray45(Data, PKX.blockPositionInvert[((PID & 0x3E000) >> 0xD)%24]);
|
||||
return PKX.ShuffleArray(Data, PKX.blockPositionInvert[((PID & 0x3E000) >> 0xD)%24], PKX.SIZE_4BLOCK);
|
||||
}
|
||||
|
||||
public PK4 ConvertToPK4()
|
||||
|
||||
@@ -377,83 +377,108 @@ public static int GetGenderFromString(string s)
|
||||
/// </summary>
|
||||
/// <param name="data">Data to shuffle</param>
|
||||
/// <param name="sv">Block Shuffle order</param>
|
||||
/// <param name="blockSize">Size of shuffling chunks</param>
|
||||
/// <returns>Shuffled byte array</returns>
|
||||
public static byte[] ShuffleArray(byte[] data, uint sv)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static byte[] ShuffleArray(byte[] data, uint sv, int blockSize)
|
||||
{
|
||||
byte[] sdata = new byte[data.Length];
|
||||
Array.Copy(data, sdata, 8); // Copy unshuffled bytes
|
||||
|
||||
// Shuffle Away!
|
||||
byte[] sdata = (byte[])data.Clone();
|
||||
for (int block = 0; block < 4; block++)
|
||||
Array.Copy(data, 8 + 56*blockPosition[block][sv], sdata, 8 + 56*block, 56);
|
||||
|
||||
// Fill the Battle Stats back
|
||||
if (data.Length > 232)
|
||||
Array.Copy(data, 232, sdata, 232, 28);
|
||||
|
||||
Array.Copy(data, 8 + blockSize * blockPosition[block][sv], sdata, 8 + blockSize * block, blockSize);
|
||||
return sdata;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts a 232 byte + party stat byte array.
|
||||
/// </summary>
|
||||
/// <param name="ekx">Encrypted <see cref="PKM"/> data.</param>
|
||||
/// <param name="ekm">Encrypted <see cref="PKM"/> data.</param>
|
||||
/// <returns>Decrypted <see cref="PKM"/> data.</returns>
|
||||
/// <returns>Encrypted <see cref="PKM"/> data.</returns>
|
||||
public static byte[] DecryptArray(byte[] ekx)
|
||||
public static byte[] DecryptArray(byte[] ekm)
|
||||
{
|
||||
byte[] pkx = (byte[])ekx.Clone();
|
||||
|
||||
uint pv = BitConverter.ToUInt32(pkx, 0);
|
||||
uint pv = BitConverter.ToUInt32(ekm, 0);
|
||||
uint sv = (pv >> 0xD & 0x1F) % 24;
|
||||
|
||||
uint seed = pv;
|
||||
|
||||
// Decrypt Blocks with RNG Seed
|
||||
for (int i = 8; i < 232; i += 2)
|
||||
Crypt(pkx, ref seed, i);
|
||||
|
||||
// Deshuffle
|
||||
pkx = ShuffleArray(pkx, sv);
|
||||
|
||||
// Decrypt the Party Stats
|
||||
seed = pv;
|
||||
if (pkx.Length <= 232) return pkx;
|
||||
for (int i = 232; i < 260; i += 2)
|
||||
Crypt(pkx, ref seed, i);
|
||||
|
||||
return pkx;
|
||||
CryptPKM(ekm, pv, SIZE_6BLOCK);
|
||||
return ShuffleArray(ekm, sv, SIZE_6BLOCK);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts a 232 byte + party stat byte array.
|
||||
/// </summary>
|
||||
/// <param name="pkx">Decrypted <see cref="PKM"/> data.</param>
|
||||
public static byte[] EncryptArray(byte[] pkx)
|
||||
/// <param name="pkm">Decrypted <see cref="PKM"/> data.</param>
|
||||
public static byte[] EncryptArray(byte[] pkm)
|
||||
{
|
||||
// Shuffle
|
||||
uint pv = BitConverter.ToUInt32(pkx, 0);
|
||||
uint pv = BitConverter.ToUInt32(pkm, 0);
|
||||
uint sv = (pv >> 0xD & 0x1F) % 24;
|
||||
|
||||
byte[] ekx = (byte[])pkx.Clone();
|
||||
byte[] ekm = ShuffleArray(pkm, blockPositionInvert[sv], SIZE_6BLOCK);
|
||||
CryptPKM(ekm, pv, SIZE_6BLOCK);
|
||||
return ekm;
|
||||
}
|
||||
|
||||
ekx = ShuffleArray(ekx, blockPositionInvert[sv]);
|
||||
/// <summary>
|
||||
/// Decrypts a 136 byte + party stat byte array.
|
||||
/// </summary>
|
||||
/// <param name="ekm">Encrypted <see cref="PKM"/> data.</param>
|
||||
/// <returns>Decrypted <see cref="PKM"/> data.</returns>
|
||||
public static byte[] DecryptArray45(byte[] ekm)
|
||||
{
|
||||
uint pv = BitConverter.ToUInt32(ekm, 0);
|
||||
uint chk = BitConverter.ToUInt16(ekm, 6);
|
||||
uint sv = (pv >> 0xD & 0x1F) % 24;
|
||||
|
||||
uint seed = pv;
|
||||
CryptPKM45(ekm, pv, chk, SIZE_4BLOCK);
|
||||
return ShuffleArray(ekm, sv, SIZE_4BLOCK);
|
||||
}
|
||||
|
||||
// Encrypt Blocks with RNG Seed
|
||||
for (int i = 8; i < 232; i += 2)
|
||||
Crypt(ekx, ref seed, i);
|
||||
/// <summary>
|
||||
/// Encrypts a 136 byte + party stat byte array.
|
||||
/// </summary>
|
||||
/// <param name="pkm">Decrypted <see cref="PKM"/> data.</param>
|
||||
/// <returns>Encrypted <see cref="PKM"/> data.</returns>
|
||||
public static byte[] EncryptArray45(byte[] pkm)
|
||||
{
|
||||
uint pv = BitConverter.ToUInt32(pkm, 0);
|
||||
uint chk = BitConverter.ToUInt16(pkm, 6);
|
||||
uint sv = (pv >> 0xD & 0x1F) % 24;
|
||||
|
||||
// If no party stats, return.
|
||||
if (ekx.Length <= 232) return ekx;
|
||||
byte[] ekm = ShuffleArray(pkm, blockPositionInvert[sv], SIZE_4BLOCK);
|
||||
CryptPKM45(ekm, pv, chk, SIZE_4BLOCK);
|
||||
return ekm;
|
||||
}
|
||||
|
||||
// Encrypt the Party Stats
|
||||
seed = pv;
|
||||
for (int i = 232; i < 260; i += 2)
|
||||
Crypt(ekx, ref seed, i);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void CryptPKM(byte[] data, uint pv, int blockSize)
|
||||
{
|
||||
const int start = 8;
|
||||
int end = 4 * blockSize + start;
|
||||
CryptArray(data, pv, 8, end); // Blocks
|
||||
CryptArray(data, pv, end, data.Length); // Party Stats
|
||||
}
|
||||
|
||||
return ekx;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void CryptPKM45(byte[] data, uint pv, uint chk, int blockSize)
|
||||
{
|
||||
const int start = 8;
|
||||
int end = 4 * blockSize + start;
|
||||
CryptArray(data, chk, start, end); // Blocks
|
||||
CryptArray(data, pv, end, data.Length); // Party Stats
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void CryptArray(byte[] data, uint seed, int start, int end)
|
||||
{
|
||||
for (int i = start; i < end; i += 2)
|
||||
Crypt(data, ref seed, i);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Crypt(byte[] data, ref uint seed, int i)
|
||||
{
|
||||
seed = 0x41C64E6D * seed + 0x00006073;
|
||||
data[i] ^= (byte)(seed >> 16);
|
||||
data[i + 1] ^= (byte)(seed >> 24);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -611,102 +636,6 @@ public static int[] SetHPIVs(int type, int[] ivs)
|
||||
{ 1, 1, 1, 1, 1, 1 }, // Dark
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Shuffles a 136 byte array containing <see cref="PKM"/> data.
|
||||
/// </summary>
|
||||
/// <param name="data">Data to shuffle</param>
|
||||
/// <param name="sv">Block Shuffle order</param>
|
||||
/// <returns>Shuffled byte array</returns>
|
||||
public static byte[] ShuffleArray45(byte[] data, uint sv)
|
||||
{
|
||||
byte[] sdata = new byte[data.Length];
|
||||
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, data.Length - 136);
|
||||
|
||||
return sdata;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts a 136 byte + party stat byte array.
|
||||
/// </summary>
|
||||
/// <param name="ekm">Encrypted <see cref="PKM"/> data.</param>
|
||||
/// <returns>Decrypted <see cref="PKM"/> data.</returns>
|
||||
public static byte[] DecryptArray45(byte[] ekm)
|
||||
{
|
||||
byte[] pkm = (byte[])ekm.Clone();
|
||||
|
||||
uint pv = BitConverter.ToUInt32(pkm, 0);
|
||||
uint chk = BitConverter.ToUInt16(pkm, 6);
|
||||
uint sv = ((pv & 0x3E000) >> 0xD) % 24;
|
||||
|
||||
uint seed = chk;
|
||||
|
||||
// Decrypt Blocks with RNG Seed
|
||||
for (int i = 8; i < 136; i += 2)
|
||||
Crypt(pkm, ref seed, i);
|
||||
|
||||
// Deshuffle
|
||||
pkm = ShuffleArray45(pkm, sv);
|
||||
|
||||
// Decrypt the Party Stats
|
||||
seed = pv;
|
||||
if (pkm.Length <= 136) return pkm;
|
||||
for (int i = 136; i < pkm.Length; i += 2)
|
||||
Crypt(pkm, ref seed, i);
|
||||
|
||||
return pkm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts a 136 byte + party stat byte array.
|
||||
/// </summary>
|
||||
/// <param name="pkm">Decrypted <see cref="PKM"/> data.</param>
|
||||
/// <returns>Encrypted <see cref="PKM"/> data.</returns>
|
||||
public static byte[] EncryptArray45(byte[] pkm)
|
||||
{
|
||||
uint pv = BitConverter.ToUInt32(pkm, 0);
|
||||
uint sv = ((pv & 0x3E000) >> 0xD) % 24;
|
||||
|
||||
uint chk = BitConverter.ToUInt16(pkm, 6);
|
||||
byte[] ekm = (byte[])pkm.Clone();
|
||||
|
||||
ekm = ShuffleArray45(ekm, blockPositionInvert[sv]);
|
||||
|
||||
uint seed = chk;
|
||||
|
||||
// Encrypt Blocks with RNG Seed
|
||||
for (int i = 8; i < 136; i += 2)
|
||||
Crypt(ekm, ref seed, i);
|
||||
|
||||
// If no party stats, return.
|
||||
if (ekm.Length <= 136) return ekm;
|
||||
|
||||
// Encrypt the Party Stats
|
||||
seed = pv;
|
||||
for (int i = 136; i < ekm.Length; i += 2)
|
||||
Crypt(ekm, ref seed, i);
|
||||
|
||||
// Done
|
||||
return ekm;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Crypt(byte[] data, ref uint seed, int i)
|
||||
{
|
||||
var val = data[i] | data[i + 1] << 8;
|
||||
seed = 0x41C64E6D * seed + 0x00006073;
|
||||
val ^= (ushort)(seed >> 16);
|
||||
data[i] = (byte)val;
|
||||
data[i + 1] = (byte)(val >> 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Unown Forme ID from PID.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user