SCHALE.GameServer/SCHALE.Common/Crypto/TableEncryptionService.cs

157 lines
5.2 KiB
C#
Raw Normal View History

2024-04-29 15:52:45 +00:00
using SCHALE.Common.Crypto.XXHash;
2024-04-21 00:21:57 +00:00
using System.Buffers.Binary;
2024-04-29 15:52:45 +00:00
using System.Collections;
using System.Reflection;
2024-04-21 00:21:57 +00:00
using System.Text;
namespace SCHALE.Common.Crypto
{
public static class TableEncryptionService
{
2024-04-29 15:52:45 +00:00
private static readonly Dictionary<Type, MethodInfo?> converterCache = [];
private static readonly Dictionary<string, byte[]> keyCache = [];
public static byte[] CreateKey(string name)
{
if (keyCache.TryGetValue(name, out var key))
return key;
byte[] password = GC.AllocateUninitializedArray<byte>(8);
using var xxhash = XXHash32.Create();
xxhash.ComputeHash(Encoding.UTF8.GetBytes(name));
var mt = new MersenneTwister((int)xxhash.HashUInt32);
int i = 0;
while (i < password.Length)
{
Array.Copy(BitConverter.GetBytes(mt.Next()), 0, password, i, Math.Min(4, password.Length - i));
i += 4;
}
keyCache.Add(name, password);
return password;
}
2024-04-21 00:21:57 +00:00
/// <summary>
/// Used for decrypting .bytes flatbuffers bin. Doesn't work yet
/// </summary>
/// <param name="name"></param>
/// <param name="bytes"></param>
public static void XOR(string name, byte[] bytes)
{
using var xxhash = XXHash32.Create();
xxhash.ComputeHash(Encoding.UTF8.GetBytes(name));
2024-04-29 15:52:45 +00:00
var mt = new MersenneTwister((int)xxhash.HashUInt32);
var key = mt.NextBytes(bytes.Length);
Crypto.XOR.Crypt(bytes, key);
}
2024-04-21 00:21:57 +00:00
2024-04-29 15:52:45 +00:00
public static MethodInfo? GetConvertMethod(Type type)
{
if (!converterCache.TryGetValue(type, out MethodInfo? convertMethod))
{
convertMethod = typeof(TableEncryptionService).GetMethods(BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(x => x.Name == nameof(Convert) && (x.ReturnType == type));
converterCache.Add(type, convertMethod);
}
return convertMethod;
}
public static List<T> Convert<T>(List<T> value, byte[] key) where T : class
{
var baseType = value.GetType().GenericTypeArguments[0];
var convertMethod = GetConvertMethod(baseType.IsEnum ? Enum.GetUnderlyingType(value.GetType()) : baseType);
if (convertMethod is null)
return value;
for (int i = 0; i < value.Count; i++)
{
value[i] = (T)convertMethod.Invoke(null, [value[i], key])!;
}
return value;
}
public static T Convert<T>(T value, byte[] key) where T : Enum
{
var convertMethod = GetConvertMethod(Enum.GetUnderlyingType(value.GetType()));
if (convertMethod is null)
return value;
return (T)convertMethod.Invoke(null, [value, key])!;
}
public static bool Convert(bool value, byte[] key)
{
return value;
}
public static int Convert(int value, byte[] key)
{
var bytes = GC.AllocateUninitializedArray<byte>(sizeof(int));
BinaryPrimitives.WriteInt32LittleEndian(bytes, value);
Crypto.XOR.Crypt(bytes, key);
return BinaryPrimitives.ReadInt32LittleEndian(bytes);
}
public static long Convert(long value, byte[] key)
{
var bytes = GC.AllocateUninitializedArray<byte>(sizeof(long));
BinaryPrimitives.WriteInt64LittleEndian(bytes, value);
Crypto.XOR.Crypt(bytes, key);
return BinaryPrimitives.ReadInt64LittleEndian(bytes);
}
public static uint Convert(uint value, byte[] key)
{
var bytes = GC.AllocateUninitializedArray<byte>(sizeof(uint));
BinaryPrimitives.WriteUInt32LittleEndian(bytes, value);
Crypto.XOR.Crypt(bytes, key);
return BinaryPrimitives.ReadUInt32LittleEndian(bytes);
}
public static ulong Convert(ulong value, byte[] key)
{
var bytes = GC.AllocateUninitializedArray<byte>(sizeof(ulong));
BinaryPrimitives.WriteUInt64LittleEndian(bytes, value);
Crypto.XOR.Crypt(bytes, key);
return BinaryPrimitives.ReadUInt64LittleEndian(bytes);
}
public static float Convert(float value, byte[] key)
{
var bytes = GC.AllocateUninitializedArray<byte>(sizeof(float));
BinaryPrimitives.WriteSingleLittleEndian(bytes, value);
Crypto.XOR.Crypt(bytes, key);
return BinaryPrimitives.ReadSingleLittleEndian(bytes);
}
public static double Convert(double value, byte[] key)
{
var bytes = GC.AllocateUninitializedArray<byte>(sizeof(double));
BinaryPrimitives.WriteDoubleLittleEndian(bytes, value);
Crypto.XOR.Crypt(bytes, key);
return BinaryPrimitives.ReadDoubleLittleEndian(bytes);
}
public static string Convert(string value, byte[] key)
{
var strBytes = System.Convert.FromBase64String(value);
Crypto.XOR.Crypt(strBytes, key);
return Encoding.Unicode.GetString(strBytes);
}
}
2024-04-21 00:21:57 +00:00
}