using System; namespace NHSE.Core { public static class Encryption { private static byte[] GetParam(uint[] data, in int index) { var rand = new XorShift128(data[data[index] & 0x7F]); var prms = data[data[index + 1] & 0x7F] & 0x7F; var rndRollCount = (prms & 0xF) + 1; for (var i = 0; i < rndRollCount; i++) rand.GetU64(); var result = new byte[0x10]; for (var i = 0; i < result.Length; i++) result[i] = (byte)(rand.GetU32() >> 24); return result; } /// /// Decrypts the using the in place. /// /// Header Data /// Encrypted SaveData public static void Decrypt(byte[] headerData, byte[] encData) { // First 256 bytes go unused var importantData = new uint[0x80]; Buffer.BlockCopy(headerData, 0x100, importantData, 0, 0x200); // Set up Key var key = GetParam(importantData, 0); // Set up counter var counter = GetParam(importantData, 2); // Do the AES using var aesCtr = new Aes128CounterMode(counter); var transform = aesCtr.CreateDecryptor(key, counter); transform.TransformBlock(encData, 0, encData.Length, encData, 0); } private static CryptoFile GenerateHeaderFile(uint seed, byte[] versionData) { // Generate 128 Random uints which will be used for params var random = new XorShift128(seed); var encryptData = new uint[128]; for (var i = 0; i < encryptData.Length; i++) encryptData[i] = random.GetU32(); var headerData = new byte[0x300]; Buffer.BlockCopy(versionData, 0, headerData, 0, 0x100); Buffer.BlockCopy(encryptData, 0, headerData, 0x100, 0x200); return new CryptoFile(headerData, GetParam(encryptData, 0), GetParam(encryptData, 2)); } /// /// Encrypts the (savedata) using the provided . /// /// SaveData to encrypt /// Seed to encrypt with /// Version data to encrypt with /// Encrypted SaveData, and associated headerData public static EncryptedSaveFile Encrypt(byte[] data, uint seed, byte[] versionData) { // Generate header file and get key and counter var header = GenerateHeaderFile(seed, versionData); // Encrypt file using var aesCtr = new Aes128CounterMode(header.Ctr); var transform = aesCtr.CreateEncryptor(header.Key, header.Ctr); var encData = new byte[data.Length]; transform.TransformBlock(data, 0, data.Length, encData, 0); return new EncryptedSaveFile(encData, header.Data); } } }