clarify possible IV reuse with multiple Encrypt handles
[python-delta-tar] / deltatar / crypto.py
index 3c3a816..388e9c7 100755 (executable)
@@ -70,6 +70,14 @@ e. g. when traversing the same object multiple times. Since the crypto context
 has no notion of a position in a PDT encrypted archive, this condition must be
 sorted out downstream.
 
+When encrypting with more than one Encrypt context special care must be taken
+to prevent accidental reuse of IVs. The builtin protection against reuse is
+only effective for objects encrypted with the same Encrypt handle. If multiple
+Encrypt handles are used to encrypt with the same combination of password and
+salt, the encryption becomes susceptible to birthday attacks (bound = 2^32 due
+to the 64-bit random iv). Thus the use of multiple handles is discouraged.
+
+
 Command Line Utility
 -------------------------------------------------------------------------------
 
@@ -971,7 +979,7 @@ class Crypto (object):
         elif cnt == AES_GCM_IV_CNT_INDEX:
             if self.index_counter_used is True:
                 raise InvalidFileCounter ("attempted to reuse index file "
-                                          " counter %d: must be unique" % cnt)
+                                          "counter %d: must be unique" % cnt)
             self.index_counter_used = True
         if cnt <= AES_GCM_IV_CNT_MAX:
             self.cnt = cnt
@@ -1091,6 +1099,15 @@ class Crypto (object):
         self.enc = None
 
 
+    def get_used_ivs (self):
+        """
+        Get the set of IVs that were used so far during the lifetime of
+        this context. Useful to check for IV reuse if multiple encryption
+        contexts were used independently.
+        """
+        return self.used_ivs
+
+
 class Encrypt (Crypto):
 
     lastinfo     = None
@@ -1103,7 +1120,6 @@ class Encrypt (Crypto):
         The ctor will throw immediately if one of the parameters does not conform
         to our expectations.
 
-                  counter=AES_GCM_IV_CNT_DATA, strict_ivs=True):
         :type      version: int to fit   uint16_t
         :type paramversion: int to fit   uint16_t
         :param    password: mutually exclusive with ``key``
@@ -1117,6 +1133,16 @@ class Encrypt (Crypto):
                             and cannot be reused even with different fixed parts.
         :type   strict_ivs: bool
         :type     insecure: bool, whether to permit passthrough mode
+
+        *Security considerations*: The ``class Encrypt`` handle guarantees that
+        all random parts (first eight bytes) of the IVs used for encrypting
+        objects are unique. This guarantee does *not* apply across handles if
+        multiple handles are used with the same combination of password and
+        salt. Thus, use of multiple handles with the same combination of password
+        and salt is subject to birthday attacks with a bound of 2^32. To avoid
+        collisions, the application should keep the number of handles as low
+        as possible and check for reuse by comparing the set of IVs used of all
+        handles that were created (accessible using the ``get_used_ivs`` method).
         """
         if         password is     None and key is     None \
                 or password is not None and key is not None :
@@ -1333,7 +1359,8 @@ class Decrypt (Crypto):
                             ``AES_GCM_IV_CNT_INDEX`` are unique in each backup set
                             and cannot be reused even with different fixed parts.
         :type   fixedparts: bytes list
-        :type     insecure: bool, whether to process objects encrypted in
+        :type     insecure: bool
+        :param    insecure: whether to process objects encrypted in
                             passthrough mode (*``paramversion`` < 1*)
         """
         if         password is     None and key is     None \