using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RMDEC { public class MVProject { public MVProject() { } //Private internal variables private byte[] encryptionKey = new byte[0x10]; private bool encryptedImages = false; private bool encryptedAudio = false; private string gameTitle; private string filePath; //Public readable variables public Boolean IsEncrypted { get { if (EncryptedAudio == true || EncryptedImages == true) { return true; } else { return false; } } } public Byte[] EncryptionKey { get { return encryptionKey; } } public String GameTitle { get { return gameTitle; } } public Boolean EncryptedImages { get { return encryptedImages; } } public Boolean EncryptedAudio { get { return encryptedAudio; } } public String FilePath { get { return filePath; } } //Private functions private static byte[] hexStr2Bytes(String HexStr) { if (HexStr.Length % 2 != 0) { throw new InvalidDataException(HexStr + " Is not divisible by 2!"); } List byteList = new List(); for (int i = 0; i < HexStr.Length; i += 2) { string curHex = HexStr.Substring(i, 2); byte hexByte = Byte.Parse(curHex, NumberStyles.HexNumber); byteList.Add(hexByte); } byte[] resultingByteArray = byteList.ToArray(); return resultingByteArray; } private static byte[] xor(byte[] input, byte[] key) { long inpLen = input.LongLength; byte[] output = new byte[inpLen]; for(long i = 0; i < input.LongLength; i++) { output[i] = (byte)(input[i] ^ key[i % key.LongLength]); } return output; } //Public functions public static MVProject ParseSystemJson(string path) { if (File.Exists(path)) { string jsonStr = File.ReadAllText(path, Encoding.UTF8); dynamic systemJson = JObject.Parse(jsonStr); //Check if valid system.json MVProject mvp = new MVProject(); if (systemJson.gameTitle != null) { mvp.gameTitle = systemJson.gameTitle; } else { throw new InvalidDataException("Not a valid system.json!"); } if (systemJson.hasEncryptedAudio != null) { mvp.encryptedAudio = systemJson.hasEncryptedAudio; } if (systemJson.hasEncryptedImages != null) { mvp.encryptedImages = systemJson.hasEncryptedImages; } if (systemJson.encryptionKey != null) { string encKey = systemJson.encryptionKey; mvp.encryptionKey = hexStr2Bytes(encKey); } mvp.filePath = Path.GetDirectoryName(Path.GetDirectoryName(path)); return mvp; } else { throw new FileNotFoundException(path + " was not found!"); } } public void DecryptFile(Stream inStream, Stream outStream) { inStream.Seek(0x00, SeekOrigin.Begin); byte[] magic = new byte[0x05]; inStream.Read(magic, 0x00,0x05); string magicStr = Encoding.UTF8.GetString(magic); if(magicStr != "RPGMV") { throw new InvalidDataException("Not an encrypted file!"); } inStream.Seek(0x10, SeekOrigin.Begin); byte[] encryptedHeader = new byte[0x10]; inStream.Read(encryptedHeader, 0x00, 0x10); byte[] plaintextHeader = xor(encryptedHeader, encryptionKey); outStream.Write(plaintextHeader, 0x00, plaintextHeader.Length); inStream.CopyTo(outStream); } } }