using System; using System.Linq; using System.Security.Cryptography; using System.Text; namespace IOL.Helpers; public static class CryptographyHelpers { private const int AES_BLOCK_BYTE_SIZE = 128 / 8; private static readonly RandomNumberGenerator _random = RandomNumberGenerator.Create(); /// /// Creates a MD5 hash of the specified input. /// /// A hash public static byte[] AsMD5Hash(this string input, string salt = default) { if (input.IsNullOrWhiteSpace()) { return default; } var hmacMd5 = salt.HasValue() ? new HMACMD5(Encoding.UTF8.GetBytes(salt ?? "")) : new HMACMD5(); return hmacMd5.ComputeHash(Encoding.UTF8.GetBytes(input)); } public static byte[] AsMD5Hash(this byte[] input, string salt = default) { if (input == null) { return default; } var hmacMd5 = salt.HasValue() ? new HMACMD5(Encoding.UTF8.GetBytes(salt ?? "")) : new HMACMD5(); return hmacMd5.ComputeHash(input); } // https://stackoverflow.com/a/13026595/253938 /// /// Method to perform a very simple (and classical) encryption for a string. This is NOT at /// all secure, it is only intended to make the string value non-obvious at a first glance. /// /// The shiftOrUnshift argument is an arbitrary "key value", and must be a non-zero integer /// between -65535 and 65535 (inclusive). To decrypt the encrypted string you use the negative /// value. For example, if you encrypt with -42, then you decrypt with +42, or vice-versa. /// /// string to be encrypted or decrypted, must not be null /// see above /// encrypted or decrypted string public static string CaesarCipher(this string input, int shiftOrUnshift) { if (input.IsNullOrWhiteSpace()) { return default; } const int C64_K = ushort.MaxValue + 1; if (input == null) throw new ArgumentException("Must not be null.", nameof(input)); switch (shiftOrUnshift) { case 0: throw new ArgumentException("Must not be zero.", nameof(shiftOrUnshift)); case <= -C64_K: case >= C64_K: throw new ArgumentException("Out of range.", nameof(shiftOrUnshift)); } // Perform the Caesar cipher shifting, using modulo operator to provide wrap-around var charArray = new char[input.Length]; for (var i = 0; i < input.Length; i++) { charArray[i] = Convert.ToChar((Convert.ToInt32(input[i]) + shiftOrUnshift + C64_K) % C64_K); } return new string(charArray); } //https://tomrucki.com/posts/aes-encryption-in-csharp/ /// /// Encrypts a string input with aes encryption /// /// The string to encrypt /// The key to encrypt the input with /// A base 64 encoded string of the encrypted input /// Throws null if encryptionKey is empty or null public static string EncryptWithAes(this string input, string encryptionKey) { if (input.IsNullOrWhiteSpace()) { return default; } if (encryptionKey.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(encryptionKey)); } var key = encryptionKey.AsMD5Hash(); using var aes = Aes.Create(); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; var iv = new byte[AES_BLOCK_BYTE_SIZE]; _random.GetBytes(iv); var plainText = Encoding.UTF8.GetBytes(input); using var encryptor = aes.CreateEncryptor(key, iv); var cipherText = encryptor.TransformFinalBlock(plainText, 0, plainText.Length); var result = new byte[iv.Length + cipherText.Length]; iv.CopyTo(result, 0); cipherText.CopyTo(result, iv.Length); return Convert.ToBase64String(result); } /// /// Decrypts a string input with aes encryption /// /// The base 64 encoded string to decrypt /// The key to decrypt the input with /// A string of the decrypted input /// Throws null if encryptionKey is empty or null public static string DecryptWithAes(this string input, string encryptionKey) { if (input.IsNullOrWhiteSpace()) { return default; } if (encryptionKey.IsNullOrWhiteSpace()) { throw new ArgumentNullException(nameof(encryptionKey)); } var key = encryptionKey.AsMD5Hash(); var encryptedData = Convert.FromBase64String(input); using var aes = Aes.Create(); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; var iv = encryptedData.Take(AES_BLOCK_BYTE_SIZE).ToArray(); var cipherText = encryptedData.Skip(AES_BLOCK_BYTE_SIZE).ToArray(); using var decryptor = aes.CreateDecryptor(key, iv); var decryptedBytes = decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length); return Encoding.UTF8.GetString(decryptedBytes); } /// /// Creates a SHA256 hash of the specified input. /// /// The input /// A base 64 encoded hash string of the input public static string AsSHA256Hash(this string input) { if (input.IsNullOrWhiteSpace()) return default; using var sha = SHA256.Create(); var bytes = Encoding.UTF8.GetBytes(input); var hash = sha.ComputeHash(bytes); return Convert.ToBase64String(hash); } /// /// Creates a SHA256 hash of the specified input. /// /// The input /// A byte array containing the hash of the input public static byte[] AsSHA256Hash(this byte[] input) { if (input == null) return default; using var sha = SHA256.Create(); return sha.ComputeHash(input); } /// /// Creates a SHA512 hash of the specified input. /// /// The input /// A base 64 encoded hash string of the input public static string AsSHA512(this string input) { if (input.IsNullOrWhiteSpace()) return default; using var sha = SHA512.Create(); var bytes = Encoding.UTF8.GetBytes(input); var hash = sha.ComputeHash(bytes); return Convert.ToBase64String(hash); } /// /// Creates a SHA256 hash of the specified input. /// /// The input /// A byte array containing the hash of the input public static byte[] AsSHA512(this byte[] input) { if (input == null) return default; using var sha = SHA512.Create(); return sha.ComputeHash(input); } }