diff options
author | Thomas Waldmann <tw@waldmann-edv.de> | 2023-07-04 00:05:10 +0200 |
---|---|---|
committer | Thomas Waldmann <tw@waldmann-edv.de> | 2023-08-30 01:13:52 +0200 |
commit | 5cd2060345f38f2e0324ab178f847c2f45598b12 (patch) | |
tree | 43bc5031a56e2131ff2e147e21b696eab3c82f08 /src | |
parent | 95b560442284eda3ffae403c3086d549f6e121b8 (diff) |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/borg/archive.py | 8 | ||||
-rw-r--r-- | src/borg/cache.py | 2 | ||||
-rw-r--r-- | src/borg/crypto/key.py | 14 |
3 files changed, 13 insertions, 11 deletions
diff --git a/src/borg/archive.py b/src/borg/archive.py index da9d3661f..964e32398 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -534,7 +534,7 @@ class Archive: cdata = self.repository.get(id) _, data = self.repo_objs.parse(id, cdata) # 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 not in (1, 2): # legacy: still need to read v1 archives raise Exception("Unknown archive metadata version") @@ -1998,7 +1998,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 @@ -2265,7 +2265,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 @@ -2293,7 +2293,7 @@ class ArchiveChecker: archive.item_ptrs = archive_put_items( items_buffer.chunks, repo_objs=self.repo_objs, add_reference=add_reference ) - 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.repo_objs.format(new_archive_id, {}, data) add_reference(new_archive_id, len(data), cdata) diff --git a/src/borg/cache.py b/src/borg/cache.py index a6ec061ed..fc9fd1851 100644 --- a/src/borg/cache.py +++ b/src/borg/cache.py @@ -755,7 +755,7 @@ class LocalCache(CacheStatsMixin): nonlocal processed_item_metadata_chunks csize, data = decrypted_repository.get(archive_id) chunk_idx.add(archive_id, 1, len(data)) - 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 not in (1, 2): # legacy raise Exception("Unknown archive metadata version") diff --git a/src/borg/crypto/key.py b/src/borg/crypto/key.py index aedb19f5e..3fb4818aa 100644 --- a/src/borg/crypto/key.py +++ b/src/borg/crypto/key.py @@ -243,11 +243,13 @@ 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)}) + tam = metadata_dict["tam"] = StableDict({"type": "HKDF_HMAC_SHA512", "hmac": bytes(64), "salt": salt}) packed = msgpack.packb(metadata_dict) - tam_key = self._tam_key(tam["salt"], context) + tam_key = self._tam_key(salt, context) tam["hmac"] = hmac.digest(tam_key, packed, "sha512") return msgpack.packb(metadata_dict) @@ -317,7 +319,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("tam", None) if not isinstance(tam, dict): raise ArchiveTAMInvalid() @@ -329,7 +331,7 @@ class KeyBase: 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("hmac") tam_salt = tam.get("salt") if not isinstance(tam_salt, (bytes, str)) or not isinstance(tam_hmac, (bytes, str)): @@ -343,7 +345,7 @@ class KeyBase: if not hmac.compare_digest(calculated_hmac, tam_hmac): raise ArchiveTAMInvalid() logger.debug("TAM-verified archive") - return unpacked, True + return unpacked, True, tam_salt class PlaintextKey(KeyBase): |