فهرست منبع

rebuild_refcounts: keep archive ID, if possible

rebuild_refcounts verifies and recreates the TAM.
Now it re-uses the salt, so that the archive ID does not change
just because of a new salt if the archive has still the same data.
Thomas Waldmann 1 سال پیش
والد
کامیت
ead49d4a24
4فایلهای تغییر یافته به همراه14 افزوده شده و 12 حذف شده
  1. 4 4
      src/borg/archive.py
  2. 1 1
      src/borg/archiver.py
  3. 1 1
      src/borg/cache.py
  4. 8 6
      src/borg/crypto/key.py

+ 4 - 4
src/borg/archive.py

@@ -380,7 +380,7 @@ class Archive:
     def _load_meta(self, id):
         data = self.key.decrypt(id, self.repository.get(id))
         # we do not require TAM for archives, otherwise we can not even borg list a repo with old archives.
-        archive, self.tam_verified = self.key.unpack_and_verify_archive(data, force_tam_not_required=True)
+        archive, self.tam_verified, _ = self.key.unpack_and_verify_archive(data, force_tam_not_required=True)
         metadata = ArchiveItem(internal_dict=archive)
         if metadata.version != 1:
             raise Exception('Unknown archive metadata version')
@@ -1441,7 +1441,7 @@ class ArchiveChecker:
                 # **after** doing the low-level checks and having a strong indication that we
                 # are likely looking at an archive item here, also check the TAM authentication:
                 try:
-                    archive, verified = self.key.unpack_and_verify_archive(data, force_tam_not_required=False)
+                    archive, verified, _ = self.key.unpack_and_verify_archive(data, force_tam_not_required=False)
                 except IntegrityError:
                     # TAM issues - do not accept this archive!
                     # either somebody is trying to attack us with a fake archive data or
@@ -1687,7 +1687,7 @@ class ArchiveChecker:
                     del self.manifest.archives[info.name]
                     continue
                 try:
-                    archive, verified = self.key.unpack_and_verify_archive(data, force_tam_not_required=False)
+                    archive, verified, salt = self.key.unpack_and_verify_archive(data, force_tam_not_required=False)
                 except IntegrityError as integrity_error:
                     # looks like there is a TAM issue with this archive, this might be an attack!
                     # when upgrading to borg 1.2.5, users are expected to TAM-authenticate all archives they
@@ -1710,7 +1710,7 @@ class ArchiveChecker:
                 for previous_item_id in archive.items:
                     mark_as_possibly_superseded(previous_item_id)
                 archive.items = items_buffer.chunks
-                data = self.key.pack_and_authenticate_metadata(archive.as_dict(), context=b'archive')
+                data = self.key.pack_and_authenticate_metadata(archive.as_dict(), context=b'archive', salt=salt)
                 new_archive_id = self.key.id_hash(data)
                 cdata = self.key.encrypt(data)
                 add_reference(new_archive_id, len(data), len(cdata), cdata)

+ 1 - 1
src/borg/archiver.py

@@ -1724,7 +1724,7 @@ class Archiver:
                     archive_formatted = format_archive(info)
                     cdata = repository.get(archive_id)
                     data = key.decrypt(archive_id, cdata)
-                    archive, verified = key.unpack_and_verify_archive(data, force_tam_not_required=True)
+                    archive, verified, _ = key.unpack_and_verify_archive(data, force_tam_not_required=True)
                     if not verified:  # we do not have an archive TAM yet -> add TAM now!
                         archive = ArchiveItem(internal_dict=archive)
                         archive.cmdline = [safe_decode(arg) for arg in archive.cmdline]

+ 1 - 1
src/borg/cache.py

@@ -726,7 +726,7 @@ class LocalCache(CacheStatsMixin):
             nonlocal processed_item_metadata_chunks
             csize, data = decrypted_repository.get(archive_id)
             chunk_idx.add(archive_id, 1, len(data), csize)
-            archive, verified = self.key.unpack_and_verify_archive(data, force_tam_not_required=True)
+            archive, verified, _ = self.key.unpack_and_verify_archive(data, force_tam_not_required=True)
             archive = ArchiveItem(internal_dict=archive)
             if archive.version != 1:
                 raise Exception('Unknown archive metadata version')

+ 8 - 6
src/borg/crypto/key.py

@@ -224,15 +224,17 @@ class KeyBase:
             output_length=64
         )
 
-    def pack_and_authenticate_metadata(self, metadata_dict, context=b'manifest'):
+    def pack_and_authenticate_metadata(self, metadata_dict, context=b'manifest', salt=None):
+        if salt is None:
+            salt = os.urandom(64)
         metadata_dict = StableDict(metadata_dict)
         tam = metadata_dict['tam'] = StableDict({
             'type': 'HKDF_HMAC_SHA512',
             'hmac': bytes(64),
-            'salt': os.urandom(64),
+            'salt': salt,
         })
         packed = msgpack.packb(metadata_dict, unicode_errors='surrogateescape')
-        tam_key = self._tam_key(tam['salt'], context)
+        tam_key = self._tam_key(salt, context)
         tam['hmac'] = HMAC(tam_key, packed, sha512).digest()
         return msgpack.packb(metadata_dict, unicode_errors='surrogateescape')
 
@@ -298,7 +300,7 @@ class KeyBase:
                 raise ArchiveTAMRequiredError(archive_name)
             else:
                 logger.debug('Archive TAM not found and not required')
-                return unpacked, False
+                return unpacked, False, None
         tam = unpacked.pop(b'tam', None)
         if not isinstance(tam, dict):
             raise ArchiveTAMInvalid()
@@ -308,7 +310,7 @@ class KeyBase:
                 raise TAMUnsupportedSuiteError(repr(tam_type))
             else:
                 logger.debug('Ignoring archive TAM made with unsupported suite, since TAM is not required: %r', tam_type)
-                return unpacked, False
+                return unpacked, False, None
         tam_hmac = tam.get(b'hmac')
         tam_salt = tam.get(b'salt')
         if not isinstance(tam_salt, bytes) or not isinstance(tam_hmac, bytes):
@@ -320,7 +322,7 @@ class KeyBase:
         if not compare_digest(calculated_hmac, tam_hmac):
             raise ArchiveTAMInvalid()
         logger.debug('TAM-verified archive')
-        return unpacked, True
+        return unpacked, True, tam_salt
 
 
 class PlaintextKey(KeyBase):