From: Philipp Gesang Date: Fri, 21 Apr 2017 13:21:06 +0000 (+0200) Subject: fix index file encryption handling X-Git-Tag: v2.2~7^2~154 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=c8c72fe19d5402c74355a9730e7e38c6400fadde;p=python-delta-tar fix index file encryption handling --- diff --git a/deltatar/deltatar.py b/deltatar/deltatar.py index ac702e3..345e33f 100644 --- a/deltatar/deltatar.py +++ b/deltatar/deltatar.py @@ -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()): diff --git a/deltatar/tarfile.py b/deltatar/tarfile.py index 6056d55..fe0a0aa 100644 --- a/deltatar/tarfile.py +++ b/deltatar/tarfile.py @@ -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