diff --git a/Vault/Tests/VaultKeygenTests/VaultKeyDeriverParameterPinTests.swift b/Vault/Tests/VaultKeygenTests/VaultKeyDeriverParameterPinTests.swift new file mode 100644 index 000000000..6ed7eed76 --- /dev/null +++ b/Vault/Tests/VaultKeygenTests/VaultKeyDeriverParameterPinTests.swift @@ -0,0 +1,65 @@ +import Foundation +import Testing +import VaultKeygen + +/// Pins the exact KDF chain — algorithm order, key length, iteration +/// counts, variants, and cost factors — for every production deriver. +/// +/// `uniqueAlgorithmIdentifier` encodes all parameters (including nesting +/// via `COMBINATION<...|...>`), so any drift in the chains fails here on +/// every run. This exists because a full pinned-vector test of +/// `Backup.Secure.v1` costs minutes of KDF per run and would rot skipped; +/// the fast pinned vectors in `VaultKeyDeriverTests` prove the shared +/// composition machinery, and this test pins the secure parameters. +struct VaultKeyDeriverParameterPinTests { + @Test + func backupSecureV1_pinsExactKDFChain() { + // The deriver that protects stolen backups. Changing any of these + // parameters is a new keygen VERSION (a new signature), never an + // edit to v1 — existing backups derive with these exact values. + #expect(VaultKeyDeriver.Backup.Secure.v1 + .uniqueAlgorithmIdentifier == + "COMBINATION|HKDF|SCRYPT>") + } + + @Test + func backupFastV1_pinsExactKDFChain() { + #expect(VaultKeyDeriver.Backup.Fast.v1 + .uniqueAlgorithmIdentifier == + "COMBINATION|HKDF|SCRYPT>") + } + + @Test + func itemSecureV1_pinsExactKDFChain() { + #expect(VaultKeyDeriver.Item.Secure.v1 + .uniqueAlgorithmIdentifier == + "COMBINATION|PBKDF2>") + } + + @Test + func itemFastV1_pinsExactKDFChain() { + #expect(VaultKeyDeriver.Item.Fast.v1 + .uniqueAlgorithmIdentifier == + "COMBINATION|PBKDF2>") + } + + @Test + func signatureIDs_areStable() { + // These raw values are persisted in backups and the keychain to + // look up the deriver at decrypt time — they can never change. + #expect(VaultKeyDeriver.Signature.backupSecureV1.rawValue == "vault.keygen.backup.secure.v1") + #expect(VaultKeyDeriver.Signature.backupFastV1.rawValue == "vault.keygen.backup.fast.v1") + #expect(VaultKeyDeriver.Signature.itemSecureV1.rawValue == "vault.keygen.item.secure.v1") + #expect(VaultKeyDeriver.Signature.itemFastV1.rawValue == "vault.keygen.item.fast.v1") + #expect(VaultKeyDeriver.Signature.testing.rawValue == "vault.keygen.testing") + #expect(VaultKeyDeriver.Signature.failing.rawValue == "vault.keygen.failing") + } + + @Test + func lookup_returnsDeriverMatchingEverySignature() { + for signature in VaultKeyDeriver.Signature.allCases { + let deriver = VaultKeyDeriver.lookup(signature: signature) + #expect(deriver.signature == signature) + } + } +}