improve iv diagnostics when decrypting
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Mon, 8 May 2017 13:33:29 +0000 (15:33 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:08 +0000 (13:34 +0200)
deltatar/crypto.py

index 44ca91f..fed8e56 100755 (executable)
@@ -37,6 +37,7 @@ Errors fall into roughly three categories:
         - ``InvalidGCMTag`` (decryption failed on account of an invalid GCM
           tag),
         - ``InvalidIVFixedPart`` (IV fixed part of object not found in list),
+        - ``DuplicateIV`` (the IV of an encrypted object already occurred),
         - ``DecryptionError`` (used in CLI decryption).
 
     - Incorrect usage of the library.
@@ -55,6 +56,11 @@ Errors fall into roughly three categories:
 Also, ``EndOfFile`` is used as a sentinel to communicate that a stream supplied
 for reading is exhausted.
 
+Initialization Vectors
+-------------------------------------------------------------------------------
+
+Initialization vectors are checked reuse during the lifetime of a decryptor.
+
 """
 
 import binascii
@@ -131,7 +137,7 @@ class DuplicateIV (Exception):
 
 
 class NonConsecutiveIV (Exception):
-    """IV reused."""
+    """IVs not numbered consecutively (not necessarily an error)."""
     pass
 
 
@@ -363,6 +369,12 @@ def hdr_fmt_pretty (h):
                    hex_spaced_of_bytes (struct.pack (FMT_UINT64_LE, h["ctsize"])),
                    hex_spaced_of_bytes (h["tag"]))
 
+IV_FMT = "((f %s) (c %d))"
+
+def iv_fmt (iv):
+    fixed, cnt = struct.unpack (FMT_I2N_IV, iv)
+    return IV_FMT % (binascii.hexlify (fixed), cnt)
+
 
 ###############################################################################
 ## passthrough / null encryption
@@ -672,7 +684,7 @@ class Decrypt (Crypto):
 
     def check_duplicate_iv (self, iv):
         if self.strict_ivs is True and iv in self.used_ivs:
-            raise DuplicateIV ("iv [%r] was reused" % iv)
+            raise DuplicateIV ("iv %s was reused" % iv_fmt (iv))
         # vi has not been used before; add to collection
         self.used_ivs.add (iv)
 
@@ -683,9 +695,9 @@ class Decrypt (Crypto):
                 and self.last_iv is not None \
                 and self.last_iv [0] == fixed \
                 and self.last_iv [1] != cnt - 1:
-            raise NonConsecutiveIV ("iv [%r] counter not successor of "
+            raise NonConsecutiveIV ("iv %s counter not successor of "
                                     "last object (expected %d, found %d)"
-                                    % (self.last_iv [1], cnt))
+                                    % (iv_fmt (self.last_iv [1]), cnt))
         self.last_iv = (iv, cnt)
 
 
@@ -705,12 +717,11 @@ class Decrypt (Crypto):
         except KeyError:
             raise InvalidHeader ("next: not a header %r" % hdr)
 
-        if self.key is None:
+        if self.key is None or nacl != self.nacl:
             super().next (self.password, paramversion, nacl)
         if self.fixed is not None and self.valid_fixed_part (iv) is False:
-            fixed, _ = struct.unpack (FMT_I2N_IV, iv)
-            raise InvalidIVFixedPart ("iv [%r] has invalid fixed part [%r]"
-                                      % (iv, fixed))
+            raise InvalidIVFixedPart ("iv %s has invalid fixed part"
+                                      % iv_fmt (iv))
         self.check_duplicate_iv   (iv)
         self.check_consecutive_iv (iv)