Skip to content

Commit

Permalink
BORG_WORKAROUNDS=authenticated_no_key to extract from authenticated r…
Browse files Browse the repository at this point in the history
…epos without key, fixes #7700
  • Loading branch information
ThomasWaldmann committed Jul 3, 2023
1 parent 6b0dc53 commit 5444452
Showing 1 changed file with 33 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/borg/crypto/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from ..helpers import bin_to_hex
from ..helpers import prepare_subprocess_env
from ..helpers import msgpack
from ..helpers import workarounds
from ..item import Key, EncryptedKey
from ..platform import SaveFile

Expand All @@ -32,6 +33,21 @@
from .low_level import AES256_CTR_HMAC_SHA256, AES256_CTR_BLAKE2b


# "authenticated" or "authenticated-blake2" mode: user lost key or passphrase!
# usually (with encrypted repos) this means "game over",
# but for not-encrypted, just "authenticated" repos, we can still extract data,
# if we do not try to check the authentication (which we can't, because we lost
# the key or passphrase).
# if the key is missing in the repository config, add "key = anything" there.
# this workaround is **only** intended for emergencies and **only** to extract data
# from an affected repository (read-only access):
# BORG_WORKAROUNDS=authenticated_no_key borg extract repo::archive
# after you have extracted all data you need, you MUST delete the repository:
# BORG_WORKAROUNDS=authenticated_no_key borg delete repo
# Now you can init a fresh repo. Make sure NOT to use the workaround any more.
AUTHENTICATED_NO_KEY = 'authenticated_no_key' in workarounds


class NoPassphraseFailure(Error):
"""can not acquire a passphrase: {}"""

Expand Down Expand Up @@ -253,6 +269,8 @@ def unpack_and_verify_manifest(self, data, force_tam_not_required=False):
offset = data.index(tam_hmac)
data[offset:offset + 64] = bytes(64)
tam_key = self._tam_key(tam_salt, context=b'manifest')
if AUTHENTICATED_NO_KEY:
return unpacked, True # True is a lie.
calculated_hmac = hmac.digest(tam_key, data, 'sha512')
if not hmac.compare_digest(calculated_hmac, tam_hmac):
raise TAMInvalid()
Expand Down Expand Up @@ -874,6 +892,19 @@ class AuthenticatedKeyBase(RepoKey):
# It's only authenticated, not encrypted.
logically_encrypted = False

def _load(self, key_data, passphrase):
if AUTHENTICATED_NO_KEY:
# fake _load if we have no key or passphrase
NOPE = bytes(32) # 256 bit all-zero
self.repository_id = NOPE
self.enc_key = NOPE
self.enc_hmac_key = NOPE
self.id_key = NOPE
self.chunk_seed = 0
self.tam_required = False
return True
return super()._load(key_data, passphrase)

def load(self, target, passphrase):
success = super().load(target, passphrase)
self.logically_encrypted = False
Expand All @@ -899,6 +930,8 @@ def decrypt(self, id, data, decompress=True):
if not decompress:
return payload
data = self.decompress(payload)
if AUTHENTICATED_NO_KEY:
return data
self.assert_id(id, data)
return data

Expand Down

0 comments on commit 5444452

Please sign in to comment.