using System.Security.Cryptography; using System.Text; namespace Landmark.OLA.Application.Common.Security { public static class CookieCryptor { private static byte[] RandomBytes(int len) { var b = new byte[len]; RandomNumberGenerator.Fill(b); return b; } private static byte[] DeriveKey(string pass, byte[] salt, int keyBytes = 32, int iterations = 100_000) => new Rfc2898DeriveBytes(pass, salt, iterations, HashAlgorithmName.SHA256).GetBytes(keyBytes); public static string EncryptJwt(string jwt, string key) { var salt = RandomBytes(32); using var aes = Aes.Create(); aes.KeySize = 256; aes.BlockSize = 128; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.GenerateIV(); aes.Key = DeriveKey(key, salt, 32); using var ms = new MemoryStream(); ms.Write(salt, 0, salt.Length); ms.Write(aes.IV, 0, aes.IV.Length); using (var crypto = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) using (var writer = new StreamWriter(crypto, Encoding.UTF8)) { writer.Write(jwt); writer.Flush(); crypto.FlushFinalBlock(); } return Convert.ToBase64String(ms.ToArray()); } public static string DecryptJwt(string cipherText, string passPhrase) { var all = Convert.FromBase64String(cipherText); var saltLen = 32; var ivLen = 16; if (all.Length < saltLen + ivLen) throw new CryptographicException("Ciphertext too short."); var salt = new byte[saltLen]; Buffer.BlockCopy(all, 0, salt, 0, saltLen); var iv = new byte[ivLen]; Buffer.BlockCopy(all, saltLen, iv, 0, ivLen); var cipher = new byte[all.Length - saltLen - ivLen]; Buffer.BlockCopy(all, saltLen + ivLen, cipher, 0, cipher.Length); using var aes = Aes.Create(); aes.KeySize = 256; aes.BlockSize = 128; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.Key = DeriveKey(passPhrase, salt, 32); aes.IV = iv; using var ms = new MemoryStream(cipher); using var crypto = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read); using var reader = new StreamReader(crypto, Encoding.UTF8); return reader.ReadToEnd(); } } }