| 550 | |
| 551 | @classmethod |
| 552 | def create(cls, repository, args, *, other_key=None): |
| 553 | key = cls(repository) |
| 554 | key.repository_id = repository.id |
| 555 | if other_key is not None: |
| 556 | if isinstance(other_key, PlaintextKey): |
| 557 | raise Error("Copying key material from an unencrypted repository is not possible.") |
| 558 | if isinstance(key, AESKeyBase): |
| 559 | # user must use an AEADKeyBase subclass (AEAD modes with session keys) |
| 560 | raise Error("Copying key material to an AES-CTR based mode is insecure and unsupported.") |
| 561 | if not uses_same_id_hash(other_key, key): |
| 562 | raise Error("You must keep the same ID hash (HMAC-SHA256 or BLAKE2b) or deduplication will break.") |
| 563 | if other_key.copy_crypt_key: |
| 564 | # give the user the option to use the same authenticated encryption (AE) key |
| 565 | crypt_key = other_key.crypt_key |
| 566 | else: |
| 567 | # borg transfer re-encrypts all data anyway, thus we can default to a new, random AE key |
| 568 | crypt_key = os.urandom(64) |
| 569 | key.init_from_given_data(crypt_key=crypt_key, id_key=other_key.id_key, chunk_seed=other_key.chunk_seed) |
| 570 | else: |
| 571 | key.init_from_random_data() |
| 572 | passphrase = Passphrase.new(allow_empty=True) |
| 573 | key.init_ciphers() |
| 574 | target = key.get_new_target(args) |
| 575 | key.save(target, passphrase, create=True, algorithm=KEY_ALGORITHMS["argon2"]) |
| 576 | logger.info('Key in "%s" created.' % target) |
| 577 | logger.info("Keep this key safe. Your data will be inaccessible without it.") |
| 578 | return key |
| 579 | |
| 580 | def sanity_check(self, filename, id): |
| 581 | file_id = self.FILE_ID.encode() + b" " |