From ef3b44993ea847df05bfffe59f8377e895acf5c3 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 8 Aug 2017 12:03:01 +0200 Subject: [PATCH] return valid decrypted data on decryption failure --- deltatar/tarfile.py | 22 +++++++++++++++++++--- 1 files changed, 19 insertions(+), 3 deletions(-) diff --git a/deltatar/tarfile.py b/deltatar/tarfile.py index 4bfc2a9..f628be2 100644 --- a/deltatar/tarfile.py +++ b/deltatar/tarfile.py @@ -996,11 +996,17 @@ class _Stream: def __read(self, size): - """Return size bytes from stream. If internal buffer is empty, - read another block from the stream. + """ + Return size bytes from stream. If internal buffer is empty, read + another block from the stream. + + The function returns up to size bytes of data. When an error occurs + during decryption, everything until the end of the last successfully + finalized object is returned. """ c = len(self.buf) t = [self.buf] + good_crypto = 0 while c < size: todo = size if self.arcmode & ARCMODE_ENCRYPT: @@ -1019,7 +1025,17 @@ class _Stream: if todo == self.remainder: # at the end of a crypto object; finalization will fail if # the GCM tag does not match - trailing = self._finalize_read_encrypt () + try: + trailing = self._finalize_read_encrypt () + except DecryptionError as exn: + if good_crypto == 0: + raise + # some objects did validate; discard all data after it; + # next call will start with the bad object and error + # out immediately + self.buf = b"".join (t [good_crypto:]) + return b"".join (t [:good_crypto]) + good_crypto = len (t) + 1 if len (trailing) > 0: buf += trailing self.remainder = 0 -- 1.7.1