mirror of https://github.com/borgbackup/borg.git
rcreate: always use argon2 kdf for new repos, fixes #6820
this way, we can remove the legacy pbkdf2 key code in next release.
This commit is contained in:
parent
ef24dafb15
commit
eabad3e3b7
|
@ -303,7 +303,6 @@ class build_man(Command):
|
|||
|
||||
'key_change-passphrase': 'key',
|
||||
'key_change-location': 'key',
|
||||
'key_change-algorithm': 'key',
|
||||
'key_export': 'key',
|
||||
'key_import': 'key',
|
||||
'key_migrate-to-repokey': 'key',
|
||||
|
|
|
@ -4380,22 +4380,6 @@ class Archiver:
|
|||
If you do **not** want to encrypt the contents of your backups, but still want to detect
|
||||
malicious tampering use an `authenticated` mode. It's like `repokey` minus encryption.
|
||||
|
||||
Key derivation functions
|
||||
++++++++++++++++++++++++
|
||||
|
||||
- ``--key-algorithm argon2`` is the default and is recommended.
|
||||
The key encryption key is derived from your passphrase via argon2-id.
|
||||
Argon2 is considered more modern and secure than pbkdf2.
|
||||
|
||||
Our implementation of argon2-based key algorithm follows the cryptographic best practices:
|
||||
|
||||
- It derives two separate keys from your passphrase: one to encrypt your key and another one
|
||||
to sign it. ``--key-algorithm pbkdf2`` uses the same key for both.
|
||||
|
||||
- It uses encrypt-then-mac instead of encrypt-and-mac used by ``--key-algorithm pbkdf2``
|
||||
|
||||
Neither is inherently linked to the key derivation function, but since we were going
|
||||
to break backwards compatibility anyway we took the opportunity to fix all 3 issues at once.
|
||||
""")
|
||||
subparser = subparsers.add_parser('rcreate', parents=[common_parser], add_help=False,
|
||||
description=self.do_rcreate.__doc__, epilog=rcreate_epilog,
|
||||
|
@ -4418,8 +4402,6 @@ class Archiver:
|
|||
help='Set storage quota of the new repository (e.g. 5G, 1.5T). Default: no quota.')
|
||||
subparser.add_argument('--make-parent-dirs', dest='make_parent_dirs', action='store_true',
|
||||
help='create the parent directories of the repository directory, if they are missing.')
|
||||
subparser.add_argument('--key-algorithm', dest='key_algorithm', default='argon2', choices=list(KEY_ALGORITHMS),
|
||||
help='the algorithm we use to derive a key encryption key from your passphrase. Default: argon2')
|
||||
|
||||
# borg key
|
||||
subparser = subparsers.add_parser('key', parents=[mid_common_parser], add_help=False,
|
||||
|
@ -4544,46 +4526,6 @@ class Archiver:
|
|||
subparser.add_argument('--keep', dest='keep', action='store_true',
|
||||
help='keep the key also at the current location (default: remove it)')
|
||||
|
||||
change_algorithm_epilog = process_epilog("""
|
||||
Change the algorithm we use to encrypt and authenticate the borg key.
|
||||
|
||||
Important: In a `repokey` mode (e.g. repokey-blake2) all users share the same key.
|
||||
In this mode upgrading to `argon2` will make it impossible to access the repo for users who use an old version of borg.
|
||||
We recommend upgrading to the latest stable version.
|
||||
|
||||
Important: In a `keyfile` mode (e.g. keyfile-blake2) each user has their own key (in ``~/.config/borg/keys``).
|
||||
In this mode this command will only change the key used by the current user.
|
||||
If you want to upgrade to `argon2` to strengthen security, you will have to upgrade each user's key individually.
|
||||
|
||||
Your repository is encrypted and authenticated with a key that is randomly generated by ``borg init``.
|
||||
The key is encrypted and authenticated with your passphrase.
|
||||
|
||||
We currently support two choices:
|
||||
|
||||
1. argon2 - recommended. This algorithm is used by default when initialising a new repository.
|
||||
The key encryption key is derived from your passphrase via argon2-id.
|
||||
Argon2 is considered more modern and secure than pbkdf2.
|
||||
2. pbkdf2 - the legacy algorithm. Use this if you want to access your repo via old versions of borg.
|
||||
The key encryption key is derived from your passphrase via PBKDF2-HMAC-SHA256.
|
||||
|
||||
Examples::
|
||||
|
||||
# Upgrade an existing key to argon2
|
||||
borg key change-algorithm /path/to/repo argon2
|
||||
# Downgrade to pbkdf2 - use this if upgrading borg is not an option
|
||||
borg key change-algorithm /path/to/repo pbkdf2
|
||||
|
||||
|
||||
""")
|
||||
subparser = key_parsers.add_parser('change-algorithm', parents=[common_parser], add_help=False,
|
||||
description=self.do_change_algorithm.__doc__,
|
||||
epilog=change_algorithm_epilog,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
help='change key algorithm')
|
||||
subparser.set_defaults(func=self.do_change_algorithm)
|
||||
subparser.add_argument('algorithm', metavar='ALGORITHM', choices=list(KEY_ALGORITHMS),
|
||||
help='select key algorithm')
|
||||
|
||||
# borg list
|
||||
list_epilog = process_epilog("""
|
||||
This command lists the contents of an archive.
|
||||
|
|
|
@ -620,7 +620,7 @@ class FlexiKey:
|
|||
passphrase = Passphrase.new(allow_empty=True)
|
||||
key.init_ciphers()
|
||||
target = key.get_new_target(args)
|
||||
key.save(target, passphrase, create=True, algorithm=KEY_ALGORITHMS[args.key_algorithm])
|
||||
key.save(target, passphrase, create=True, algorithm=KEY_ALGORITHMS['argon2'])
|
||||
logger.info('Key in "%s" created.' % target)
|
||||
logger.info('Keep this key safe. Your data will be inaccessible without it.')
|
||||
return key
|
||||
|
|
|
@ -613,7 +613,7 @@ cdef class CHACHA20_POLY1305(_AEAD_BASE):
|
|||
super().__init__(key, iv=iv, header_len=header_len, aad_offset=aad_offset)
|
||||
|
||||
|
||||
cdef class AES:
|
||||
cdef class AES: # legacy
|
||||
"""A thin wrapper around the OpenSSL EVP cipher API - for legacy code, like key file encryption"""
|
||||
cdef CIPHER cipher
|
||||
cdef EVP_CIPHER_CTX *ctx
|
||||
|
|
|
@ -3472,53 +3472,24 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02
|
|||
key = msgpack.unpackb(a2b_base64(repository.load_key()))
|
||||
assert key['algorithm'] == 'argon2 chacha20-poly1305'
|
||||
|
||||
def test_init_with_explicit_key_algorithm(self):
|
||||
"""https://github.com/borgbackup/borg/issues/747#issuecomment-1076160401"""
|
||||
self.cmd(f'--repo={self.repository_location}', 'rcreate', RK_ENCRYPTION, '--key-algorithm=pbkdf2')
|
||||
with Repository(self.repository_path) as repository:
|
||||
key = msgpack.unpackb(a2b_base64(repository.load_key()))
|
||||
assert key['algorithm'] == 'sha256'
|
||||
|
||||
def verify_change_passphrase_does_not_change_algorithm(self, given_algorithm, expected_algorithm):
|
||||
self.cmd(f'--repo={self.repository_location}', 'rcreate', RK_ENCRYPTION, '--key-algorithm', given_algorithm)
|
||||
def test_change_passphrase_does_not_change_algorithm_argon2(self):
|
||||
self.cmd(f'--repo={self.repository_location}', 'rcreate', RK_ENCRYPTION)
|
||||
os.environ['BORG_NEW_PASSPHRASE'] = 'newpassphrase'
|
||||
|
||||
self.cmd(f'--repo={self.repository_location}', 'key', 'change-passphrase')
|
||||
|
||||
with Repository(self.repository_path) as repository:
|
||||
key = msgpack.unpackb(a2b_base64(repository.load_key()))
|
||||
assert key['algorithm'] == expected_algorithm
|
||||
assert key['algorithm'] == 'argon2 chacha20-poly1305'
|
||||
|
||||
def test_change_passphrase_does_not_change_algorithm_argon2(self):
|
||||
self.verify_change_passphrase_does_not_change_algorithm('argon2', 'argon2 chacha20-poly1305')
|
||||
|
||||
def test_change_passphrase_does_not_change_algorithm_pbkdf2(self):
|
||||
self.verify_change_passphrase_does_not_change_algorithm('pbkdf2', 'sha256')
|
||||
|
||||
def verify_change_location_does_not_change_algorithm(self, given_algorithm, expected_algorithm):
|
||||
self.cmd(f'--repo={self.repository_location}', 'rcreate', KF_ENCRYPTION, '--key-algorithm', given_algorithm)
|
||||
def test_change_location_does_not_change_algorithm_argon2(self):
|
||||
self.cmd(f'--repo={self.repository_location}', 'rcreate', KF_ENCRYPTION)
|
||||
|
||||
self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'repokey')
|
||||
|
||||
with Repository(self.repository_path) as repository:
|
||||
key = msgpack.unpackb(a2b_base64(repository.load_key()))
|
||||
assert key['algorithm'] == expected_algorithm
|
||||
|
||||
def test_change_location_does_not_change_algorithm_argon2(self):
|
||||
self.verify_change_location_does_not_change_algorithm('argon2', 'argon2 chacha20-poly1305')
|
||||
|
||||
def test_change_location_does_not_change_algorithm_pbkdf2(self):
|
||||
self.verify_change_location_does_not_change_algorithm('pbkdf2', 'sha256')
|
||||
|
||||
def test_key_change_algorithm(self):
|
||||
self.cmd(f'--repo={self.repository_location}', 'rcreate', RK_ENCRYPTION, '--key-algorithm=pbkdf2')
|
||||
|
||||
self.cmd(f'--repo={self.repository_location}', 'key', 'change-algorithm', 'argon2')
|
||||
|
||||
with Repository(self.repository_path) as repository:
|
||||
_, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK)
|
||||
assert key._encrypted_key_algorithm == 'argon2 chacha20-poly1305'
|
||||
self.cmd(f'--repo={self.repository_location}', 'rinfo')
|
||||
assert key['algorithm'] == 'argon2 chacha20-poly1305'
|
||||
|
||||
|
||||
@unittest.skipUnless('binary' in BORG_EXES, 'no borg.exe available')
|
||||
|
|
|
@ -396,8 +396,7 @@ def test_decrypt_key_file_v2_is_unsupported():
|
|||
key.decrypt_key_file(encrypted, "hello, pass phrase")
|
||||
|
||||
|
||||
@pytest.mark.parametrize('cli_argument, expected_algorithm', KEY_ALGORITHMS.items())
|
||||
def test_key_file_roundtrip(monkeypatch, cli_argument, expected_algorithm):
|
||||
def test_key_file_roundtrip(monkeypatch):
|
||||
def to_dict(key):
|
||||
extract = 'repository_id', 'enc_key', 'enc_hmac_key', 'id_key', 'chunk_seed'
|
||||
return {a: getattr(key, a) for a in extract}
|
||||
|
@ -405,10 +404,10 @@ def test_key_file_roundtrip(monkeypatch, cli_argument, expected_algorithm):
|
|||
repository = MagicMock(id=b'repository_id')
|
||||
monkeypatch.setenv('BORG_PASSPHRASE', "hello, pass phrase")
|
||||
|
||||
save_me = AESOCBRepoKey.create(repository, args=MagicMock(key_algorithm=cli_argument))
|
||||
save_me = AESOCBRepoKey.create(repository, args=MagicMock(key_algorithm='argon2'))
|
||||
saved = repository.save_key.call_args.args[0]
|
||||
repository.load_key.return_value = saved
|
||||
load_me = AESOCBRepoKey.detect(repository, manifest_data=None)
|
||||
|
||||
assert to_dict(load_me) == to_dict(save_me)
|
||||
assert msgpack.unpackb(a2b_base64(saved))['algorithm'] == expected_algorithm
|
||||
assert msgpack.unpackb(a2b_base64(saved))['algorithm'] == KEY_ALGORITHMS['argon2']
|
||||
|
|
Loading…
Reference in New Issue