public static bool VerifyMemeData(byte[] input, out byte[] output, MemeKeyIndex keyIndex) { output = null; if (input.Length < 0x60) { return(false); } var memekey = new MemeKey(keyIndex); output = (byte[])input.Clone(); var sigBuffer = new byte[0x60]; Array.Copy(input, input.Length - 0x60, sigBuffer, 0, 0x60); sigBuffer = memekey.RsaPublic(sigBuffer); using (var sha1 = SHA1.Create()) foreach (var orVal in new byte[] { 0, 0x80 }) { sigBuffer[0x0] |= orVal; sigBuffer.CopyTo(output, output.Length - 0x60); memekey.AesDecrypt(output).CopyTo(output, 0); // Check for 8-byte equality. if (BitConverter.ToUInt64(sha1.ComputeHash(output, 0, output.Length - 0x8), 0) == BitConverter.ToUInt64(output, output.Length - 0x8)) { return(true); } } output = null; return(false); }
public static byte[] SignMemeData(byte[] input, MemeKeyIndex keyIndex = MemeKeyIndex.PokedexAndSaveFile) { // Validate Input if (input.Length < 0x60) { throw new ArgumentException("Cannot memesign a buffer less than 0x60 bytes in size!"); } var memekey = new MemeKey(keyIndex); if (!memekey.CanResign) { throw new ArgumentException("Cannot sign with the specified memekey!"); } var output = (byte[])input.Clone(); // Copy in the SHA1 signature using (var sha1 = SHA1.Create()) { Array.Copy(sha1.ComputeHash(input, 0, input.Length - 8), 0, output, output.Length - 8, 8); } // Perform AES operations output = memekey.AesEncrypt(output); var sigBuffer = new byte[0x60]; Array.Copy(output, output.Length - 0x60, sigBuffer, 0, 0x60); sigBuffer[0] &= 0x7F; sigBuffer = memekey.RsaPrivate(sigBuffer); sigBuffer.CopyTo(output, output.Length - 0x60); return(output); }
public static bool VerifyMemeData(byte[] input, out byte[] output, MemeKeyIndex keyIndex) { if (input.Length < 0x60) { output = input; return(false); } var key = new MemeKey(keyIndex); output = (byte[])input.Clone(); var sigBuffer = key.RsaPublic(input.SliceEnd(input.Length - 0x60)); using var sha1 = SHA1.Create(); if (DecryptCompare(output, sigBuffer, key, sha1)) { return(true); } sigBuffer[0x0] |= 0x80; if (DecryptCompare(output, sigBuffer, key, sha1)) { return(true); } output = input; return(false); }
private static bool DecryptCompare(byte[] output, byte[] sigBuffer, MemeKey key, SHA1 sha1) { sigBuffer.CopyTo(output, output.Length - 0x60); key.AesDecrypt(output).CopyTo(output, 0); // Check for 8-byte equality. var hash = sha1.ComputeHash(output, 0, output.Length - 0x8); var computed = BitConverter.ToUInt64(hash, 0); var existing = BitConverter.ToUInt64(output, output.Length - 0x8); return(computed == existing); }
public static bool VerifyMemePOKE(byte[] input, out byte[] output) { if (input.Length < 0x60) { throw new ArgumentException("Invalid POKE buffer!"); } var memeLen = input.Length - 8; var memeIndex = MemeKeyIndex.PokedexAndSaveFile; for (var i = input.Length - 8; i >= 0; i--) { if (BitConverter.ToUInt32(input, i) != POKE) { continue; } var keyIndex = BitConverter.ToInt32(input, i + 4); if (!MemeKey.IsValidPokeKeyIndex(keyIndex)) { continue; } memeLen = i; memeIndex = (MemeKeyIndex)keyIndex; break; } foreach (var len in new[] { memeLen, memeLen - 2 }) // Account for Pokédex QR Edge case { if (VerifyMemeData(input, out output, 0, len, memeIndex)) { return(true); } if (VerifyMemeData(input, out output, 0, len, MemeKeyIndex.PokedexAndSaveFile)) { return(true); } } output = input; return(false); }