using System; using System.Collections.Generic; using System.Text; namespace Duplicati.Encryption { /// /// Implements AES encryption /// public class AESEncryption : EncryptionBase, IEncryption { /// /// The AES instance /// private System.Security.Cryptography.Rijndael m_instance; /// /// Constructs a new AES encryption/decyption instance /// /// The key used for encryption. The key gets stretched through SHA hashing to fit the key size requirements public AESEncryption(string key) { m_instance = System.Security.Cryptography.Rijndael.Create(); System.Security.Cryptography.SHA256 sha = System.Security.Cryptography.SHA256.Create(); int len = m_instance.IV.Length + m_instance.Key.Length; System.IO.MemoryStream ms = new System.IO.MemoryStream(); //We stretch the key material by issuing cascading hash operations. //This somewhat alters the characteristics of the key, but as long //as the hashing is cryptographically safe and does not induce aliasing //with the encryption, it does not reduce the strength of the encryption byte[] tmp = System.Text.Encoding.UTF8.GetBytes(key); while (ms.Length < len) { if (!sha.CanReuseTransform) sha = System.Security.Cryptography.SHA256.Create(); sha.Initialize(); tmp = sha.ComputeHash(tmp); ms.Write(tmp, 0, (int)Math.Min(tmp.Length, len - ms.Length)); } byte[] realkey = new byte[m_instance.Key.Length]; byte[] iv = new byte[m_instance.IV.Length]; ms.Position = 0; if (ms.Read(iv, 0, iv.Length) != iv.Length) throw new Exception("Bad key stretch"); if (ms.Read(realkey, 0, realkey.Length) != realkey.Length) throw new Exception("Bad key stretch"); ms.Dispose(); m_instance.IV = iv; m_instance.Key = realkey; m_instance.Mode = System.Security.Cryptography.CipherMode.CBC; } #region IEncryption Members public override void Encrypt(System.IO.Stream input, System.IO.Stream output) { if (m_instance.Mode == System.Security.Cryptography.CipherMode.ECB) throw new Exception("Useless encryption detected"); System.Security.Cryptography.ICryptoTransform ct = m_instance.CreateEncryptor(); using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(input, ct, System.Security.Cryptography.CryptoStreamMode.Write)) Core.Utility.CopyStream(cs, output); } public override void Decrypt(System.IO.Stream input, System.IO.Stream output) { if (m_instance.Mode == System.Security.Cryptography.CipherMode.ECB) throw new Exception("Useless encryption detected"); System.Security.Cryptography.ICryptoTransform ct = m_instance.CreateDecryptor(); using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(input, ct, System.Security.Cryptography.CryptoStreamMode.Read)) Core.Utility.CopyStream(cs, output); } #endregion } }