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; } }