Managing OpenPGP Keys

Posted on 30 2026

This is the most important step in the GPG section. The decisions made here, key type, key size, subkey structure, expiry dates, have long-term consequences. A poorly generated key is not something you quietly fix later. It is something you either live with or revoke and start over. Take the time to understand what you are generating before generating it.

Before you start

Two things need to be in place before generating your key.

First, make sure your GPG configuration from the previous section is in place. The settings in gpg.conf affect key generation defaults, and you want those to be correct before you begin.

Second, have your passphrase ready. You will need a seven-word Diceware passphrase to protect the primary key. If you have not generated one yet, do that now using xkcdpass --numwords 7 as covered in the passphrases section. Write it down and keep it somewhere physically secure. You will type it repeatedly during key generation and setup, but once the key is in daily use the agent will handle it.

Key generation strategy

The recommended approach for a personal GPG key in this setup is:

  • A primary key with certify-only capability, kept offline after setup
  • Three subkeys: one for signing, one for encryption, one for authentication
  • A two-year expiry on all keys, renewed annually
  • A revocation certificate generated and stored securely before anything else

The reason for keeping the primary key offline is covered in the introduction to this section. The short version: if a subkey is compromised, you revoke it. If the primary key is compromised, you lose your identity in the web of trust. Keeping it offline significantly reduces the attack surface.

Generating the primary key

GnuPG 2.4.x uses an interactive expert mode for full control over key generation. This takes a few more steps than the simple --gen-key command, but the result is a key structure you actually understand and control:

gpg --expert --full-gen-key

You will be prompted to select a key type. Choose option 11 (ECC (set your own capabilities)):

Please select what kind of key you want:
   (1) RSA and RSA
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
   (9) ECC (sign only)
  (10) ECC (set your own capabilities)
  (11) ECC (set your own capabilities)
  (13) Existing key
  (14) Existing key from card
Your selection? 11

You will then be shown the current capabilities. The goal is a primary key with certify capability only. Toggle off sign if it is currently on:

Possible actions for this ECC key: Sign Certify Authenticate
Current allowed actions: Sign Certify

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? S

The current allowed actions should now show only Certify. Select Q to finish:

Current allowed actions: Certify

Your selection? Q

Select the elliptic curve. Choose Curve 25519 (option 1):

Please select which elliptic curve you want:
   (1) Curve 25519 *default*
   (4) NIST P-384
   (6) Brainpool P-256
Your selection? 1

Set the expiry. Two years is a reasonable balance between security and convenience:

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? 2y

Confirm, then enter your name and email address when prompted. Use the email address associated with the key. Add a comment only if you have a specific reason to, most people leave it blank.

GPG will prompt for your passphrase. Enter your seven-word Diceware passphrase.

Note the key ID from the output. It will look something like 0x0123456789ABCDEF. Set it as an environment variable immediately:

export GPGKEY=0x0123456789ABCDEF

Add this export to your ~/.bashrc so it persists across sessions.

Generating subkeys

With the primary key generated, add the three subkeys. Open the key for editing:

gpg --expert --edit-key $GPGKEY

Signing subkey

At the gpg> prompt:

gpg> addkey

Select option 10 (ECC, set your own capabilities), toggle to signing only, choose Curve 25519, and set a two-year expiry. Enter your passphrase when prompted.

Encryption subkey

gpg> addkey

Select option 12 (ECC, encryption only). Note that encryption keys use a different algorithm under the hood (Curve 25519 / X25519 rather than Ed25519), but GnuPG handles this automatically when you select the encryption-only option. Set a two-year expiry.

Authentication subkey

gpg> addkey

Select option 10 again, toggle to authentication only, choose Curve 25519, set a two-year expiry.

Save and exit

gpg> save

Verify the key structure:

gpg --list-secret-keys --keyid-format 0xlong $GPGKEY

The output should show your primary key (sec) with [C] capability, and three subkeys (ssb) with [S], [E], and [A] capabilities respectively.

Generate a revocation certificate

Do this immediately after key generation, before anything else. A revocation certificate allows you to publicly invalidate your key if it is ever compromised or lost. Without one, a compromised key stays valid in the eyes of anyone who has it until it expires.

gpg --output ~/.gnupg/openpgp-revocs.d/$GPGKEY.rev \
    --gen-revoke $GPGKEY

GPG will ask for a reason. The default (no reason specified) is fine for a pre-generated certificate. Store this file somewhere secure and separate from your private key. An encrypted USB drive is the right place.

Backing up your keys

Back up now, before the key is used for anything. Losing your private key means losing access to everything encrypted with it. This is not recoverable.

Create a backup directory on your encrypted safe storage, then export:

# Export private key
gpg --verbose --export-options backup --armor \
    --output /media/${USER}/SafeStorage/OpenPGP/${GPGKEY}.private.asc \
    --export-secret-keys $GPGKEY

# Export public key
gpg --verbose --export-options backup --armor \
    --output /media/${USER}/SafeStorage/OpenPGP/${GPGKEY}.asc \
    --export $GPGKEY

# Export trust settings
gpg --verbose --export-ownertrust \
    > /media/${USER}/SafeStorage/OpenPGP/OwnerTrust.db

# Copy revocation certificate
cp --archive --verbose \
    ~/.gnupg/openpgp-revocs.d/$GPGKEY.rev \
    /media/${USER}/SafeStorage/OpenPGP/

Verify the backup by checking the exported files are non-empty and readable.

Moving the primary key offline

Once the backup is secure, remove the primary key from your daily-use keyring, leaving only the subkeys. This is the step that makes the offline primary key model actually work.

gpg --export-secret-subkeys $GPGKEY > /tmp/subkeys.gpg
gpg --delete-secret-key $GPGKEY
gpg --import /tmp/subkeys.gpg
rm /tmp/subkeys.gpg

Verify the result:

gpg --list-secret-keys $GPGKEY

The primary key (sec) should now show # after the key ID, indicating it is not available locally. The subkeys (ssb) should remain. This is the correct state for day-to-day use.

Key maintenance

Extending expiry

When a key approaches its expiry date, extend it rather than generating a new one. This preserves your existing trust relationships and signatures.

gpg --expert --edit-key $GPGKEY

Select each key and subkey in turn using key 0, key 1, etc., then use expire to set a new expiry date. Save when done.

Adding a new UID

If you change email addresses and want to add it to your existing key rather than generating a new one:

gpg --edit-key $GPGKEY
gpg> adduid

Follow the prompts, then set the new UID as primary if appropriate, and save.

Revoking a subkey

If a subkey is compromised, revoke it without touching the primary key:

gpg --edit-key $GPGKEY
gpg> key 1
gpg> revkey
gpg> save

Generate a new subkey to replace it and update your key on any key servers you use.

The primary key is your identity. Treat it accordingly. It should come off the encrypted USB drive only when you need to certify a new subkey or someone else’s key, and go back immediately after.