return valid decrypted data on decryption failure
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Tue, 8 Aug 2017 10:03:01 +0000 (12:03 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:09 +0000 (13:34 +0200)
deltatar/tarfile.py

index 4bfc2a9..f628be2 100644 (file)
@@ -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