rmdec/RMDEC/MVProject.cs

251 lines
7.0 KiB
C#

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
namespace RMDEC
{
public class MVProject
{
public MVProject() { }
//Private internal variables
private byte[] encryptionKey = new byte[0x10];
private bool isKeySet = false;
private bool encryptedImages = false;
private bool encryptedAudio = false;
public bool MZ = false;
private string gameTitle;
private string filePath;
private string systemJsonFile;
private dynamic jsonData;
//Public readable variables
public Boolean IsEncrypted
{
get
{
if (EncryptedAudio == true || EncryptedImages == true)
{
return true;
}
else
{
return false;
}
}
}
public Byte[] EncryptionKey
{
get
{
if(isKeySet)
{
return encryptionKey;
}
else
{
genEncryptionKey();
return encryptionKey;
}
}
}
public String GameTitle
{
get
{
return gameTitle;
}
}
public Boolean EncryptedImages
{
get
{
return encryptedImages;
}
set
{
jsonData.hasEncryptedImages = value;
File.WriteAllText(systemJsonFile, jsonData.ToString(Formatting.None));
encryptedImages = value;
}
}
public Boolean EncryptedAudio
{
get
{
return encryptedAudio;
}
set
{
jsonData.hasEncryptedAudio = value;
File.WriteAllText(systemJsonFile, jsonData.ToString(Formatting.None));
encryptedAudio = value;
}
}
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<byte> byteList = new List<byte>();
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 void genEncryptionKey()
{
byte[] keyData = new byte[0x10];
Random rng = new Random((int)DateTime.Now.Ticks);
rng.NextBytes(keyData);
encryptionKey = keyData;
jsonData.encryptionKey = BitConverter.ToString(keyData, 0x00, keyData.Length).Replace("-", "");
File.WriteAllText(systemJsonFile, jsonData.ToString(Formatting.None));
isKeySet = true;
}
//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.isKeySet = true;
}
mvp.filePath = Path.GetDirectoryName(Path.GetDirectoryName(path));
// Detect MV or MZ
if (File.Exists(Path.Combine(mvp.filePath, "js", "rmmz_core.js")))
{
mvp.MZ = true;
}
else
{
mvp.MZ = false;
}
mvp.systemJsonFile = path;
mvp.jsonData = systemJson;
return mvp;
}
else
{
throw new FileNotFoundException(path + " was not found!");
}
}
public void EncryptFile(Stream inStream, Stream outStream)
{
outStream.Seek(0x00, SeekOrigin.Begin);
outStream.SetLength(0x00);
BinaryWriter boutStream = new BinaryWriter(outStream);
string magic = "RPGMV";
byte[] magicBytes = Encoding.UTF8.GetBytes(magic);
outStream.Write(magicBytes, 0x00, magicBytes.Length);
boutStream.Write(0x00);
boutStream.Write(0x103);
outStream.Write(new byte[0x3], 0x00, 0x3);
inStream.Seek(0x00, SeekOrigin.Begin);
byte[] plaintextHeader = new byte[0x10];
inStream.Read(plaintextHeader, 0x00, 0x10);
byte[] encryptedHeader = RMProject.Xor(plaintextHeader, EncryptionKey);
outStream.Write(encryptedHeader, 0x00, encryptedHeader.Length);
inStream.CopyTo(outStream);
}
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 = RMProject.Xor(encryptedHeader, EncryptionKey);
outStream.Seek(0x00, SeekOrigin.Begin);
outStream.SetLength(0);
outStream.Write(plaintextHeader, 0x00, plaintextHeader.Length);
inStream.CopyTo(outStream);
}
}
}