start working on AES-only delta tar mode, with no encryption. some tests still fail
authorEduardo Robles Elvira <edulix@wadobo.com>
Wed, 9 Oct 2013 09:56:09 +0000 (11:56 +0200)
committerEduardo Robles Elvira <edulix@wadobo.com>
Wed, 9 Oct 2013 09:56:09 +0000 (11:56 +0200)
deltatar/deltatar.py
deltatar/tarfile.py
runtests.py
testing/test_deltatar.py

index bab22f4..872f9cf 100644 (file)
@@ -94,7 +94,9 @@ class DeltaTar(object):
         '|bz2': '.bz2',
         '#gz': '.gz',
         '#gz.aes128': '.gz.aes128',
-        '#gz.aes256': '.gz.aes256'
+        '#gz.aes256': '.gz.aes256',
+        '#aes128': '.aes128',
+        '#aes256': '.aes256',
     }
 
     # valid index modes and their corresponding default file extension
@@ -103,7 +105,9 @@ class DeltaTar(object):
         'gz': '.gz',
         'bz2': '.bz2',
         'gz.aes128': '.gz.aes128',
-        'gz.aes256': '.gz.aes256'
+        'gz.aes256': '.gz.aes256',
+        'aes128': '.aes128',
+        'aes256': '.aes256'
     }
 
     # valid path prefixes
@@ -149,6 +153,8 @@ class DeltaTar(object):
            '#gz'       open a stream of gzip compressed tar blocks
            '#gz.aes128'   open an aes128 encrypted stream of gzip compressed tar blocks
            '#gz.aes256'   open an aes256 encrypted stream of gzip compressed tar blocks
+           '#aes128'   open an aes128 encrypted stream of tar blocks
+           '#aes256'   open an aes256 encrypted stream of tar blocks
 
         - password: used together with aes modes to encrypt and decrypt backups.
 
@@ -166,6 +172,8 @@ class DeltaTar(object):
            'bz2'      open with bzip2 compression
            'gz.aes128'   open an aes128 encrypted stream of gzip compressed tar blocks
            'gz.aes256'   open an aes256 encrypted stream of gzip compressed tar blocks
+           'aes128'   open an aes128 encrypted stream of tar blocks
+           'aes256'   open an aes256 encrypted stream of tar blocks
 
         - index_name_func: function that sets a custom name for the index file.
           This function receives the backup_path and if it's a full backup as
@@ -199,6 +207,8 @@ class DeltaTar(object):
                 index_mode = "gz"
             elif 'bz2' in mode:
                 index_mode = "bz2"
+            elif 'aes' in mode:
+                index_mode = mode[1:]
         elif mode not in self.__index_extensions_dict:
             raise Exception('Unrecognized extension')
 
index f9c8e79..1832199 100644 (file)
@@ -456,7 +456,7 @@ class _Stream:
                 self._init_write_gz()
             self.crc = zlib.crc32("") & 0xffffffffL
 
-        if comptype == "bz2":
+        elif comptype == "bz2":
             try:
                 import bz2
             except ImportError:
@@ -467,6 +467,13 @@ class _Stream:
             else:
                 self.cmp = bz2.BZ2Compressor()
 
+        elif self.enctype == 'aes':
+            self.encryption = aescrypto.AESCrypt(self.password,
+                                                key_length=self.key_length)
+            if mode != "r":
+                self.encryption.init()
+                self.__write_to_file(self.encryption.salt_str)
+
     def __del__(self):
         if hasattr(self, "closed") and not self.closed:
             self.close()
@@ -504,6 +511,8 @@ class _Stream:
             raise CompressionError("new compression blocks can only be added in mode 'w'")
         if self.comptype == "gz":
             self._new_gz_block(True)
+        elif self.enctype == 'aes':
+            self._new_aes_block(True)
         else:
             raise CompressionError("Concat compression only available for comptype 'gz'")
 
@@ -522,19 +531,23 @@ class _Stream:
 
         # if aes, we encrypt after compression
         if self.enctype == 'aes':
-            self.__write_to_file(self.encryption.close_enc())
-            if set_last_block_offset:
-                self.last_block_offset = self.fileobj.tell()
-            self.encryption = aescrypto.AESCrypt(self.password,
-                                                 key_length=self.key_length)
-            self.encryption.init()
-            self.__write_to_file(self.encryption.salt_str)
+            self._new_aes_block(set_last_block_offset)
         elif set_last_block_offset:
             self.last_block_offset = self.fileobj.tell()
 
         timestamp = struct.pack("<L", long(time.time()))
         self.__write("\037\213\010\000%s\002\377" % timestamp)
 
+
+    def _new_aes_block(self, set_last_block_offset=False):
+        self.__write_to_file(self.encryption.close_enc())
+        if set_last_block_offset:
+            self.last_block_offset = self.fileobj.tell()
+        self.encryption = aescrypto.AESCrypt(self.password,
+                                                key_length=self.key_length)
+        self.encryption.init()
+        self.__write_to_file(self.encryption.salt_str)
+
     def write(self, s):
         """Write string s to the stream.
         """
@@ -1943,6 +1956,9 @@ class TarFile(object):
            'w#gz.aes128'   open an aes128 encrypted stream of gzip compressed tar blocks for writing
            'r#gz.aes256'   open an aes256 encrypted stream of gzip compressed tar blocks for reading
            'w#gz.aes256'   open an aes256 encrypted stream of gzip compressed tar blocks for writing
+
+           'r#aes128'    open an aes128 encrypted stream of tar blocks for reading
+           'w#aes128'    open an aes128 encrypted stream of tar blocks for writing
         """
 
         if not name and not fileobj:
@@ -2000,8 +2016,9 @@ class TarFile(object):
             if filemode not in "rw":
                 raise ValueError("mode must be 'r' or 'w'")
 
-            if comptype not in ["gz", "gz.aes128", "gz.aes256"]:
-                raise ValueError("comptype must be 'gz'")
+            if comptype not in ["gz", "gz.aes128", "gz.aes256", 'aes128',
+                                'aes256']:
+                raise ValueError("comptype must be 'gz' or 'aes'")
 
             # encryption gz.aes128 or gz.aes256
             if "." in comptype:
@@ -2013,6 +2030,16 @@ class TarFile(object):
                 if not password:
                     raise ValueError("you should give a password for encryption")
 
+            if comptype.startswith("aes"):
+                enctype = comptype
+                comptype = 'tar'
+                kl = comptype[3:]
+                enctype = enctype[:3]
+                key_length = 128 if kl == '128' else 256
+                password = kwargs.get('password', '')
+                if not password:
+                    raise ValueError("you should give a password for encryption")
+
             kwargs['concat_compression'] = True
 
             t = cls(name, filemode,
index a984af3..19b17f5 100644 (file)
@@ -26,7 +26,9 @@ from testing.test_encryption import EncryptionTest
 from testing.test_deltatar import (DeltaTarTest, DeltaTar2Test,
     DeltaTarStreamTest, DeltaTarGzipTest, DeltaTarGzipStreamTest,
     DeltaTarGzipConcatTest, DeltaTarGzipAes128ConcatTest,
-    DeltaTarGzipAes256ConcatTest)
+    DeltaTarGzipAes256ConcatTest,
+    #DeltaTarAes128ConcatTest, DeltaTarAes256ConcatTest
+    )
 
 if __name__ == "__main__":
     unittest.main()
index 596288e..b5c6802 100644 (file)
@@ -1299,3 +1299,19 @@ class DeltaTarGzipAes256ConcatTest(DeltaTarTest):
     '''
     MODE = '#gz.aes256'
     PASSWORD = 'some magic key'
+
+
+class DeltaTarAes128ConcatTest(DeltaTarTest):
+    '''
+    Same as DeltaTar but with specific aes128 concat stream mode
+    '''
+    MODE = '#aes128'
+    PASSWORD = 'some magic key'
+
+
+class DeltaTarAes256ConcatTest(DeltaTarTest):
+    '''
+    Same as DeltaTar but with specific aes128 concat stream mode
+    '''
+    MODE = '#aes256'
+    PASSWORD = 'some magic key'
\ No newline at end of file