NHSE/NHSE.Core/Encryption/EncryptedInt32.cs
2020-03-27 17:54:17 -07:00

93 lines
3.2 KiB
C#

using System;
namespace NHSE.Core
{
public sealed class EncryptedInt32
{
// Encryption constant used to encrypt the int.
private const uint ENCRYPTION_CONSTANT = 0x80E32B11;
// Base shift count used in the encryption.
private const byte SHIFT_BASE = 3;
public uint Value;
public ushort Adjust;
public byte Shift;
public byte Checksum;
public override string ToString() => Value.ToString();
public EncryptedInt32(uint encryptedValue, ushort adjust = 0, byte shift = 0, byte checksum = 0)
{
Adjust = adjust;
Shift = shift;
Checksum = checksum;
Value = Decrypt(encryptedValue, shift, adjust);
}
public EncryptedInt32(uint value)
{
Adjust = (ushort)RandUtil.Rand.Next();
Shift = (byte)RandUtil.Rand.Next();
var enc = Encrypt(value, Shift, Adjust);
Checksum = CalculateChecksum(enc);
Value = value;
}
public void Write(byte[] data, int offset) => Write(this, data, offset);
// Calculates a checksum for a given encrypted value
// Checksum calculation is every byte of the encrypted in added together minus 0x2D.
public static byte CalculateChecksum(uint value)
{
var byteSum = value + (value >> 16) + (value >> 24) + (value >> 8);
return (byte)(byteSum - 0x2D);
}
public static uint Decrypt(uint encrypted, byte shift, ushort adjust)
{
// Decrypt the encrypted int using the given params.
ulong val = ((ulong) encrypted) << ((32 - SHIFT_BASE - shift) & 0x3F);
int valConcat = (int) val + (int) (val >> 32);
return (uint) ((ENCRYPTION_CONSTANT - adjust) + valConcat);
}
public static uint Encrypt(uint value)
{
var adjust = (ushort)RandUtil.Rand.Next();
var shift = (byte)RandUtil.Rand.Next();
return Encrypt(value, shift, adjust);
}
private static uint Encrypt(uint value, byte shift, ushort adjust)
{
ulong val = (ulong) (value + (adjust - ENCRYPTION_CONSTANT)) << (shift + SHIFT_BASE);
return (uint) ((val >> 32) + val);
}
public static EncryptedInt32 Read(byte[] data, int offset)
{
var enc = BitConverter.ToUInt32(data, offset + 0);
var adjust = BitConverter.ToUInt16(data, offset + 4);
var shift = data[offset + 6];
var chk = data[offset + 7];
return new EncryptedInt32(enc, adjust, shift, chk);
}
public static void Write(EncryptedInt32 value, byte[] data, int offset)
{
uint enc = Encrypt(value.Value, value.Shift, value.Adjust);
byte chk = CalculateChecksum(enc);
BitConverter.GetBytes(enc).CopyTo(data, offset + 0);
BitConverter.GetBytes(value.Adjust).CopyTo(data, offset + 4);
data[offset + 6] = value.Shift;
data[offset + 7] = chk;
}
public static void Write(uint value, byte[] data, int offset)
{
var fake = new EncryptedInt32(value);
Write(fake, data, offset);
}
}
}