|
@@ -119,9 +119,7 @@ def key_argument_names():
|
|
|
def identify_key(manifest_data):
|
|
|
key_type = manifest_data[0]
|
|
|
if key_type == PassphraseKey.TYPE:
|
|
|
- # we just dispatch to repokey mode and assume the passphrase was migrated to a repokey.
|
|
|
- # see also comment in PassphraseKey class.
|
|
|
- return RepoKey
|
|
|
+ return RepoKey # see comment in PassphraseKey class.
|
|
|
|
|
|
for key in AVAILABLE_KEY_TYPES:
|
|
|
if key.TYPE == key_type:
|
|
@@ -327,8 +325,7 @@ class ID_BLAKE2b_256:
|
|
|
def id_hash(self, data):
|
|
|
return blake2b_256(self.id_key, data)
|
|
|
|
|
|
- def init_from_random_data(self, data=None):
|
|
|
- assert data is None # PassphraseKey is the only caller using *data*
|
|
|
+ def init_from_random_data(self):
|
|
|
super().init_from_random_data()
|
|
|
self.enc_hmac_key = random_blake2b_256_key()
|
|
|
self.id_key = random_blake2b_256_key()
|
|
@@ -347,8 +344,6 @@ class ID_HMAC_SHA_256:
|
|
|
|
|
|
class AESKeyBase(KeyBase):
|
|
|
"""
|
|
|
- Common base class shared by KeyfileKey and PassphraseKey
|
|
|
-
|
|
|
Chunks are encrypted using 256bit AES in Counter Mode (CTR)
|
|
|
|
|
|
Payload layout: TYPE(1) + HMAC(32) + NONCE(8) + CIPHERTEXT
|
|
@@ -386,9 +381,8 @@ class AESKeyBase(KeyBase):
|
|
|
self.assert_id(id, data)
|
|
|
return data
|
|
|
|
|
|
- def init_from_random_data(self, data=None):
|
|
|
- if data is None:
|
|
|
- data = os.urandom(100)
|
|
|
+ def init_from_random_data(self):
|
|
|
+ data = os.urandom(100)
|
|
|
self.enc_key = data[0:32]
|
|
|
self.enc_hmac_key = data[32:64]
|
|
|
self.id_key = data[64:96]
|
|
@@ -523,59 +517,13 @@ class Passphrase(str):
|
|
|
return pbkdf2_hmac('sha256', self.encode('utf-8'), salt, iterations, length)
|
|
|
|
|
|
|
|
|
-class PassphraseKey(ID_HMAC_SHA_256, AESKeyBase):
|
|
|
- # This mode was killed in borg 1.0, see: https://github.com/borgbackup/borg/issues/97
|
|
|
- # Reasons:
|
|
|
- # - you can never ever change your passphrase for existing repos.
|
|
|
- # - you can never ever use a different iterations count for existing repos.
|
|
|
- # "Killed" means:
|
|
|
- # - there is no automatic dispatch to this class via type byte
|
|
|
- # - --encryption=passphrase is an invalid argument now
|
|
|
- # This class is kept for a while to support migration from passphrase to repokey mode.
|
|
|
+class PassphraseKey:
|
|
|
+ # this is only a stub, repos with this mode could not be created any more since borg 1.0, see #97.
|
|
|
+ # in borg 1.3 all of its code and also the "borg key migrate-to-repokey" command was removed.
|
|
|
+ # if you still need to, you can use "borg key migrate-to-repokey" with borg 1.0, 1.1 and 1.2.
|
|
|
+ # Nowadays, we just dispatch this to RepoKey and assume the passphrase was migrated to a repokey.
|
|
|
TYPE = 0x01
|
|
|
NAME = 'passphrase'
|
|
|
- ARG_NAME = None
|
|
|
- STORAGE = KeyBlobStorage.NO_STORAGE
|
|
|
-
|
|
|
- iterations = 100000 # must not be changed ever!
|
|
|
-
|
|
|
- @classmethod
|
|
|
- def create(cls, repository, args):
|
|
|
- key = cls(repository)
|
|
|
- logger.warning('WARNING: "passphrase" mode is unsupported since borg 1.0.')
|
|
|
- passphrase = Passphrase.new(allow_empty=False)
|
|
|
- key.init(repository, passphrase)
|
|
|
- return key
|
|
|
-
|
|
|
- @classmethod
|
|
|
- def detect(cls, repository, manifest_data):
|
|
|
- prompt = 'Enter passphrase for %s: ' % repository._location.canonical_path()
|
|
|
- key = cls(repository)
|
|
|
- passphrase = Passphrase.env_passphrase()
|
|
|
- if passphrase is None:
|
|
|
- passphrase = Passphrase.getpass(prompt)
|
|
|
- for retry in range(1, 3):
|
|
|
- key.init(repository, passphrase)
|
|
|
- try:
|
|
|
- key.decrypt(None, manifest_data)
|
|
|
- key.init_ciphers(manifest_data)
|
|
|
- key._passphrase = passphrase
|
|
|
- return key
|
|
|
- except IntegrityError:
|
|
|
- passphrase = Passphrase.getpass(prompt)
|
|
|
- else:
|
|
|
- raise PasswordRetriesExceeded
|
|
|
-
|
|
|
- def change_passphrase(self):
|
|
|
- class ImmutablePassphraseError(Error):
|
|
|
- """The passphrase for this encryption key type can't be changed."""
|
|
|
-
|
|
|
- raise ImmutablePassphraseError
|
|
|
-
|
|
|
- def init(self, repository, passphrase):
|
|
|
- self.init_from_random_data(passphrase.kdf(repository.id, self.iterations, 100))
|
|
|
- self.init_ciphers()
|
|
|
- self.tam_required = False
|
|
|
|
|
|
|
|
|
class KeyfileKeyBase(AESKeyBase):
|
|
@@ -888,7 +836,6 @@ class Blake2AuthenticatedKey(ID_BLAKE2b_256, AuthenticatedKeyBase):
|
|
|
|
|
|
AVAILABLE_KEY_TYPES = (
|
|
|
PlaintextKey,
|
|
|
- PassphraseKey,
|
|
|
KeyfileKey, RepoKey, AuthenticatedKey,
|
|
|
Blake2KeyfileKey, Blake2RepoKey, Blake2AuthenticatedKey,
|
|
|
)
|