validate data lengths against value in header
[python-delta-tar] / deltatar / crypto.py
index 8928737..53150f1 100755 (executable)
@@ -233,6 +233,14 @@ class NonConsecutiveIV (Exception):
     pass
 
 
+class CiphertextTooLong (Exception):
+    """
+    An attempt was made to decrypt more data than the ciphertext size declared
+    in the object header.
+    """
+    pass
+
+
 class FormatError (Exception):
     """Unusable parameters in header."""
     pass
@@ -1288,6 +1296,7 @@ class Decrypt (Crypto):
 
     tag        = None   # GCM tag, part of header
     last_iv    = None   # check consecutive ivs in strict mode
+    hdr_ctsize = -1
 
     def __init__ (self, password=None, key=None, counter=None, fixedparts=None,
                   strict_ivs=False):
@@ -1379,9 +1388,17 @@ class Decrypt (Crypto):
             nacl         = hdr ["nacl"]
             iv           = hdr ["iv"]
             tag          = hdr ["tag"]
+            ctsize       = hdr ["ctsize"]
         except KeyError:
             raise InvalidHeader ("next: not a header %r" % hdr)
 
+        if ctsize > PDTCRYPT_MAX_OBJ_SIZE:
+            raise InvalidHeader ("next: ciphertext size %d exceeds maximum "
+                                 "object size (%d)"
+                                 % (ctsize, PDTCRYPT_MAX_OBJ_SIZE))
+
+        self.hdr_ctsize = ctsize
+
         super().next (self.password, paramversion, nacl, iv)
         if self.fixed is not None and self.valid_fixed_part (iv) is False:
             raise InvalidIVFixedPart ("iv %s has invalid fixed part"
@@ -1430,8 +1447,11 @@ class Decrypt (Crypto):
             raise InvalidGCMTag ("done: tag mismatch of object %d: %s "
                                   "rejected by finalize ()"
                                   % (self.cnt, binascii.hexlify (self.tag)))
-        self.ctsize += len (data)
+        self.ptsize += len (data)
         self.stats ["out"] += len (data)
+
+        assert self.ctsize == self.ptsize == self.hdr_ctsize
+
         return data
 
 
@@ -1443,6 +1463,11 @@ class Decrypt (Crypto):
             raise InvalidParameter ("process: expected byte buffer, not %s"
                                     % type (buf))
         self.ctsize += len (buf)
+        if self.ctsize > self.hdr_ctsize:
+            raise CiphertextTooLong ("process: object length exceeded: got "
+                                     "%d B but header specfiies %d B"
+                                     % (self.ctsize, self.hdr_ctsize))
+
         data = super().process (buf)
         self.ptsize += len (data)
         return data