VMProtect/runtime/VMProtect.Runtime/Crypto.cs

195 lines
4.2 KiB
C#

using System;
using System.Runtime.InteropServices;
// ReSharper disable once CheckNamespace
namespace VMProtect
{
public class CipherRC5
{
private const int R = 15; // number of rounds
private const int B = 8; // number of bytes in key
private const int C = 8 * B / BitRotate.W; // 16 - number u32s in key = ceil(8*B/W)
private const int T = 2 * (R + 1); // 34 - size of table _s = 2*(R+1) u32s
private readonly uint[] _s; // expanded key table
#if RUNTIME
private const uint P = (uint)Faces.RC5_P;
private const uint Q = (uint)Faces.RC5_Q;
#else
private static readonly uint P = Core.Instance.Rand32();
private static readonly uint Q = Core.Instance.Rand32();
public static byte[] CreateRandomKey()
{
var ret = new byte[B];
Core.Instance.RndGenerator.NextBytes(ret);
return ret;
}
#endif
public CipherRC5(byte[] key)
{
uint i, j, k, u = BitRotate.W / 8, a, b;
var l = new uint[C];
_s = new uint[T];
for (i = B - 1, l[C - 1] = 0; i != uint.MaxValue; i--)
l[i / u] = (l[i / u] << 8) + key[i];
for (_s[0] = P, i = 1; i < T; i++)
_s[i] = _s[i - 1] + Q;
for (a = b = i = j = k = 0; k < 3 * T; k++, i = (i + 1) % T, j = (j + 1) % C) // 3*T > 3*C
{
a = _s[i] = BitRotate.Left(_s[i] + a + b, 3);
b = l[j] = BitRotate.Left(l[j] + a + b, (int)(a + b));
}
}
[StructLayout(LayoutKind.Explicit)]
private struct Dword
{
[FieldOffset(0)]
public ulong dw;
[FieldOffset(0)]
public uint w0;
[FieldOffset(4)]
public uint w1;
}
private void Encrypt(ref Dword io)
{
uint i, a = io.w0 + _s[0], b = io.w1 + _s[1];
for (i = 1; i <= R; i++)
{
a = BitRotate.Left(a ^ b, (int)b) + _s[2 * i];
b = BitRotate.Left(b ^ a, (int)a) + _s[2 * i + 1];
}
io.w0 = a;
io.w1 = b;
}
private void Decrypt(ref Dword io)
{
uint i, b = io.w1, a = io.w0;
for (i = R; i > 0; i--)
{
b = BitRotate.Right(b - _s[2 * i + 1], (int)a) ^ a;
a = BitRotate.Right(a - _s[2 * i], (int)b) ^ b;
}
io.w1 = b - _s[1];
io.w0 = a - _s[0];
}
public byte[] Encrypt(byte[] ain)
{
var aout = new byte[ain.Length];
Encrypt(ain, aout);
return aout;
}
public byte[] Decrypt(byte[] ain)
{
var aout = new byte[ain.Length];
Decrypt(ain, aout);
return aout;
}
public void Encrypt(byte[] ain, byte[] aout)
{
var block = new Dword();
for (var i = 0; i < ain.Length; i += 8)
{
block.dw = BitConverter.ToUInt64(ain, i);
Encrypt(ref block);
BitConverter.GetBytes(block.dw).CopyTo(aout, i);
}
}
public void Decrypt(byte[] ain, byte[] aout)
{
var block = new Dword();
for (var i = 0; i < ain.Length; i += 8)
{
block.dw = BitConverter.ToUInt64(ain, i);
Decrypt(ref block);
BitConverter.GetBytes(block.dw).CopyTo(aout, i);
}
}
}
public class CRC32
{
static uint[] _table;
public CRC32()
{
if (_table == null)
{
_table = new uint[256];
for (var i = 0; i < 256; i++)
{
var entry = (uint)i;
for (var j = 0; j < 8; j++)
if ((entry & 1) == 1)
entry = (entry >> 1) ^ 0xedb88320u;
else
entry = entry >> 1;
_table[i] = entry;
}
}
}
public uint Hash(IntPtr ptr, uint size)
{
uint crc = 0;
for (var i = 0; i < size; i++)
crc = _table[(Marshal.ReadByte(new IntPtr(ptr.ToInt64() + i)) ^ crc) & 0xff] ^ (crc >> 8);
return ~crc;
}
}
public class CRCValueCryptor
{
private uint _key;
public CRCValueCryptor()
{
_key = (uint)Faces.CRC_INFO_SALT;
}
public uint Decrypt(uint value)
{
uint res = value ^ _key;
_key = BitRotate.Left(_key, 7) ^ res;
return res;
}
}
public class BitRotate
{
public const int W = 32; // u32 size in bits
public static uint Left(uint a, int offset)
{
var r1 = a << offset;
var r2 = a >> (W - offset);
return r1 | r2;
}
public static uint Right(uint a, int offset)
{
var r1 = a >> offset;
var r2 = a << (W - offset);
return r1 | r2;
}
public static uint Swap(uint value)
{
uint mask_xx_zz = (value & 0x00FF00FFU);
uint mask_ww_yy = (value & 0xFF00FF00U);
return ((mask_xx_zz >> 8) | (mask_xx_zz << 24)) +
((mask_ww_yy << 8) | (mask_ww_yy >> 24));
}
}
}