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 8ac7178
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 0 deletions.
16 changes: 16 additions & 0 deletions docs/usage/general/environment.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,22 @@ General:
caused EROFS. You will need this to make archives from volume shadow copies
in WSL1 (Windows Subsystem for Linux 1).

authenticated_no_key
Work around a lost passphrase or key for an ``authenticated`` mode repository
(these are only authenticated, but not encrypted).
If the key is missing in the repository config, add ``key = anything`` there.

This workaround is **only** 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 you do not use the workaround any more.

Some automatic "answerers" (if set, they automatically answer confirmation questions):
BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=no (or =yes)
For "Warning: Attempting to access a previously unknown unencrypted repository"
Expand Down
2 changes: 2 additions & 0 deletions src/borg/archiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -4227,6 +4227,8 @@ def define_borg_mount(parser):
If you do **not** want to encrypt the contents of your backups, but still
want to detect malicious tampering use ``--encryption authenticated``.
To normally work with ``authenticated`` repos, you will need the passphrase, but
there is an emergency workaround, see ``BORG_WORKAROUNDS=authenticated_no_key`` docs.
If ``BLAKE2b`` is faster than ``SHA-256`` on your hardware, use ``--encryption authenticated-blake2``,
``--encryption repokey-blake2`` or ``--encryption keyfile-blake2``. Note: for remote backups
Expand Down
22 changes: 22 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,10 @@
from .low_level import AES256_CTR_HMAC_SHA256, AES256_CTR_BLAKE2b


# workaround for lost passphrase or key in "authenticated" or "authenticated-blake2" mode
AUTHENTICATED_NO_KEY = 'authenticated_no_key' in workarounds


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

Expand Down Expand Up @@ -253,6 +258,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 +881,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 +919,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 8ac7178

Please sign in to comment.