Keep the OpenPGP primary private key off your daily computer. Use separate subkeys for signing, decryption, and authentication. This limits what an attacker can do after compromising the computer: the primary key is required to certify new subkeys and identity information.
This procedure uses GnuPG on Linux, an encrypted removable volume, and temporary keyrings under /dev/shm. It assumes that you can identify the correct key and storage device. Practise with a disposable key before changing an existing identity.
The examples retain the RSA-8192 primary and RSA-4096 subkeys from the original walkthrough. RSA-8192 is an example configuration, not a requirement for keeping a primary key offline. Replace the example fingerprint with your full fingerprint. Enter passphrases through pinentry; keep them out of scripts and shell history.
Basics · Primary key and subkey roles
Publish the public key so others can verify signatures or encrypt messages to you. Protect the private keys that authorize your operations. Separate their capabilities:
| Capability | Purpose | Key used here |
|---|---|---|
Certify [C] |
Certify user IDs and subkeys; certify other public keys | Primary |
Sign [S] |
Sign messages, files, or Git commits | Signing subkey |
Encrypt [E] |
Receive encrypted data; decrypt it with the private subkey | Encryption subkey |
Authenticate [A] |
Authenticate to services, such as SSH through gpg-agent |
Authentication subkey |
Separate certification from daily use
- Give the primary key the certification capability only.
- Create separate signing, encryption, and authentication subkeys.
- Keep a tested backup of all private keys on encrypted removable media.
- Remove the primary private key from the daily keyring after testing recovery.
- Optionally move the operational subkeys to an OpenPGP smartcard.
Use full fingerprints to identify keys. A keygrip is a separate identifier used by gpg-agent for a private-key component. Inspect both before any deletion:
gpg --list-secret-keys --fingerprint --with-keygrip
Expert · Create the primary key and three subkeys
Save this template as primary_gpg_key_constructor.tpl, replacing the name and email address. Expire-Date: 0 makes this example primary non-expiring; choose an expiry if your key policy requires one. GnuPG requests the passphrase through pinentry.
%echo Generating a RSA key 8192
Key-Type: RSA
Key-Length: 8192
Key-Usage: cert
Name-Real: My Name
Name-Email: something@something
Expire-Date: 0
%commit
%echo done
gpg --batch --generate-key --enable-large-rsa primary_gpg_key_constructor.tpl
gpg --list-secret-keys
The example uses --enable-large-rsa for the 8192-bit key. Confirm that the primary shows [C] only. The output below is illustrative:
sec rsa8192 2023-01-14 [C]
E6B0933DD47E3B2F823334F0A567B3B17C27BF6D
uid [ultimate] My Name <something@something>
gpg --expert --edit-key E6B0933DD47E3B2F823334F0A567B3B17C27BF6D
At the gpg> prompt, add the subkeys:
- Signing:
addkey, RSA (sign only), 4096 bits, then an expiry. - Encryption:
addkey, RSA (encrypt only), 4096 bits, then an expiry. - Authentication:
addkey, RSA (set your own capabilities). DisableSandE, enableA, then choose the size and expiry.
Menu numbers can vary by version. Select by capability and verify the result. Use save to write the changes, then list all fingerprints:
gpg --fingerprint --fingerprint E6B0933DD47E3B2F823334F0A567B3B17C27BF6D
pub rsa8192 2023-01-14 [C]
E6B0 933D D47E 3B2F 8233 34F0 A567 B3B1 7C27 BF6D
uid [ultimate] My Name <something@something>
sub rsa4096 2023-01-14 [S] [expires: 2030-01-12]
61DF 146E F7F6 0971 5E60 46B8 8C75 87C8 6EAC 2F2F
sub rsa4096 2023-01-14 [E] [expires: 2030-01-12]
DBBC AE3F 8166 9FF4 75B7 5F35 51D8 8833 7727 23AD
sub rsa4096 2023-01-14 [A] [expires: 2030-01-12]
F4CF F234 E969 2304 CC58 D55B D13A E6B6 5E8B E723
When replacing an existing primary, you can certify the new key with the old key before retiring it. Explicitly select the old signing key; do not rely on GnuPG’s default selection:
gpg --local-user "$OLD_FINGERPRINT" --sign-key "$NEW_FINGERPRINT"
Intermediate · Choose a setup you can maintain
If you do not need OpenPGP certification, consider age for file encryption and dedicated SSH keys for login. If you keep an OpenPGP primary on your daily computer, protect it with a passphrase, preserve a revocation certificate, and test an encrypted backup. That setup exposes the primary to the daily computer; document that limitation.
Back up and test before removing the primary
Export the private keys before removing the primary or moving subkeys to a card. Later exports may contain references to unavailable keys rather than recoverable private material. A successful export command is not proof of recovery.
The RAM keyrings below reduce persistent writes. /dev/shm may use swap, and removing its files does not guarantee secure erasure. Use a trusted environment with disabled or encrypted swap and no hibernation. A RAM keyring on a connected or compromised computer is not an offline environment.
Expert · Export to encrypted media and test restoration
Run these examples in Bash. Confirm the active GnuPG home first:
gpgconf --list-dirs homedir
Set the destination and fingerprint. Confirm that the expected encrypted device is mounted. mountpoint checks that a mount exists; it does not verify encryption or device identity.
set -euo pipefail
umask 077
ENCRYPTED_MOUNT="/run/media/user/Encrypted_Device"
EXPORT_DIR="$ENCRYPTED_MOUNT/secrets/gpg"
EXPORT_FILENAME="MySelf_Master_MyComment_private_rsa8192"
EXPORT_FINGERPRINT="E6B0933DD47E3B2F823334F0A567B3B17C27BF6D"
if ! mountpoint -q -- "$ENCRYPTED_MOUNT"; then
echo "Encrypted device is not mounted at $ENCRYPTED_MOUNT" >&2
exit 1
fi
install -d -m 0700 -- "$EXPORT_DIR"
Use new filenames for each backup version. Keep the last tested backup until the replacement passes restoration checks. Export the full private key, operational subkeys, public key, and ownertrust:
gpg --armor --output "$EXPORT_DIR/$EXPORT_FILENAME.private-key.sec" \
--export-secret-keys "$EXPORT_FINGERPRINT"
gpg --armor --output "$EXPORT_DIR/$EXPORT_FILENAME.subkeys.sec" \
--export-secret-subkeys "$EXPORT_FINGERPRINT"
gpg --armor --output "$EXPORT_DIR/$EXPORT_FILENAME.pubkey.asc" \
--export "$EXPORT_FINGERPRINT"
gpg --list-secret-keys --fingerprint --with-keygrip "$EXPORT_FINGERPRINT" \
> "$EXPORT_DIR/$EXPORT_FILENAME.keygrip.txt"
gpg --export-ownertrust > "$EXPORT_DIR/gnupg-ownertrust.txt"
Generate revocation certificates while the primary private key is available. Store them securely: anyone who obtains one can publish the revocation. These examples cover the four revocation reasons:
printf '%s\n' y 0 "" y | gpg --no-tty --command-fd 0 --armor \
--output "$EXPORT_DIR/revoke.no-reason.asc" --gen-revoke "$EXPORT_FINGERPRINT"
printf '%s\n' y 1 "" y | gpg --no-tty --command-fd 0 --armor \
--output "$EXPORT_DIR/revoke.compromised.asc" --gen-revoke "$EXPORT_FINGERPRINT"
printf '%s\n' y 2 "" y | gpg --no-tty --command-fd 0 --armor \
--output "$EXPORT_DIR/revoke.superseded.asc" --gen-revoke "$EXPORT_FINGERPRINT"
printf '%s\n' y 3 "" y | gpg --no-tty --command-fd 0 --armor \
--output "$EXPORT_DIR/revoke.no-longer-used.asc" --gen-revoke "$EXPORT_FINGERPRINT"
chmod 0600 -- "$EXPORT_DIR"/*
private-key.sec: primary and subkey private material for full recovery.subkeys.sec: operational private subkeys; primary private material excluded.pubkey.asc: public certificate for distribution.keygrip.txt: identifiers for checking key components.gnupg-ownertrust.txt: local trust assignments; inspect before importing into another keyring.revoke.*.asc: certificates for revoking the primary.
Import the full private backup into a separate temporary keyring:
umask 077
TEST_GNUPGHOME="$(mktemp -d /dev/shm/gnupg-test.XXXXXX)"
chmod 0700 "$TEST_GNUPGHOME"
gpg --homedir "$TEST_GNUPGHOME" \
--import "$EXPORT_DIR/$EXPORT_FILENAME.private-key.sec"
gpg --homedir "$TEST_GNUPGHOME" \
--list-secret-keys --fingerprint --with-keygrip "$EXPORT_FINGERPRINT"
Check the full fingerprint, a usable sec, and all three ssb entries. Test signing, decryption of a previously encrypted test file, and authentication where configured. Also test that the restored primary can certify a disposable test key. Key listings alone do not prove that the private material works.
Stop the temporary agents and remove only the test directory created above:
case "$TEST_GNUPGHOME" in
/dev/shm/gnupg-test.*)
gpgconf --homedir "$TEST_GNUPGHOME" --kill all
rm -rf -- "$TEST_GNUPGHOME"
;;
*) echo "Unexpected test keyring path" >&2; exit 1 ;;
esac
After recovery succeeds, remove only the primary private key from the daily keyring. The quoted ! selects that component. Omitting it also deletes the secret subkeys. Confirm the active home and fingerprint before proceeding. GnuPG command reference.
gpg --delete-secret-keys "${EXPORT_FINGERPRINT}!"
gpg --list-secret-keys "$EXPORT_FINGERPRINT"
sec# rsa8192 2023-01-14 [C]
E6B0933DD47E3B2F823334F0A567B3B17C27BF6D
uid [ultimate] My Name <something@something>
ssb rsa4096 2023-01-14 [S] [expires: 2030-01-12]
ssb rsa4096 2023-01-14 [E] [expires: 2030-01-12]
ssb rsa4096 2023-01-14 [A] [expires: 2030-01-12]
sec# means the primary private key is unavailable in this keyring. It does not prove that no copy remains in another keyring, backup, filesystem snapshot, or recoverable disk data. For new identities, generate the primary in the offline environment and import only operational subkeys onto the daily computer.
Use the primary in a separate environment
Use a trusted offline environment for certification, identity changes, and subkey management. Connect the encrypted backup only for the required operation. Store it separately from the daily computer and keep another tested copy in a separate location.
sec actual primary secret available
sec# primary secret unavailable in this keyring
ssb secret subkey locally available
ssb# secret subkey unavailable
ssb> secret subkey on a smartcard
Expert · Restore, make changes, and test a new backup
Start from the normal GnuPG home, with no GNUPGHOME override. In the trusted offline environment, verify the encrypted mount and import the backup into a temporary home:
umask 077
ENCRYPTED_MOUNT="/run/media/user/Encrypted_Device"
EXPORT_DIR="$ENCRYPTED_MOUNT/secrets/gpg"
EXPORT_FILENAME="MySelf_Master_MyComment_private_rsa8192"
EXPORT_FINGERPRINT="E6B0933DD47E3B2F823334F0A567B3B17C27BF6D"
mountpoint -q -- "$ENCRYPTED_MOUNT" || exit 1
NORMAL_GNUPGHOME="$(gpgconf --list-dirs homedir)"
GNUPGHOME="$(mktemp -d /dev/shm/gnupg.XXXXXX)"
export GNUPGHOME
chmod 0700 "$GNUPGHOME"
gpg --import "$EXPORT_DIR/$EXPORT_FILENAME.private-key.sec"
gpg --import-ownertrust "$EXPORT_DIR/gnupg-ownertrust.txt"
gpg --list-secret-keys --fingerprint --with-keygrip "$EXPORT_FINGERPRINT"
Verify the primary fingerprint and usable private components before editing:
gpg --edit-key "$EXPORT_FINGERPRINT"
Changes to this keyring do not update the backup files. Export a new candidate after changing a passphrase, expiry, user ID, certification, or subkey:
NEW_BACKUP="$EXPORT_DIR/$EXPORT_FILENAME.private-key.NEW.sec"
gpg --armor --output "$NEW_BACKUP" --export-secret-keys "$EXPORT_FINGERPRINT"
chmod 0600 "$NEW_BACKUP"
Restore the candidate into a second temporary keyring and repeat the checks. Refresh and test the subkey and public exports too. Only then archive the previous version and replace the backup set. Publish the updated public certificate where others retrieve it.
case "$GNUPGHOME" in
/dev/shm/gnupg.*)
gpgconf --homedir "$GNUPGHOME" --kill all
rm -rf -- "$GNUPGHOME"
;;
*) echo "Unexpected working keyring path" >&2; exit 1 ;;
esac
unset GNUPGHOME
gpgconf --list-dirs homedir
Confirm that the final path matches NORMAL_GNUPGHOME. On the daily computer, import only the updated public certificate and operational subkeys:
gpg --import "$EXPORT_DIR/$EXPORT_FILENAME.pubkey.asc"
gpg --import "$EXPORT_DIR/$EXPORT_FILENAME.subkeys.sec"
gpg --import-ownertrust "$EXPORT_DIR/gnupg-ownertrust.txt"
Check sec# on the daily computer and test its operational subkeys. Importing private-key.sec there makes the primary private key available again.
Revoke the affected key
Expert · Select the subkey before revoking it
If a subkey is compromised, load the primary in the offline environment and edit the certificate:
gpg --expert --edit-key E6B0933DD47E3B2F823334F0A567B3B17C27BF6D
Use key N to select the affected subkey. Verify the selection marker and fingerprint, run revkey, then save. Export and distribute the updated public certificate. Removing a local key with delkey does not inform others that it is revoked.
For a compromised or retired primary, use the appropriate primary revocation certificate and distribute the revoked public certificate. Keep old encryption private keys if you still need to decrypt historical data, subject to your retention and compromise policy.
Verify the result
The setup is complete when you have a tested full backup, accessible revocation certificates, working operational subkeys, and a daily keyring that cannot use the primary private key. Record the backup locations and restoration procedure. Repeat the recovery checks after changing the keys.




