diff --git a/Pilz.Cryptography/AESStringCrypter.cs b/Pilz.Cryptography/AESStringCrypter.cs new file mode 100644 index 0000000..fdb4160 --- /dev/null +++ b/Pilz.Cryptography/AESStringCrypter.cs @@ -0,0 +1,212 @@ +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; + } + } +}