using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Text; namespace Pilz.Cryptography { public class AESStringCrypter : ICrypter { public delegate void AESStringCrypterEventHandler(AESStringCrypter sender); /// /// This event throws if no key and no default key was found. You can now provide a key or default key (maybe depending on the given instance). If no value is provided, a default key will be created. /// public static event AESStringCrypterEventHandler NeedKey; /// /// This event throws if no IV and no default IV was found. You can now provide a IV or default IV (maybe depending on the given instance). If no value is provided, a default IV will be created. /// public static event AESStringCrypterEventHandler NeedIV; private byte[] key = new byte[] { }; private byte[] iv = new byte[] { }; private static byte[] defaultKey = new byte[] { }; private static byte[] defaultIV = new byte[] { }; public Encoding Encoding { get; set; } = Encoding.Default; public string Name { get; set; } public object Tag { get; set; } public string Key { get => Convert.ToBase64String(key); set => key = Convert.FromBase64String(value); } public string IV { get => Convert.ToBase64String(iv); set => iv = Convert.FromBase64String(value); } public static string DefaultKey { get => Convert.ToBase64String(defaultKey); set => defaultKey = Convert.FromBase64String(value); } public static string DefaultIV { get => Convert.ToBase64String(defaultIV); set => defaultIV = Convert.FromBase64String(value); } public string Decrypt(string encryptedValue) { return DecryptStringFromBytes_Aes(Convert.FromBase64String(encryptedValue), GetKey(), GetIV()); } public string Encrypt(string plainValue) { return Convert.ToBase64String(EncryptStringToBytes_Aes(plainValue, GetKey(), GetIV())); } private byte[] GetKey(bool createIfFail = false) { byte[] keyToUse; if (key.Length != 0) keyToUse = key; else if (defaultKey.Length != 0) keyToUse = defaultKey; else if (createIfFail) keyToUse = defaultKey = GenerateKeyInternal(); else { NeedKey?.Invoke(this); keyToUse = GetKey(true); } return keyToUse; } private byte[] GetIV(bool createIfFail = false) { byte[] ivToUse; if (iv.Length != 0) ivToUse = iv; else if (defaultIV.Length != 0) ivToUse = defaultIV; else if (createIfFail) ivToUse = defaultIV = GenerateIVInternal(); else { NeedIV?.Invoke(this); ivToUse = GetIV(true); } return ivToUse; } private static byte[] GenerateKeyInternal() { var aes = Aes.Create(); var key = aes.Key; aes.Dispose(); return key; } public static string GenerateKey() { return Convert.ToBase64String(GenerateKeyInternal()); } private static byte[] GenerateIVInternal() { var aes = Aes.Create(); var iv = aes.IV; aes.Dispose(); return iv; } public static string GenerateIV() { return Convert.ToBase64String(GenerateIVInternal()); } private static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV) { // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV"); byte[] encrypted; // Create an Aes object // with the specified key and IV. using (Aes aesAlg = Aes.Create()) { aesAlg.Key = Key; aesAlg.IV = IV; // Create an encryptor to perform the stream transform. ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { //Write all data to the stream. swEncrypt.Write(plainText); } encrypted = msEncrypt.ToArray(); } } } // Return the encrypted bytes from the memory stream. return encrypted; } private static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV) { // Check arguments. if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV"); // Declare the string used to hold // the decrypted text. string plaintext = null; // Create an Aes object // with the specified key and IV. using (Aes aesAlg = Aes.Create()) { aesAlg.Key = Key; aesAlg.IV = IV; // Create a decryptor to perform the stream transform. ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for decryption. using (MemoryStream msDecrypt = new MemoryStream(cipherText)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { // Read the decrypted bytes from the decrypting stream // and place them in a string. plaintext = srDecrypt.ReadToEnd(); } } } } return plaintext; } } }