Przeglądaj źródła

generalize block count computation

also: use block_count method for legacy ciphersuites
Thomas Waldmann 8 lat temu
rodzic
commit
71b8d7fc18
1 zmienionych plików z 36 dodań i 11 usunięć
  1. 36 11
      src/borg/crypto/low_level.pyx

+ 36 - 11
src/borg/crypto/low_level.pyx

@@ -196,6 +196,7 @@ cdef class AES256_CTR_HMAC_SHA256:
     cdef HMAC_CTX *hmac_ctx
     cdef unsigned char *mac_key
     cdef unsigned char *enc_key
+    cdef int cipher_blk_len
     cdef int iv_len, iv_len_short
     cdef int mac_len
     cdef unsigned char iv[16]  # XXX use self.iv_len or some MAX_IV_LEN?
@@ -204,6 +205,7 @@ cdef class AES256_CTR_HMAC_SHA256:
     def __init__(self, mac_key, enc_key, iv=None):
         assert isinstance(mac_key, bytes) and len(mac_key) == 32
         assert isinstance(enc_key, bytes) and len(enc_key) == 32
+        self.cipher_blk_len = 16
         self.iv_len = 16
         self.iv_len_short = 8
         self.mac_len = 32
@@ -230,7 +232,8 @@ cdef class AES256_CTR_HMAC_SHA256:
         cdef int hlen = len(header)
         cdef int aoffset = aad_offset
         cdef int alen = hlen - aoffset
-        cdef unsigned char *odata = <unsigned char *>PyMem_Malloc(hlen + self.mac_len + self.iv_len_short + ilen + 16)
+        cdef unsigned char *odata = <unsigned char *>PyMem_Malloc(hlen + self.mac_len + self.iv_len_short +
+                                                                  ilen + self.cipher_blk_len)  # play safe, 1 extra blk
         if not odata:
             raise MemoryError
         cdef int olen
@@ -264,7 +267,7 @@ cdef class AES256_CTR_HMAC_SHA256:
                 raise CryptoError('HMAC_Update failed')
             if not HMAC_Final(self.hmac_ctx, odata+hlen, NULL):
                 raise CryptoError('HMAC_Final failed')
-            self.blocks += num_aes_blocks(ilen)
+            self.blocks += self.block_count(ilen)
             return odata[:offset]
         finally:
             PyMem_Free(odata)
@@ -279,7 +282,7 @@ cdef class AES256_CTR_HMAC_SHA256:
         cdef int hlen = header_len
         cdef int aoffset = aad_offset
         cdef int alen = hlen - aoffset
-        cdef unsigned char *odata = <unsigned char *>PyMem_Malloc(ilen + 16)
+        cdef unsigned char *odata = <unsigned char *>PyMem_Malloc(ilen + self.cipher_blk_len)  # play safe, 1 extra blk
         if not odata:
             raise MemoryError
         cdef int olen
@@ -312,12 +315,16 @@ cdef class AES256_CTR_HMAC_SHA256:
             if rc <= 0:
                 raise CryptoError('EVP_DecryptFinal_ex failed')
             offset += olen
-            self.blocks += num_aes_blocks(offset)
+            self.blocks += self.block_count(offset)
             return odata[:offset]
         finally:
             PyMem_Free(odata)
             PyBuffer_Release(&idata)
 
+    def block_count(self, length):
+        # number of cipher blocks needed for data of length bytes
+        return (length + self.cipher_blk_len - 1) // self.cipher_blk_len
+
     def set_iv(self, iv):
         self.blocks = 0  # how many AES blocks got encrypted with this IV?
         for i in range(self.iv_len):
@@ -346,6 +353,7 @@ cdef class _AEAD_BASE:
     cdef CIPHER cipher
     cdef EVP_CIPHER_CTX *ctx
     cdef unsigned char *enc_key
+    cdef int cipher_blk_len
     cdef int iv_len
     cdef int mac_len
     cdef unsigned char iv[12]  # XXX use self.iv_len or some MAX_IV_LEN?
@@ -376,7 +384,8 @@ cdef class _AEAD_BASE:
         cdef int hlen = len(header)
         cdef int aoffset = aad_offset
         cdef int alen = hlen - aoffset
-        cdef unsigned char *odata = <unsigned char *>PyMem_Malloc(hlen + self.mac_len + self.iv_len + ilen + 16)
+        cdef unsigned char *odata = <unsigned char *>PyMem_Malloc(hlen + self.mac_len + self.iv_len +
+                                                                  ilen + self.cipher_blk_len)
         if not odata:
             raise MemoryError
         cdef int olen
@@ -414,7 +423,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 += num_aes_blocks(ilen)
+            self.blocks += self.block_count(ilen)
             return odata[:offset]
         finally:
             PyMem_Free(odata)
@@ -429,7 +438,7 @@ cdef class _AEAD_BASE:
         cdef int hlen = header_len
         cdef int aoffset = aad_offset
         cdef int alen = hlen - aoffset
-        cdef unsigned char *odata = <unsigned char *>PyMem_Malloc(ilen + 16)
+        cdef unsigned char *odata = <unsigned char *>PyMem_Malloc(ilen + self.cipher_blk_len)
         if not odata:
             raise MemoryError
         cdef int olen
@@ -464,12 +473,16 @@ 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 += num_aes_blocks(offset)
+            self.blocks += self.block_count(offset)
             return odata[:offset]
         finally:
             PyMem_Free(odata)
             PyBuffer_Release(&idata)
 
+    def block_count(self, length):
+        # number of cipher blocks needed for data of length bytes
+        return (length + self.cipher_blk_len - 1) // self.cipher_blk_len
+
     def set_iv(self, iv):
         self.blocks = 0  # number of cipher blocks encrypted with this IV
         for i in range(self.iv_len):
@@ -494,7 +507,19 @@ cdef class _AEAD_BASE:
             iv_out[i] = iv[i]
 
 
-cdef class AES256_GCM(_AEAD_BASE):
+cdef class _AES_BASE(_AEAD_BASE):
+    def __init__(self, mac_key, enc_key, iv=None):
+        self.cipher_blk_len = 16
+        super().__init__(mac_key, enc_key, iv=iv)
+
+
+cdef class _CHACHA_BASE(_AEAD_BASE):
+    def __init__(self, mac_key, enc_key, iv=None):
+        self.cipher_blk_len = 64
+        super().__init__(mac_key, enc_key, iv=iv)
+
+
+cdef class AES256_GCM(_AES_BASE):
     def __init__(self, mac_key, enc_key, iv=None):
         if OPENSSL_VERSION_NUMBER < 0x10001040:
             raise ValueError('AES GCM requires OpenSSL >= 1.0.1d. Detected: OpenSSL %08x' % OPENSSL_VERSION_NUMBER)
@@ -502,7 +527,7 @@ cdef class AES256_GCM(_AEAD_BASE):
         super().__init__(mac_key, enc_key, iv=iv)
 
 
-cdef class AES256_OCB(_AEAD_BASE):
+cdef class AES256_OCB(_AES_BASE):
     def __init__(self, mac_key, enc_key, iv=None):
         if OPENSSL_VERSION_NUMBER < 0x10100000:
             raise ValueError('AES OCB requires OpenSSL >= 1.1.0. Detected: OpenSSL %08x' % OPENSSL_VERSION_NUMBER)
@@ -510,7 +535,7 @@ cdef class AES256_OCB(_AEAD_BASE):
         super().__init__(mac_key, enc_key, iv=iv)
 
 
-cdef class CHACHA20_POLY1305(_AEAD_BASE):
+cdef class CHACHA20_POLY1305(_CHACHA_BASE):
     def __init__(self, mac_key, enc_key, iv=None):
         if OPENSSL_VERSION_NUMBER < 0x10100000:
             raise ValueError('CHACHA20-POLY1305 requires OpenSSL >= 1.1.0. Detected: OpenSSL %08x' % OPENSSL_VERSION_NUMBER)