key: unify keyfile/repokey classes, locate key independent of type byte (#9743)#9767
Conversation
…te (borgbackup#9743) Borg used to read the manifest's key-type byte and then look for the key in exactly one place (keyfile or repokey) depending on the key class that byte selected. As a result every crypto suite was duplicated into a keyfile class and a repokey class that differed only in TYPE, NAME, ARG_NAME and STORAGE. Now key *location* is independent of the type byte: detection tries keyfiles first and repokeys afterwards until a passphrase unlocks a key. The type byte still selects the crypto suite (id hash, MAC, cipher) to instantiate. Where a key is stored (keyfile vs repokey) is therefore a per-key property (self.storage), not a separate class, so a repository may even hold a mix of keyfile- and repo-stored borg keys. With storage decoupled from class identity, the keyfile/repokey class pairs collapse into one class per crypto suite: - modern AEAD: AESOCBKey, CHPOKey, Blake3AESOCBKey, Blake3CHPOKey - legacy borg 1.x (read-only): AESCTRKey, Blake2AESCTRKey There is now exactly one type byte per modern crypto suite (the old separate repokey type bytes 0x11/0x21/0x31/0x41 were removed; borg2 is beta and only needs to read repos it created). identify_key() matches on TYPES_ACCEPTABLE. CLI: --encryption selects only the crypto suite (aes-ocb, chacha20-poly1305, blake3-aes-ocb, blake3-chacha20-poly1305, authenticated*, none); the storage location is chosen with the new --key-location=repokey|keyfile (default repokey). The old combined modes (repokey-aes-ocb etc.) were removed. borg key import also gained --key-location. borg key change-location no longer swaps key classes or rewrites the manifest; it just re-saves the unlocked key at the new location. Keyfile removal (key remove, change-location) now overwrites the keyfile with random data via secure_erase() before unlinking, consistent with save(). borg 1.x legacy read compatibility is preserved (the legacy class merge is a behavior-preserving rename; the legacy type bytes incl. PASSPHRASE stay in TYPES_ACCEPTABLE). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #9767 +/- ##
==========================================
+ Coverage 84.85% 84.91% +0.06%
==========================================
Files 92 92
Lines 15172 15107 -65
Branches 2273 2260 -13
==========================================
- Hits 12874 12828 -46
+ Misses 1593 1581 -12
+ Partials 705 698 -7 ☔ View full report in Codecov by Harness. |
|
🎉 🚀 I'd like to reiterate the idea from #9168 of dropping the former |
|
@PhrozenByte Scope of this PR is only finding the key no matter where it is (keyfile vs. repokey) and decouple the key location from type-bytes in the repository. I put these 2 tickets into the b22 milestone to have a look at them again later. |
The authenticated and authenticated-blake3 modes do not encrypt data, but they still have a real key (id/auth key material) stored as a key blob. That blob can live as a keyfile or as a repokey just like the encrypted modes, so make it configurable instead of always forcing repokey storage. - AuthenticatedKeyBase: set LOCATION_CONFIGURABLE = True so --key-location (at repo-create) and "borg key change-location" apply. - key change-location: only copy sessionid/cipher when present (those are AEAD-only; authenticated keys do not have them). - repo-info: report the key storage location for authenticated keys too, and handle the authenticated-blake3 variant (was only "authenticated"). - repo-create help: stop claiming authenticated* has no keyfile/repokey storage; only "none" truly has no key. - add change-location round-trip tests for authenticated mode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Make key location independent of the manifest key-type byte, and collapse the duplicated keyfile/repokey key classes into one class per crypto suite.
Builds on #9762 (multiple borg keys per repository), which is already merged to master, so this PR contains only the unify commit.
Why
Borg used to read the manifest's key-type byte and then look for the key in exactly one place (keyfile or repokey) depending on the key class that byte selected. As a result every crypto suite was duplicated into a keyfile class and a repokey class that differed only in
TYPE,NAME,ARG_NAMEandSTORAGE.How
self.storage), not a separate class — so a repository may even hold a mix of keyfile- and repo-stored borg keys.AESOCBKey,CHPOKey,Blake3AESOCBKey,Blake3CHPOKeyAESCTRKey,Blake2AESCTRKeyThere is now exactly one type byte per modern suite (the separate repokey type bytes
0x11/0x21/0x31/0x41were removed; borg2 is beta and only needs to read repos it created).identify_key()matches onTYPES_ACCEPTABLE.--encryptionselects only the crypto suite (aes-ocb,chacha20-poly1305,blake3-aes-ocb,blake3-chacha20-poly1305,authenticated*,none); the storage location is chosen with the new--key-location=repokey|keyfile(defaultrepokey). The old combined modes (repokey-aes-ocbetc.) were removed.borg key importalso gained--key-location.borg key change-locationno longer swaps key classes or rewrites the manifest; it just re-saves the unlocked key at the new location.key remove,change-location) now overwrites the keyfile with random data viasecure_erase()before unlinking, consistent withsave().Compatibility
PASSPHRASE) stay inTYPES_ACCEPTABLE.Tests
1633 passed, 82 skipped).change-locationboth directions, mixed keyfile+repokey multi-key repos,--key-locationround-trips.🤖 Generated with Claude Code