Просмотр исходного кода

refactor / generalize to num_cipher_blocks

Thomas Waldmann 8 лет назад
Родитель
Сommit
2d79f19263
3 измененных файлов с 21 добавлено и 15 удалено
  1. 3 3
      src/borg/crypto/key.py
  2. 16 10
      src/borg/crypto/low_level.pyx
  3. 2 2
      src/borg/testsuite/archiver.py

+ 3 - 3
src/borg/crypto/key.py

@@ -27,7 +27,7 @@ from ..item import Key, EncryptedKey
 from ..platform import SaveFile
 
 from .nonces import NonceManager
-from .low_level import AES, bytes_to_long, long_to_bytes, bytes_to_int, num_aes_blocks, hmac_sha256, blake2b_256, hkdf_hmac_sha512
+from .low_level import AES, bytes_to_long, long_to_bytes, bytes_to_int, num_cipher_blocks, hmac_sha256, blake2b_256, hkdf_hmac_sha512
 from .low_level import AES256_CTR_HMAC_SHA256 as CIPHERSUITE
 
 
@@ -514,7 +514,7 @@ class PassphraseKey(ID_HMAC_SHA_256, AESKeyBase):
             key.init(repository, passphrase)
             try:
                 key.decrypt(None, manifest_data)
-                num_blocks = num_aes_blocks(len(manifest_data) - 41)
+                num_blocks = num_cipher_blocks(len(manifest_data) - 41)
                 key.init_ciphers(key.extract_nonce(manifest_data) + num_blocks)
                 key._passphrase = passphrase
                 return key
@@ -554,7 +554,7 @@ class KeyfileKeyBase(AESKeyBase):
         else:
             if not key.load(target, passphrase):
                 raise PassphraseWrong
-        num_blocks = num_aes_blocks(len(manifest_data) - 41)
+        num_blocks = num_cipher_blocks(len(manifest_data) - 41)
         key.init_ciphers(key.extract_nonce(manifest_data) + num_blocks)
         key._passphrase = passphrase
         return key

+ 16 - 10
src/borg/crypto/low_level.pyx

@@ -168,11 +168,20 @@ def increment_iv(iv, amount=1):
     return iv
 
 
-def num_aes_blocks(length):
-    """Return the number of AES blocks required to encrypt/decrypt *length* bytes of data.
-       Note: this is only correct for modes without padding, like AES-CTR.
+def num_cipher_blocks(length, blocksize=16):
+    """Return the number of cipher blocks required to encrypt/decrypt <length> bytes of data.
+
+    For a precise computation, <blocksize> must be the used cipher's block size (AES: 16, CHACHA20: 64).
+
+    For a safe-upper-boundary computation, <blocksize> must be the MINIMUM of the block sizes (in
+    bytes) of ALL supported ciphers. This can be used to adjust a counter if the used cipher is not
+    known (yet).
+    The default value of blocksize must be adjusted so it reflects this minimum, so a call of this
+    function without a blocksize is "safe-upper-boundary by default".
+
+    Padding cipher modes are not supported.
     """
-    return (length + 15) // 16
+    return (length + blocksize - 1) // blocksize
 
 
 class CryptoError(Exception):
@@ -363,8 +372,7 @@ cdef class AES256_CTR_HMAC_SHA256:
             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
+        return num_cipher_blocks(length, self.cipher_blk_len)
 
     def set_iv(self, iv):
         # set_iv needs to be called before each encrypt() call
@@ -528,8 +536,7 @@ cdef class _AEAD_BASE:
             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
+        return num_cipher_blocks(length, self.cipher_blk_len)
 
     def set_iv(self, iv):
         # set_iv needs to be called before each encrypt() call,
@@ -679,8 +686,7 @@ cdef class AES:
             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
+        return num_cipher_blocks(length, self.cipher_blk_len)
 
     def set_iv(self, iv):
         # set_iv needs to be called before each encrypt() call,

+ 2 - 2
src/borg/testsuite/archiver.py

@@ -36,7 +36,7 @@ from ..archive import Archive, ChunkBuffer, flags_noatime, flags_normal
 from ..archiver import Archiver, parse_storage_quota
 from ..cache import Cache, LocalCache
 from ..constants import *  # NOQA
-from ..crypto.low_level import bytes_to_long, num_aes_blocks
+from ..crypto.low_level import bytes_to_long, num_cipher_blocks
 from ..crypto.key import KeyfileKeyBase, RepoKey, KeyfileKey, Passphrase, TAMRequiredError
 from ..crypto.keymanager import RepoIdMismatch, NotABorgKeyFile
 from ..crypto.file_integrity import FileIntegrityError
@@ -2169,7 +2169,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
                     hash = sha256(data).digest()
                     if hash not in seen:
                         seen.add(hash)
-                        num_blocks = num_aes_blocks(len(data) - 41)
+                        num_blocks = num_cipher_blocks(len(data) - 41)
                         nonce = bytes_to_long(data[33:41])
                         for counter in range(nonce, nonce + num_blocks):
                             self.assert_not_in(counter, used)