private static byte[] CreateSequence(Nintendo.Sead.Random random) { // Create byte array byte[] sequence = new byte[16]; // Create each byte for (int i = 0; i < sequence.Length; i++) { // Create empty byte string string byteString = ""; // Get characters from key material byteString += KeyMaterialString[(int)(random.GetUInt32() >> 24)]; byteString += KeyMaterialString[(int)(random.GetUInt32() >> 24)]; // Parse the resulting byte sequence[i] = Convert.ToByte(byteString, 16); } // Return the sequence return(sequence); }
public static void Decrypt(Stream inputStream, Stream outputStream, string gamePath) { // Read the entire file into an array byte[] encryptedData = new byte[inputStream.Length - 8]; inputStream.Seek(0, SeekOrigin.Begin); inputStream.Read(encryptedData, 0, (int)inputStream.Length - 8); // Generate a CRC32 over the game path Crc32 crc32 = new Crc32(); uint seed = crc32.Get(Encoding.ASCII.GetBytes(gamePath)); // Create a new SeadRandom instance using the seed Nintendo.Sead.Random seadRandom = new Nintendo.Sead.Random(seed); // Create the encryption key and IV byte[] encryptionKey = CreateSequence(seadRandom); byte[] iv = CreateSequence(seadRandom); // Generate a KeyParameter instance KeyParameter parameter = new KeyParameter(encryptionKey); // Initialize the AES-CBC cipher IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CBC/NoPadding"); cipher.Init(false, new ParametersWithIV(parameter, iv)); // Return the decrypted bytes byte[] output = cipher.DoFinal(encryptedData); // Seek to the beginning outputStream.Seek(0, SeekOrigin.Begin); // Write to the output stream outputStream.Write(output, 0, output.Length); // Seek back to the beginning outputStream.Seek(0, SeekOrigin.Begin); }