168 lines
4.2 KiB
C#
168 lines
4.2 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace PureCrack.Crypto;
|
|
|
|
public static class Symmetric
|
|
{
|
|
public static readonly byte[] AesKey = HexToBytes("e6c43cc05d35fee7c8533d96203eeda357c65e85e30dbe622fad26fdfbb222a8");
|
|
|
|
public static byte[] AesEncrypt(byte[] plaintext, byte[] iv)
|
|
{
|
|
if (iv.Length != 16)
|
|
{
|
|
throw new ArgumentException("iv must be 16 bytes", "iv");
|
|
}
|
|
using Aes aes = Aes.Create() ?? throw new InvalidOperationException("Aes.Create returned null");
|
|
aes.Mode = CipherMode.CBC;
|
|
aes.Padding = PaddingMode.PKCS7;
|
|
aes.KeySize = 256;
|
|
aes.Key = AesKey;
|
|
aes.IV = iv;
|
|
using ICryptoTransform cryptoTransform = aes.CreateEncryptor();
|
|
return cryptoTransform.TransformFinalBlock(plaintext, 0, plaintext.Length);
|
|
}
|
|
|
|
public static byte[] AesDecrypt(byte[] ciphertext, byte[] iv)
|
|
{
|
|
if (iv.Length != 16)
|
|
{
|
|
throw new ArgumentException("iv must be 16 bytes", "iv");
|
|
}
|
|
using Aes aes = Aes.Create() ?? throw new InvalidOperationException("Aes.Create returned null");
|
|
aes.Mode = CipherMode.CBC;
|
|
aes.Padding = PaddingMode.PKCS7;
|
|
aes.KeySize = 256;
|
|
aes.Key = AesKey;
|
|
aes.IV = iv;
|
|
using ICryptoTransform cryptoTransform = aes.CreateDecryptor();
|
|
return cryptoTransform.TransformFinalBlock(ciphertext, 0, ciphertext.Length);
|
|
}
|
|
|
|
public static byte[] AesEncryptFraming(byte[] plaintext)
|
|
{
|
|
byte[] array = RandomBytes(16);
|
|
byte[] array2 = AesEncrypt(plaintext, array);
|
|
byte[] array3 = new byte[16 + array2.Length];
|
|
Buffer.BlockCopy(array, 0, array3, 0, 16);
|
|
Buffer.BlockCopy(array2, 0, array3, 16, array2.Length);
|
|
return array3;
|
|
}
|
|
|
|
public static byte[] AesDecryptFraming(byte[] framedBody)
|
|
{
|
|
if (framedBody.Length < 32)
|
|
{
|
|
throw new ArgumentException("framed body must be at least 32 bytes (IV + 1 block)");
|
|
}
|
|
byte[] array = new byte[16];
|
|
Buffer.BlockCopy(framedBody, 0, array, 0, 16);
|
|
byte[] array2 = new byte[framedBody.Length - 16];
|
|
Buffer.BlockCopy(framedBody, 16, array2, 0, array2.Length);
|
|
return AesDecrypt(array2, array);
|
|
}
|
|
|
|
public static byte[] TripleDesEncrypt(byte[] plaintext, byte[] key, byte[] iv)
|
|
{
|
|
if (key.Length != 24)
|
|
{
|
|
throw new ArgumentException("3DES key must be 24 bytes", "key");
|
|
}
|
|
if (iv.Length != 8)
|
|
{
|
|
throw new ArgumentException("3DES iv must be 8 bytes", "iv");
|
|
}
|
|
using TripleDES tripleDES = TripleDES.Create() ?? throw new InvalidOperationException("TripleDES.Create returned null");
|
|
tripleDES.Mode = CipherMode.CBC;
|
|
tripleDES.Padding = PaddingMode.PKCS7;
|
|
tripleDES.Key = key;
|
|
tripleDES.IV = iv;
|
|
using ICryptoTransform cryptoTransform = tripleDES.CreateEncryptor();
|
|
return cryptoTransform.TransformFinalBlock(plaintext, 0, plaintext.Length);
|
|
}
|
|
|
|
public static byte[] RandomBytes(int n)
|
|
{
|
|
byte[] array = new byte[n];
|
|
using RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create();
|
|
randomNumberGenerator.GetBytes(array);
|
|
return array;
|
|
}
|
|
|
|
public static byte[] Gzip(byte[] data)
|
|
{
|
|
using MemoryStream memoryStream = new MemoryStream();
|
|
using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionLevel.Optimal, leaveOpen: true))
|
|
{
|
|
gZipStream.Write(data, 0, data.Length);
|
|
}
|
|
return memoryStream.ToArray();
|
|
}
|
|
|
|
public static byte[] HexToBytes(string hex)
|
|
{
|
|
if ((hex.Length & 1) != 0)
|
|
{
|
|
throw new ArgumentException("hex string must have even length", "hex");
|
|
}
|
|
byte[] array = new byte[hex.Length / 2];
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
int num = HexNibble(hex[i * 2]);
|
|
int num2 = HexNibble(hex[i * 2 + 1]);
|
|
array[i] = (byte)((num << 4) | num2);
|
|
}
|
|
return array;
|
|
}
|
|
|
|
private static int HexNibble(char c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
return c - 48;
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
return c - 97 + 10;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
return c - 65 + 10;
|
|
default:
|
|
throw new FormatException($"non-hex char: {c}");
|
|
}
|
|
}
|
|
|
|
public static bool ConstantTimeEquals(byte[] a, byte[] b)
|
|
{
|
|
if (a.Length != b.Length)
|
|
{
|
|
return false;
|
|
}
|
|
int num = 0;
|
|
for (int i = 0; i < a.Length; i++)
|
|
{
|
|
num |= a[i] ^ b[i];
|
|
}
|
|
return num == 0;
|
|
}
|
|
}
|