diff --git a/Duplicati/Encryption/AESEncryption.cs b/Duplicati/Encryption/AESEncryption.cs
new file mode 100644
index 000000000..0e993e057
--- /dev/null
+++ b/Duplicati/Encryption/AESEncryption.cs
@@ -0,0 +1,81 @@
+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
+ }
+}
diff --git a/Duplicati/Encryption/Duplicati.Encryption.csproj b/Duplicati/Encryption/Duplicati.Encryption.csproj
new file mode 100644
index 000000000..3fee9ef5d
--- /dev/null
+++ b/Duplicati/Encryption/Duplicati.Encryption.csproj
@@ -0,0 +1,56 @@
+
+
+ Debug
+ AnyCPU
+ 8.0.50727
+ 2.0
+ {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}
+ Library
+ Properties
+ Duplicati.Encryption
+ Duplicati.Encryption
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}
+ Duplicati.Core
+
+
+
+
+
\ No newline at end of file
diff --git a/Duplicati/Encryption/EncryptionBase.cs b/Duplicati/Encryption/EncryptionBase.cs
new file mode 100644
index 000000000..70a11275a
--- /dev/null
+++ b/Duplicati/Encryption/EncryptionBase.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Duplicati.Encryption
+{
+ ///
+ /// Simple helper class that implements the filebased functions, and wraps them onto the stream based ones
+ ///
+ public abstract class EncryptionBase : IEncryption
+ {
+ #region IEncryption Members
+
+ public virtual void Encrypt(string inputfile, string outputfile)
+ {
+ using (System.IO.FileStream fs1 = System.IO.File.OpenRead(inputfile))
+ using (System.IO.FileStream fs2 = System.IO.File.Create(outputfile))
+ this.Encrypt(fs1, fs2);
+ }
+
+ public abstract void Encrypt(System.IO.Stream input, System.IO.Stream output);
+
+ public virtual void Decrypt(string inputfile, string outputfile)
+ {
+ using (System.IO.FileStream fs1 = System.IO.File.OpenRead(inputfile))
+ using (System.IO.FileStream fs2 = System.IO.File.Create(outputfile))
+ this.Decrypt(fs1, fs2);
+ }
+
+ public abstract void Decrypt(System.IO.Stream input, System.IO.Stream output);
+
+ #endregion
+ }
+}
diff --git a/Duplicati/Encryption/GPGEncryption.cs b/Duplicati/Encryption/GPGEncryption.cs
new file mode 100644
index 000000000..5fac85aed
--- /dev/null
+++ b/Duplicati/Encryption/GPGEncryption.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace Duplicati.Encryption
+{
+ ///
+ /// Implements a encryption/decryption with the GNU Privacy Guard (GPG)
+ ///
+ public class GPGEncryption : EncryptionBase, IEncryption
+ {
+ ///
+ /// The PGP program to use, should be with absolute path
+ ///
+ public static string PGP_PROGRAM = "pgp";
+
+ ///
+ /// Always present commandline args
+ ///
+ private const string COMMANDLINE_ARGS = "--symmetric --armor";
+
+ ///
+ /// Commandline switches for encryption
+ ///
+ private const string ENCRYPTION_ARGS = "--encrypt";
+
+ ///
+ /// Commandline switches for decryption
+ ///
+ private const string DECRYPTION_ARGS = "--decrypt";
+
+ ///
+ /// The key used for cryptographic operations
+ ///
+ private string m_key;
+
+ ///
+ /// An optional key, used for signature verification
+ ///
+ private string m_signaturekey;
+
+ ///
+ /// Constructs a new instance of the PGP encryption/decryption class.
+ ///
+ /// The key used to encrypt/decrypt data
+ /// The key used to generate a signature with (currently unused)
+ public GPGEncryption(string key, string signaturekey)
+ {
+ m_key = key;
+ m_signaturekey = signaturekey;
+ }
+
+ #region IEncryption Members
+
+ public override void Encrypt(System.IO.Stream input, System.IO.Stream output)
+ {
+ this.Execute(COMMANDLINE_ARGS + " " + ENCRYPTION_ARGS, input, output);
+ }
+
+ public override void Decrypt(System.IO.Stream input, System.IO.Stream output)
+ {
+ this.Execute(COMMANDLINE_ARGS + " " + DECRYPTION_ARGS, input, output);
+ }
+
+ ///
+ /// Internal helper that wraps GPG usage
+ ///
+ /// The commandline arguments
+ /// The input stream
+ /// The output stream
+ private void Execute(string args, System.IO.Stream input, System.IO.Stream output)
+ {
+ System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
+ psi.Arguments = args;
+ psi.CreateNoWindow = true;
+ psi.FileName = PGP_PROGRAM;
+ psi.RedirectStandardError = true;
+ psi.RedirectStandardInput = true;
+ psi.RedirectStandardOutput = true;
+ psi.UseShellExecute = false;
+ psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
+
+ System.Diagnostics.Process p = System.Diagnostics.Process.Start(psi);
+ p.StandardInput.WriteLine(m_key);
+
+ //Prevent blocking of the output buffer
+ System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(Runner));
+ t.Start(new object[] {p.StandardOutput.BaseStream, output});
+
+ //Copy input stream to GPG
+ Core.Utility.CopyStream(input, p.StandardInput.BaseStream);
+ p.StandardInput.Close();
+
+ if (!t.Join(5000))
+ throw new Exception("Failure while invoking GnuPG, program won't flush output");
+
+ if (!p.WaitForExit(5000))
+ throw new Exception("Failure while invoking GnuPG, program won't terminate");
+ }
+
+ private void Runner(object x)
+ {
+ //Unwrap arguments and read stream
+ object[] tmp = (object[])x;
+ Core.Utility.CopyStream((Stream)tmp[0], (Stream)tmp[1]);
+ }
+
+ #endregion
+ }
+}
diff --git a/Duplicati/Encryption/IEncryption.cs b/Duplicati/Encryption/IEncryption.cs
new file mode 100644
index 000000000..0ca5893a3
--- /dev/null
+++ b/Duplicati/Encryption/IEncryption.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace Duplicati.Encryption
+{
+ ///
+ /// Public interface for an encryption method
+ ///
+ public interface IEncryption
+ {
+ ///
+ /// Encrypts the contents of the inputfile, and saves the result as the outputfile.
+ ///
+ /// The file to encrypt
+ /// The encrypted file
+ void Encrypt(string inputfile, string outputfile);
+
+ ///
+ /// Encrypts the contents of the input stream, and writes the result to the output stream.
+ ///
+ /// The stream to encrypt
+ /// The encrypted stream
+ void Encrypt(Stream input, Stream output);
+
+ ///
+ /// Decrypts the contents of the input file and saves the result as the outputfile
+ ///
+ /// The file to decrypt
+ /// The decrypted output file
+ void Decrypt(string inputfile, string outputfile);
+
+ ///
+ /// Dencrypts the contents of the input stream, and writes the result to the output stream.
+ ///
+ /// The stream to decrypt
+ /// The decrypted stream
+ void Decrypt(Stream input, Stream output);
+ }
+}
diff --git a/Duplicati/Encryption/Properties/AssemblyInfo.cs b/Duplicati/Encryption/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..d99f1bb9f
--- /dev/null
+++ b/Duplicati/Encryption/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Duplicati.Encryption")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("HexaD")]
+[assembly: AssemblyProduct("Duplicati.Encryption")]
+[assembly: AssemblyCopyright("Copyright © HexaD 2008")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ea360f7d-b721-452e-8a7d-60da8ad1094f")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Duplicati/Main/RSyncDir.cs b/Duplicati/Main/RSyncDir.cs
index bd04d5ecf..05b5c7d08 100644
--- a/Duplicati/Main/RSyncDir.cs
+++ b/Duplicati/Main/RSyncDir.cs
@@ -174,10 +174,8 @@ namespace Duplicati.Main.RSync
string s = m_unproccesed[next];
m_unproccesed.RemoveAt(next);
- //TODO: Add the delta to zip, don't use temp file
if (ProccessDiff(s, sigfile))
totalSize = AddFileToCompression(s, c);
-
}
if (m_unproccesed.Count == 0)