NHSE/NHSE.Core/Encryption/Encryption.cs
Kurt 6c40e1c769
Initial v1.7.0 Support (#445)
* Pre-patch preparations

* Update magic values

* Check formatting characters directly rather than string compare

"Brown".StartsWith("\u000e")
>true
what

let's be paranoid here, because .NET Core behaves differently from .NET framework.

* Update FileHashRevision.cs

Postbox with the massive decrease in size; likely the same mutation caused the other massive decreases.

* Dump item names

* Update flag definitions

* Update item info

* Add feathers to bug list

Might remove later.

* Update RecipeList.cs

* Update ItemRemakeUtil.cs

* Update stack details

* Update offsets

* Update MainSaveOffsets17.cs

* Update GameLists.cs
2021-01-27 20:04:51 -08:00

83 lines
3.1 KiB
C#

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;
}
/// <summary>
/// Decrypts the <see cref="encData"/> using the <see cref="headerData"/> in place.
/// </summary>
/// <param name="headerData">Header Data</param>
/// <param name="encData">Encrypted SaveData</param>
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));
}
/// <summary>
/// Encrypts the <see cref="data"/> (savedata) using the provided <see cref="seed"/>.
/// </summary>
/// <param name="data">SaveData to encrypt</param>
/// <param name="seed">Seed to encrypt with</param>
/// <param name="versionData">Version data to encrypt with</param>
/// <returns>Encrypted SaveData, and associated headerData</returns>
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);
}
}
}