fix index file encryption handling
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Fri, 21 Apr 2017 13:21:06 +0000 (15:21 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:08 +0000 (13:34 +0200)
deltatar/deltatar.py
deltatar/tarfile.py

index ac702e3..345e33f 100644 (file)
@@ -98,11 +98,6 @@ class DeltaTar(object):
     # establishing the Tarfile stream iff a password is supplied.
     crypto_ctx = None
 
-    # When encrypting, the salt is created by the first crypto operation, i. e.
-    # opening the index for writing. The subsequently opened archive uses the
-    # same salt.
-    nacl = None
-
     # python logger object.
     logger = None
 
@@ -522,6 +517,9 @@ class DeltaTar(object):
         inheriting the encryption and compression settings from the backup.
         Returns a file object ready to use.
 
+        :param mode:        IO mode (read or write, ``"r"`` and ``"w"``,
+                            respectively).
+        :type  mode:        str
         :param kind:        Role of the file, see AUXILIARY_FILE_* constants. The
                             only special value is AUXILIARY_FILE_INFO which
                             sets the appropriate counter in the crypto layer.
@@ -534,14 +532,18 @@ class DeltaTar(object):
         else:
             comptype = 'tar'
 
-        encver = None
-        counter = None
-        if self.crypto_ctx is not None and kind == AUXILIARY_FILE_INFO:
-            counter = crypto.AES_GCM_IV_CNT_INFOFILE
-
-        return tarfile._Stream(name=path, mode=mode, comptype=comptype,
+        sink = tarfile._Stream(name=path, mode=mode, comptype=comptype,
+                               concat_stream=True, # no global zlib header
                                bufsize=tarfile.RECORDSIZE, fileobj=None,
-                               encryption=self.crypto_ctx, enccounter=counter)
+                               encryption=self.crypto_ctx)
+        if self.crypto_ctx is not None and mode == "w":
+            counter = None
+            if kind == AUXILIARY_FILE_INFO:
+                counter = crypto.AES_GCM_IV_CNT_INFOFILE
+            sink._init_write_encrypt (path, counter)
+
+        return sink
+
 
     def create_full_backup(self, source_path, backup_path,
                            max_volume_size=None, extra_data=dict()):
@@ -693,13 +695,9 @@ class DeltaTar(object):
         # init index
         index_name = self.index_name_func(True)
         index_path = os.path.join(backup_path, index_name)
-        index_sink = self.open_auxiliary_file(index_path, 'w') # **NOT** an fd
-        if index_sink.encryption is not None:
-            self.nacl = index_sink.encryption.nacl
-            dummyhdr = index_sink.encryption.next (path)
-            index_sink.write (dummyhdr)
+        index_sink = self.open_auxiliary_file(index_path, 'w')
         index_sink.write (index_accu.getvalue ())
-        index_sink.close ()
+        index_sink.close (close_fileobj=True)
 
     def create_diff_backup(self, source_path, backup_path, previous_index_path,
                            max_volume_size=None, extra_data=dict()):
index 6056d55..fe0a0aa 100644 (file)
@@ -418,8 +418,7 @@ class _Stream:
     remainder = -1 # track size in encrypted entries
 
     def __init__(self, name, mode, comptype, fileobj, bufsize,
-                 concat_stream=False, encryption=None, enccounter=None,
-                 compresslevel=9):
+                 concat_stream=False, encryption=None, compresslevel=9):
         """Construct a _Stream object.
         """
         self._extfileobj = True
@@ -462,11 +461,12 @@ class _Stream:
                 except ImportError:
                     raise CompressionError("zlib module is not available")
                 self.zlib = zlib
-                if mode == "r":
-                    self._init_read_gz()
-                    self.exception = zlib.error
-                elif mode == "w" and concat_stream is False:
-                    self._new_gz_block()
+                if concat_stream is False:
+                    if mode == "r":
+                        self._init_read_gz()
+                        self.exception = zlib.error
+                    elif mode == "w":
+                        self._new_gz_block()
                 self.crc = zlib.crc32(b"") & 0xFFFFffff
 
             elif comptype == "bz2":
@@ -516,7 +516,7 @@ class _Stream:
             self.close()
 
 
-    def _init_write_encrypt (self, entry=None):
+    def _init_write_encrypt (self, entry=None, counter=None):
         """Save position for delayed write of header; fill the header location
         with dummy bytes."""
         if self.encryption is not None:
@@ -524,7 +524,7 @@ class _Stream:
             # secondly, assemble the header with the updated parameters
             # and commit it directly to the underlying stream, bypassing the
             # encryption layer in .__write().
-            dummyhdr = self.encryption.next (entry)
+            dummyhdr = self.encryption.next (entry, counter=counter)
             if dummyhdr is None:
                 raise EncryptionError ("Crypto.next(): bad dummy header") # XXX
 
@@ -540,7 +540,6 @@ class _Stream:
 
         Returns the list of IV fixed parts as used during encryption.
         """
-        fixed = None
         if      self.encryption is not None \
             and self.lasthdr    is not None :
             self.__sync ()
@@ -551,11 +550,10 @@ class _Stream:
             dpos = pos1 - self.lasthdr
             assert dpos == crypto.PDTCRYPT_HDR_SIZE
             self.fileobj.seek_set (pos0)
-            data, hdr, fixed = self.encryption.done (dummy)
+            data, hdr, _ = self.encryption.done (dummy)
             self.__write_to_file(hdr, pos=self.lasthdr)
             self.__write_to_file(data) # append remainder of data
             self.lasthdr = -1
-        return fixed
 
 
     def _finalize_write_gz (self):
@@ -691,7 +689,6 @@ class _Stream:
         """Close the _Stream object. No operation should be
            done on it afterwards.
         """
-        fixed = None
 
         if self.closed:
             return
@@ -703,7 +700,7 @@ class _Stream:
         if close_fileobj is True:
             if self.mode == "w":
                 # end of Tar archive marker (two empty blocks) was written
-                fixed = self._finalize_write_encrypt ()
+                self._finalize_write_encrypt ()
             if not self._extfileobj:
                 self.fileobj.close()
         else:
@@ -716,13 +713,9 @@ class _Stream:
                     raise CompressionError("bad gzip crc")
         self.closed = True
 
-        return fixed
-
     def _init_read_gz(self):
         """Initialize for reading a gzip compressed fileobj.
         """
-        if getattr(self, "zlib", None) is None:
-            return
         self.cmp = self.zlib.decompressobj(-self.zlib.MAX_WBITS)
 
         # taken from gzip.GzipFile with some alterations