Index: decrypt-dump.sh
===================================================================
--- decrypt-dump.sh	(revision 0)
+++ decrypt-dump.sh	(working copy)
@@ -0,0 +1,10 @@
+#!/bin/bash
+# Decryptor script to handle encrypted  SVN dumps
+# arg1 AES256 key in hex text (32 bytes in 64 characters)
+# arg2 Encryped dump file
+
+file_name=$2
+key=$1
+counter_prefix="$(echo -n  ${file_name##*/} | openssl md5 | awk '{print substr($2,0,16)}')"
+openssl enc -d -aes-256-ctr -K $1 -iv $counter_prefix -in $2 -out /tmp/mm/client_security.000000-001767.svndmp.bz2.clear
+echo 'Decrypted SVN dump to '$2'.clear'
Index: how_to_decrpyt_backups.txt
===================================================================
--- how_to_decrpyt_backups.txt	(revision 0)
+++ how_to_decrpyt_backups.txt	(working copy)
@@ -0,0 +1 @@
+Look at decrypt-dump.sh which is based on "openssl enc -d -aes-256-ctr"
Index: svn-backup-dumps.py
===================================================================
--- svn-backup-dumps.py	(revision 1684623)
+++ svn-backup-dumps.py	(working copy)
@@ -39,6 +39,7 @@
 #    6. Create bzipped dump files.
 #    7. Transfer the dumpfile to another host using ftp.
 #    8. Transfer the dumpfile to another host using smb.
+#    9. Create encrypted dump files.
 #
 # See also 'svn-backup-dumps.py -h'.
 #
@@ -143,13 +144,24 @@
 #    repository name (basename of the repository path).
 #
 #
+# 9. Create encrypted dump files
 #
+#    svn-backup-dumps.py -k <key>
+#   
+#    <key>        the encryption key which is used to encrypt the dump. 
+#                 it has to be 32 byte hex text (64 characters) like 
+#                 '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'
+#
+#    The encryption feature works in conjuction with every other configuration / feature
+#    except -z option (stock zip). As for the encryption scheme the file name of the dump
+#    plays a crucial part in both encryption and decryption therefore it must not be changed!
+#
 # TODO:
 #  - find out how to report smbclient errors
 #  - improve documentation
 #
 
-__version = "0.6"
+__version = "0.7"
 
 import sys
 import os
@@ -169,12 +181,56 @@
 except ImportError:
     have_bz2 = False
 
+try:
+    from Crypto.Cipher import AES
+    from hashlib import md5
+    import struct
+    have_aes = True
+except ImportError:
+    have_aes = False
 
+class SvnBackupAesCtrSchema:
+    '''
+        Encryption schema uses AES256 in CTR mode (openssl compliant)
+        It uses the md5 hash of filename to create the counter/iv prefix
+        (not a secret but needs to be different per file)
+
+        Example decryption with openssl (has to be 1.0.1 at least):
+        openssl enc -d -aes-256-ctr -K 3333333333333333333333333333333333333333333333333333333333333333 -iv 7392497a327cd49d -in /var/tmp/aes256_ctr_test.txt
+    '''
+    def __init__(self,key,filename):
+        self.__key = key
+        self.__counter_prefix = md5(filename).digest()[:8]
+        self.__position = 0
+        print 'In Init'
+    def encrypt(self, data):
+        # Create key stream
+        start_block = self.__position/AES.block_size
+        end_block = ((self.__position+len(data))/AES.block_size)+1
+        counter_blocks = ''.join([ (self.__counter_prefix+struct.pack(">Q",c)) for c in range(start_block,end_block)])
+        key_stream = AES.new(self.__key,AES.MODE_ECB).encrypt(counter_blocks)[self.__position%AES.block_size:]
+        # Encrypt the data
+        cipher_text = bytearray(data)
+        for i in range(len(cipher_text)):
+            cipher_text[i] = cipher_text[i]^ord(key_stream[i])
+        self.__position+=len(data)
+        return str(cipher_text)
+
+class SvnBackupStubEncryptor:
+    def __init__(self):
+        pass
+    def encrypt(self, data):
+        return data
+
 class SvnBackupOutput:
 
-    def __init__(self, abspath, filename):
+    def __init__(self, abspath, filename,encryption_key=None):
         self.__filename = filename
         self.__absfilename = os.path.join(abspath, filename)
+        if encryption_key:
+            self.encryptor = SvnBackupAesCtrSchema(encryption_key,filename)
+        else:
+            self.encryptor = SvnBackupStubEncryptor()
 
     def open(self):
         pass
@@ -194,14 +250,14 @@
 
 class SvnBackupOutputPlain(SvnBackupOutput):
 
-    def __init__(self, abspath, filename):
-        SvnBackupOutput.__init__(self, abspath, filename)
+    def __init__(self, abspath, filename, encryption_key=None):
+        SvnBackupOutput.__init__(self, abspath, filename, encryption_key)
 
     def open(self):
         self.__ofd = open(self.get_absfilename(), "wb")
 
     def write(self, data):
-        self.__ofd.write(data)
+        self.__ofd.write(self.encryptor.encrypt(data))
 
     def close(self):
         self.__ofd.close()
@@ -209,8 +265,10 @@
 
 class SvnBackupOutputGzip(SvnBackupOutput):
 
-    def __init__(self, abspath, filename):
-        SvnBackupOutput.__init__(self, abspath, filename + ".gz")
+    def __init__(self, abspath, filename, encryption_key=None):
+        if encryption_key:
+            raise SvnBackupException("Backup encryption in stock Gzip mode is not supported! (use non-stock gzip or stock bz2 compression)")
+        SvnBackupOutput.__init__(self, abspath, filename + ".gz", encryption_key)
 
     def open(self):
         self.__compressor = gzip.GzipFile(filename=self.get_absfilename(),
@@ -226,25 +284,25 @@
 
 class SvnBackupOutputBzip2(SvnBackupOutput):
 
-    def __init__(self, abspath, filename):
-        SvnBackupOutput.__init__(self, abspath, filename + ".bz2")
+    def __init__(self, abspath, filename, encryption_key=None):
+        SvnBackupOutput.__init__(self, abspath, filename + ".bz2", encryption_key)
 
     def open(self):
         self.__compressor = bz2.BZ2Compressor()
         self.__ofd = open(self.get_absfilename(), "wb")
 
     def write(self, data):
-        self.__ofd.write(self.__compressor.compress(data))
+        self.__ofd.write(self.encryptor.encrypt(self.__compressor.compress(data)))
 
     def close(self):
-        self.__ofd.write(self.__compressor.flush())
+        self.__ofd.write(self.encryptor.encrypt(self.__compressor.flush()))
         self.__ofd.close()
 
 class SvnBackupOutputCommand(SvnBackupOutput):
 
     def __init__(self, abspath, filename, file_extension, cmd_path,
-                 cmd_options):
-        SvnBackupOutput.__init__(self, abspath, filename + file_extension)
+                 cmd_options,encryption_key=None):
+        SvnBackupOutput.__init__(self, abspath, filename + file_extension,encryption_key)
         self.__cmd_path    = cmd_path
         self.__cmd_options = cmd_options
 
@@ -262,7 +320,7 @@
         self.__stdin = proc.stdin
 
     def write(self, data):
-        self.__stdin.write(data)
+        self.__stdin.write(self.encryptor.encrypt(data))
 
     def close(self):
         self.__stdin.close()
@@ -329,6 +387,11 @@
         if options.svnlook_path:
            self.__svnlook_path = options.svnlook_path
 
+        # encryption
+        self.__encryption_key = None
+        if options.key:
+            self.__encryption_key = options.key.decode("hex")
+
         # check compress option
         self.__gzip_path  = options.gzip_path
         self.__bzip2_path = options.bzip2_path
@@ -511,17 +574,17 @@
         output = None
         if self.__bzip2_path:
              output = SvnBackupOutputCommand(self.__dumpdir, filename, ".bz2",
-                                             self.__bzip2_path, "-cz" )
+                                             self.__bzip2_path, "-cz" , encryption_key=self.__encryption_key )
         elif self.__gzip_path:
              output = SvnBackupOutputCommand(self.__dumpdir, filename, ".gz",
-                                             self.__gzip_path, "-cf" )
+                                             self.__gzip_path, "-cf" , encryption_key=self.__encryption_key )
         elif self.__zip:
             if self.__zip == "gzip":
-                output = SvnBackupOutputGzip(self.__dumpdir, filename)
+                output = SvnBackupOutputGzip(self.__dumpdir, filename, encryption_key=self.__encryption_key )
             else:
-                output = SvnBackupOutputBzip2(self.__dumpdir, filename)
+                output = SvnBackupOutputBzip2(self.__dumpdir, filename, encryption_key=self.__encryption_key )
         else:
-            output = SvnBackupOutputPlain(self.__dumpdir, filename)
+            output = SvnBackupOutputPlain(self.__dumpdir, filename, encryption_key=self.__encryption_key )
         absfilename = output.get_absfilename()
         realfilename = output.get_filename()
         if checkonly:
@@ -608,6 +671,13 @@
                        action="store_true",
                        dest="bzip2", default=False,
                        help="compress the dump using python bzip2 library.")
+
+    if have_aes:
+        parser.add_option("-k",
+                       action="store", type=str,
+                       dest="key", default=None,
+                       help="key for encrypted backups (AES256-CTR mode)")
+
     parser.add_option("-i",
                        action="store_true",
                        dest="relative_incremental", default=False,
@@ -676,6 +746,10 @@
         print("    -t smb:<share>:<user>:<password>:<dest-path>")
         print("")
         sys.exit(0)
+    if  options.key and len(options.key)!=64:
+        print("Encryption key must be 32 bytes long represented in hex-text encoding in the argument!\n")
+        print("\tExample: -k 00112233445566778899aabbccddeeff000102030405060708090a0b0c0d0e0f\n")
+        sys.exit(0)
     rc = False
     try:
         backup = SvnBackup(options, args)
