Răsfoiți Sursa

make sure set_iv is called before each encrypt() call

Thomas Waldmann 8 ani în urmă
părinte
comite
5287531130
1 a modificat fișierele cu 13 adăugiri și 2 ștergeri
  1. 13 2
      src/borg/crypto/low_level.pyx

+ 13 - 2
src/borg/crypto/low_level.pyx

@@ -213,6 +213,8 @@ cdef class AES256_CTR_HMAC_SHA256:
         self.enc_key = enc_key
         if iv is not None:
             self.set_iv(iv)
+        else:
+            self.blocks = -1  # make sure set_iv is called before encrypt
 
     def __cinit__(self, mac_key, enc_key, iv=None):
         self.ctx = EVP_CIPHER_CTX_new()
@@ -227,6 +229,7 @@ cdef class AES256_CTR_HMAC_SHA256:
         encrypt data, compute mac over aad + iv + cdata, prepend header.
         aad_offset is the offset into the header where aad starts.
         """
+        assert self.blocks == 0, 'set_iv needs to be called before encrypt'
         cdef int ilen = len(data)
         cdef int hlen = len(header)
         cdef int aoffset = aad_offset
@@ -326,12 +329,14 @@ cdef class AES256_CTR_HMAC_SHA256:
         return (length + self.cipher_blk_len - 1) // self.cipher_blk_len
 
     def set_iv(self, iv):
+        # set_iv needs to be called before each encrypt() call
         assert isinstance(iv, bytes) and len(iv) == self.iv_len
         self.blocks = 0  # how many AES blocks got encrypted with this IV?
         for i in range(self.iv_len):
             self.iv[i] = iv[i]
 
     def next_iv(self):
+        # call this after encrypt() to get the next iv for the next encrypt() call
         return increment_iv(self.iv[:self.iv_len], self.blocks)
 
     cdef fetch_iv(self, unsigned char * iv_in):
@@ -368,6 +373,8 @@ cdef class _AEAD_BASE:
         self.enc_key = enc_key
         if iv is not None:
             self.set_iv(iv)
+        else:
+            self.blocks = -1  # make sure set_iv is called before encrypt
 
     def __cinit__(self, mac_key, enc_key, iv=None):
         self.ctx = EVP_CIPHER_CTX_new()
@@ -380,6 +387,7 @@ cdef class _AEAD_BASE:
         encrypt data, compute mac over aad + iv + cdata, prepend header.
         aad_offset is the offset into the header where aad starts.
         """
+        assert self.blocks == 0, 'set_iv needs to be called before encrypt'
         cdef int ilen = len(data)
         cdef int hlen = len(header)
         cdef int aoffset = aad_offset
@@ -423,7 +431,7 @@ cdef class _AEAD_BASE:
             offset += olen
             if not EVP_CIPHER_CTX_ctrl(self.ctx, EVP_CTRL_GCM_GET_TAG, self.mac_len, odata+hlen):
                 raise CryptoError('EVP_CIPHER_CTX_ctrl GET TAG failed')
-            self.blocks += self.block_count(ilen)
+            self.blocks = self.block_count(ilen)
             return odata[:offset]
         finally:
             PyMem_Free(odata)
@@ -473,7 +481,7 @@ cdef class _AEAD_BASE:
                 # a failure here means corrupted or tampered tag (mac) or data.
                 raise IntegrityError('Authentication / EVP_DecryptFinal_ex failed')
             offset += olen
-            self.blocks += self.block_count(offset)
+            self.blocks = self.block_count(offset)
             return odata[:offset]
         finally:
             PyMem_Free(odata)
@@ -484,12 +492,15 @@ cdef class _AEAD_BASE:
         return (length + self.cipher_blk_len - 1) // self.cipher_blk_len
 
     def set_iv(self, iv):
+        # set_iv needs to be called before each encrypt() call,
+        # because encrypt does a full initialisation of the cipher context.
         assert isinstance(iv, bytes) and len(iv) == self.iv_len
         self.blocks = 0  # number of cipher blocks encrypted with this IV
         for i in range(self.iv_len):
             self.iv[i] = iv[i]
 
     def next_iv(self):
+        # call this after encrypt() to get the next iv for the next encrypt() call
         # AES-GCM, AES-OCB, CHACHA20 ciphers all add a internal 32bit counter to the 96bit
         # (12 byte) IV we provide, thus we only need to increment the IV by 1 (and we must
         # not encrypt more than 2^32 cipher blocks with same IV):