cryptkey rekey¶
Rebuild a profile with a new provider set and/or threshold while preserving the master key — and therefore every key already derived from the profile.
Usage¶
cryptkey rekey [profile] [options]
If profile is omitted, cryptkey uses default.
When to use it¶
- A hardware key died, was lost, or was retired and you want to enroll a replacement.
- You added a new device (laptop, security key, phone) and want to give it access to the profile.
- You want to remove a provider you no longer trust or no longer use.
- You want to change the threshold (e.g., 2-of-3 → 3-of-5).
In every case, output keys derived from the profile (age identities, ed25519 keys, AEAD keys you stored elsewhere) stay the same. Only the set of providers that can unlock the profile changes.
Options¶
| Flag | Description | Default |
|---|---|---|
--threshold N, -t |
New threshold | keep current |
--keep TYPE:ID |
Explicit list of providers to keep (repeatable). Default: keep all that aren't --removed. |
— |
--remove TYPE:ID |
Drop a provider from the new profile (repeatable) | — |
--add TYPE:ID, -a |
Enroll a new provider (repeatable; TYPE alone auto-assigns an ID) |
— |
--no-tui |
Force plain-line prompts (no colors, no inline editing) | implied when stderr isn't a TTY |
--no-backup |
Skip writing <profile>.toml.bak before saving |
false |
--fido2-uv MODE |
FIDO2 user verification for newly enrolled providers | provider default |
--argon-time N / --argon-memory N / --argon-threads N |
Argon2id parameters for newly enrolled passphrase / recovery providers | provider defaults |
--timeout DURATION |
Override the hardware-provider timeout during the unlock phase (e.g. 60s, 2m) |
provider-specific, typically 30s |
Interactive (TUI)¶
Running cryptkey rekey [profile] with no plan-shaping flags (--keep, --remove, --add, --threshold) launches a planning TUI:
- Arrow keys to navigate
spaceto toggle keep / remove on existing providersato add a new provider (type only — id is auto-assigned at enroll time)←/→on the Threshold row to adjust the new thresholdenterto confirm and run the rekeyescorctrl+cto cancel without changes
Once you confirm, the TUI exits and the unlock + enroll phases run in the regular terminal so PIN entry, passphrase entry, and FIDO2 device prompts use the same masked-input UX as cryptkey derive.
If you pass any of the plan-shaping flags, the TUI is skipped — useful for scripts. --no-tui also forces script mode.
Examples¶
Replace a dead FIDO2 key with a new one:
cryptkey rekey personal \
--remove fido2:yubikey-old \
--add fido2:yubikey-new
Add a recovery code to an existing profile (threshold unchanged):
cryptkey rekey personal --add recovery:emergency
Tighten security from 2-of-3 to 3-of-5 by adding two more devices:
cryptkey rekey personal \
--threshold 3 \
--add fido2:laptop \
--add fido2:phone
How it works¶
rekey runs in three phases:
-
Unlock. This is the normal
cryptkey deriveflow against the existing profile: every provider is walked in profile order, you can skip individual ones withesc, and the phase ends when threshold-many shares have been decrypted and the integrity HMAC verifies. Providers used for unlock aren't filtered by--keep/--remove— a provider you're about to remove is still a valid share of the current polynomial, so it can (and often should) participate in unlock. -
Fill in missing kept secrets. The re-split produces a new share value for every kept provider, and each new share has to be encrypted with that provider's secret. If a kept provider wasn't used during the unlock phase (either it came after threshold was met, or you skipped it),
rekeyprompts for it now. Skipping a required kept provider aborts the rekey — you'd have no way to write a valid share for it. -
Enroll. Each
--addprovider runs through its full enrollment flow (FIDO2 touch + create credential, new passphrase, etc.). -
Re-split and write. A fresh Shamir polynomial of degree
(t' - 1)is generated with K as its constant term. Every provider — kept and added — gets a new share encrypted with its own secret. The integrity HMAC is recomputed. The original profile is copied to<profile>.toml.bak(unless--no-backup), and the new profile is atomically written via temp-file + rename.
The existing output_salt is preserved verbatim, which is why output keys derived from the same --use continue to match.
Interaction count¶
For a typical "replace one dead key" rekey on a 5-of-3 profile keeping 4 of the original 5 providers (the 5th is the dead one being removed) and adding 1 new provider:
| Phase | Interactions |
|---|---|
| Unlock (until threshold reached) | 3 |
| Fill-in kept providers not used during unlock | 1 |
| Enroll (added providers) | 1 |
| Total | 5 |
The exact split between phases 1 and 2 depends on which providers you choose during unlock — if kept providers happen to be what unlocks the profile, the fill-in phase is empty.
Safety¶
- The original profile is never modified in place. The new profile is written to a temp file, fsynced, and renamed. A
.bakof the previous profile is written first by default. - If unlock or enrollment fails, no write occurs. The original profile is untouched.
- The integrity HMAC is recomputed against the recovered master key, so a tampered profile that somehow survives the unlock phase still won't write a new profile.
- New hardware credentials (FIDO2 / passkey) are created on the device the moment you enroll them. If a later step fails, those credentials remain on the device but unused — same caveat as
init.
Recovering from a failed rekey¶
If the new profile was written but you suspect it's wrong (typo on a passphrase, wrong device picked, etc.), restore the previous one:
mv ~/.config/cryptkey/myprofile.toml.bak ~/.config/cryptkey/myprofile.toml
The backup is a literal copy of the pre-rekey profile, so the original providers continue to unlock it.