diff --git a/PKHeX.Core/Saves/Encryption/MemeCrypto/MemeKey.cs b/PKHeX.Core/Saves/Encryption/MemeCrypto/MemeKey.cs index 14b49e601..06b9e6263 100644 --- a/PKHeX.Core/Saves/Encryption/MemeCrypto/MemeKey.cs +++ b/PKHeX.Core/Saves/Encryption/MemeCrypto/MemeKey.cs @@ -5,6 +5,9 @@ using System.Security.Cryptography; namespace PKHeX.Core { + /// + /// Key for crypto with binaries. + /// public sealed class MemeKey { /// Distinguished Encoding Rules @@ -82,7 +85,8 @@ namespace PKHeX.Core { var curblock = new byte[0x10]; Array.Copy(data, ((data.Length / 0x10) - 1 - i) * 0x10, curblock, 0, 0x10); - temp = AesEcbDecrypt(key, temp.Xor(curblock)); + var temp1 = Xor(temp, curblock); + temp = AesEcbDecrypt(key, temp1); temp.CopyTo(outdata, ((data.Length / 0x10) - 1 - i) * 0x10); } @@ -93,7 +97,7 @@ namespace PKHeX.Core // Well, (a ^ a) = 0. so (block first ^ subkey) ^ (block last ^ subkey) // = block first ^ block last ;) Array.Copy(outdata, ((data.Length / 0x10) - 1) * 0x10, temp, 0, 0x10); - temp = temp.Xor(outdata.Slice(0, 0x10)); + temp = Xor(temp, outdata.Slice(0, 0x10)); for (var ofs = 0; ofs < 0x10; ofs += 2) // Imperfect ROL implementation { byte b1 = temp[ofs + 0], b2 = temp[ofs + 1]; @@ -109,7 +113,8 @@ namespace PKHeX.Core { var curblock = new byte[0x10]; Array.Copy(outdata, 0x10 * i, curblock, 0, 0x10); - Array.Copy(curblock.Xor(subkey), 0, outdata, 0x10 * i, 0x10); + var temp1 = Xor(curblock, subkey); + Array.Copy(temp1, 0, outdata, 0x10 * i, 0x10); } // Now we have Phase1Encrypt(buf). @@ -118,7 +123,9 @@ namespace PKHeX.Core { var curblock = new byte[0x10]; Array.Copy(outdata, i * 0x10, curblock, 0, 0x10); - AesEcbDecrypt(key, curblock).Xor(temp).CopyTo(outdata, i * 0x10); + var temp1 = AesEcbDecrypt(key, curblock); + var temp2 = Xor(temp1, temp); + temp2.CopyTo(outdata, i * 0x10); curblock.CopyTo(temp, 0); } @@ -143,12 +150,14 @@ namespace PKHeX.Core { var curblock = new byte[0x10]; Array.Copy(data, i * 0x10, curblock, 0, 0x10); - temp = AesEcbEncrypt(key, temp.Xor(curblock)); + var temp1 = Xor(temp, curblock); + temp = AesEcbEncrypt(key, temp1); temp.CopyTo(outdata, i * 0x10); } // In between - CMAC stuff - temp = temp.Xor(outdata.Slice(0, 0x10)); + var inbet = outdata.Slice(0, 0x10); + temp = Xor(temp, inbet); for (var ofs = 0; ofs < 0x10; ofs += 2) // Imperfect ROL implementation { byte b1 = temp[ofs + 0], b2 = temp[ofs + 1]; @@ -165,8 +174,10 @@ namespace PKHeX.Core { var curblock = new byte[0x10]; Array.Copy(outdata, ((data.Length / 0x10) - 1 - i) * 0x10, curblock, 0, 0x10); - byte[] temp2 = curblock.Xor(subkey); - Array.Copy(AesEcbEncrypt(key, temp2).Xor(temp), 0, outdata, ((data.Length / 0x10) - 1 - i) * 0x10, 0x10); + byte[] temp2 = Xor(curblock, subkey); + byte[] temp3 = AesEcbEncrypt(key, temp2); + byte[] temp4 = Xor(temp3, temp); + Array.Copy(temp4, 0, outdata, ((data.Length / 0x10) - 1 - i) * 0x10, 0x10); temp2.CopyTo(temp, 0); } @@ -176,6 +187,16 @@ namespace PKHeX.Core return outbuf; } + private static byte[] Xor(byte[] b1, byte[] b2) + { + if (b1.Length != b2.Length) + throw new ArgumentException("Cannot xor two arrays of uneven length!"); + var x = new byte[b1.Length]; + for (var i = 0; i < b1.Length; i++) + x[i] = (byte)(b1[i] ^ b2[i]); + return x; + } + /// /// Perform Rsa Decryption /// @@ -300,55 +321,4 @@ namespace PKHeX.Core private static readonly byte[] D_3 = "00775455668FFF3CBA3026C2D0B26B8085895958341157AEB03B6B0495EE57803E2186EB6CB2EB62A71DF18A3C9C6579077670961B3A6102DABE5A194AB58C3250AED597FC78978A326DB1D7B28DCCCB2A3E014EDBD397AD33B8F28CD525054251".ToByteArray(); #endregion } - - public static class StringExtentions - { - public static byte[] ToByteArray(this string toTransform) - { - var result = new byte[toTransform.Length / 2]; - for (int i = 0; i < result.Length; i++) - { - var ofs = i << 1; - var _0 = toTransform[ofs + 0]; - var _1 = toTransform[ofs + 1]; - result[i] = DecodeTuple(_0, _1); - } - return result; - } - - private static bool IsNum(char c) => (uint)(c - '0') <= 9; - private static bool IsHexUpper(char c) => (uint)(c - 'A') <= 5; - - private static byte DecodeTuple(char _0, char _1) - { - byte result; - if (IsNum(_0)) - result = (byte)((_0 - '0') << 4); - else if (IsHexUpper(_0)) - result = (byte)((_0 - 'A' + 10) << 4); - else - throw new ArgumentOutOfRangeException(nameof(_0)); - - if (IsNum(_1)) - result |= (byte)(_1 - '0'); - else if (IsHexUpper(_1)) - result |= (byte)(_1 - 'A' + 10); - else - throw new ArgumentOutOfRangeException(nameof(_1)); - return result; - } - } - - public static class ByteArrayExtensions - { - public static byte[] Xor(this byte[] b1, byte[] b2) - { - if (b1.Length != b2.Length) - throw new ArgumentException("Cannot xor two arrays of uneven length!"); - var x = new byte[b1.Length]; - for (var i = 0; i < b1.Length; i++) - x[i] = (byte)(b1[i] ^ b2[i]); - return x; - } - } -} \ No newline at end of file +} diff --git a/PKHeX.Core/Saves/Encryption/MemeCrypto/MemeKeyIndex.cs b/PKHeX.Core/Saves/Encryption/MemeCrypto/MemeKeyIndex.cs index 989e7b33e..b2db0bca6 100644 --- a/PKHeX.Core/Saves/Encryption/MemeCrypto/MemeKeyIndex.cs +++ b/PKHeX.Core/Saves/Encryption/MemeCrypto/MemeKeyIndex.cs @@ -1,5 +1,8 @@ namespace PKHeX.Core { + /// + /// Different Key Types used for + /// public enum MemeKeyIndex { LocalWireless = -1, @@ -18,4 +21,4 @@ namespace PKHeX.Core Unknown12 = 12, Unknown13 = 13 } -} \ No newline at end of file +} diff --git a/PKHeX.Core/Saves/SAV3XD.cs b/PKHeX.Core/Saves/SAV3XD.cs index fa47da65b..9fa2a989b 100644 --- a/PKHeX.Core/Saves/SAV3XD.cs +++ b/PKHeX.Core/Saves/SAV3XD.cs @@ -74,7 +74,7 @@ namespace PKHeX.Core keys[i] = BigEndian.ToUInt16(slot, 8 + (i * 2)); // Decrypt Slot - Data = GCSaveUtil.Decrypt(slot, 0x00010, 0x27FD8, keys); + Data = GeniusCrypto.Decrypt(slot, 0x00010, 0x27FD8, keys); } // Get Offset Info @@ -140,7 +140,7 @@ namespace PKHeX.Core ushort[] keys = new ushort[4]; for (int i = 0; i < keys.Length; i++) keys[i] = BigEndian.ToUInt16(Data, 8 + (i * 2)); - byte[] newSAV = GCSaveUtil.Encrypt(Data, 0x10, 0x27FD8, keys); + byte[] newSAV = GeniusCrypto.Encrypt(Data, 0x10, 0x27FD8, keys); // Put save slot back in original save data byte[] newFile = MC != null ? MC.SelectedSaveData : (byte[]) State.BAK.Clone(); diff --git a/PKHeX.Core/Saves/SAV4BR.cs b/PKHeX.Core/Saves/SAV4BR.cs index 5dc083b32..6549cdfe7 100644 --- a/PKHeX.Core/Saves/SAV4BR.cs +++ b/PKHeX.Core/Saves/SAV4BR.cs @@ -235,7 +235,7 @@ namespace PKHeX.Core { var keys = GetKeys(input, i); Array.Copy(input, i, output, i, 8); - GCSaveUtil.Decrypt(input, i + 8, i + 0x1C0000, keys, output); + GeniusCrypto.Decrypt(input, i + 8, i + 0x1C0000, keys, output); } return output; } @@ -247,7 +247,7 @@ namespace PKHeX.Core { var keys = GetKeys(input, i); Array.Copy(input, i, output, i, 8); - GCSaveUtil.Encrypt(input, i + 8, i + 0x1C0000, keys, output); + GeniusCrypto.Encrypt(input, i + 8, i + 0x1C0000, keys, output); } return output; } diff --git a/PKHeX.Core/Util/StringUtil.cs b/PKHeX.Core/Util/StringUtil.cs index c97dd47dc..120a49e3b 100644 --- a/PKHeX.Core/Util/StringUtil.cs +++ b/PKHeX.Core/Util/StringUtil.cs @@ -77,5 +77,43 @@ namespace PKHeX.Core } return -1; } + + /// + /// Converts an all-caps hex string to a byte array. + /// + public static byte[] ToByteArray(this string toTransform) + { + var result = new byte[toTransform.Length / 2]; + for (int i = 0; i < result.Length; i++) + { + var ofs = i << 1; + var _0 = toTransform[ofs + 0]; + var _1 = toTransform[ofs + 1]; + result[i] = DecodeTuple(_0, _1); + } + return result; + } + + private static bool IsNum(char c) => (uint)(c - '0') <= 9; + private static bool IsHexUpper(char c) => (uint)(c - 'A') <= 5; + + private static byte DecodeTuple(char _0, char _1) + { + byte result; + if (IsNum(_0)) + result = (byte)((_0 - '0') << 4); + else if (IsHexUpper(_0)) + result = (byte)((_0 - 'A' + 10) << 4); + else + throw new ArgumentOutOfRangeException(nameof(_0)); + + if (IsNum(_1)) + result |= (byte)(_1 - '0'); + else if (IsHexUpper(_1)) + result |= (byte)(_1 - 'A' + 10); + else + throw new ArgumentOutOfRangeException(nameof(_1)); + return result; + } } }