PGP key/subkey management
Contents
Creating the keyset
The strategy: create a primary secret key which is only used to issue and certify subkeys, which are actually used for encryption/signing/authorization. The Debian wiki has a good rundown on why this is desirable.
Create temporary working directory
Any time we’re working with the primary secret key, we’ll do so by setting GPG’s home directory to an ephemeral working directory (deleted on reboot):
export GNUPGHOME=$(mktemp -d -t)
Creating the secret key
gpg --expert --full-gen-key
Following the prompts:
- Select key type
RSA (set your own capabilities)
- Select allowed actions
- Disable
Sign
andEncrypt
Certify
should be the only allowed capability
- Disable
- Select keysize
4096
bits - Select key expiration
0 = key does not expire
. - Enter user ID (name and email)
- Choose a strong passphrase (and back it up securely if you won’t remember it)
Creating subkeys
Generate a subkey each for the signing
, encryption
, and authentication
actions:
gpg --expert --edit-key jon@jonwebb.dev
Once in the editing prompt, add 3 subkeys:
gpg> addkey
- Signing key
- Select key type
RSA (sign only)
- Select key type
- Encryption key
- Select key type
RSA (encrypt only)
- Select key type
- Authentication key
- Select key type
RSA (set your own capabilities)
- Disable
Sign
andEncrypt
- Enable
Authenticate
, which should be the only allowed capability
- Disable
- Select key type
For each subkey:
- Select keysize
4096
bits - Select key expiration
1y
Finally, write the subkeys to the main key:
gpg> save
Validate the generated keys:
gpg -K
/home/jon/.gnupg/pubring.kbx
----------------------------
sec rsa4096 2023-01-05 [C]
D35F9AA116CB89015A7A44EF4B540D953C59993B
uid [ultimate] Jon Fake <jon@jonwebb.dev>
ssb rsa4096 2023-01-05 [S] [expires: 2024-01-05]
ssb rsa4096 2023-01-05 [E] [expires: 2024-01-05]
ssb rsa4096 2023-01-05 [A] [expires: 2024-01-05]
Here’s what the acronyms stand for:
sec
- Secret key
uid
- User ID
ssb
- Secret subkey
Backup
Get a semi-reliable form of digital media, and backup the following files (maybe > 1, in different locations):
Export & publish public key
gpg -o pubkey.asc -a --export jon@jonwebb.dev
This is the only one that’s ok to share. Put it on your website , or publish it to a keyserver if desired.
Export secret key + subkeys
gpg -o masterkey.asc -a --export-secret-keys jon@jonwebb.dev
This would be pretty bad to share. If someone steals it, the only thing between you and crypto hell is your passphrase.
Export subkeys (w/o secret keys)
gpg -o subkeys.asc -a --export-secret-subkeys jon@jonwebb.dev
This would be slightly less bad to share, since you still store the secret key required to create new keys, and you can revoke compromised subkeys.
Export revokation certificate
Store this in an additional location in the event the secret key is lost. You should probably print it to paper.
gpg -o revoke.asc --gen-revoke jon@jonwebb.dev
This would be annoying to share, since it could allow anyone to revoke your keys, necessitating a lot of work and an embarrasing blog post.
Still paranoid? Use paper.
Paper lasts hundreds of years , but the earliest known USB drive was created mere decades ago.
Nuke the working directory
gpg --delete-secret-key jon@jonwebb.dev
sudo reboot
Import working subkeys (“laptop” keypair)
Get your backup media and import the subkeys (the export without the secret key):
gpg --import subkeys.asc
gpg --edit-key jon@jonwebb.dev trust quit # trust ultimately when prompted
Validate the imported keys:
gpg -K
sec# rsa4096 2023-01-05 [C]
D35F9AA116CB89015A7A44EF4B540D953C59993B
uid [ultimate] Jon Fake <jon@jonwebb.dev>
ssb rsa4096 2023-01-05 [S] [expires: 2024-01-05]
ssb rsa4096 2023-01-05 [E] [expires: 2024-01-05]
ssb rsa4096 2023-01-05 [E] [expires: 2024-01-05]
The hash at the end of sec#
means that the master, certifying key is not present. Success!
Now yeet your backup media back to the nether realm.
Renewing subkeys
Every year, your subkeys will expire, so they will have to be renewed with the secret key.
Create temporary working directory
export GNUPGHOME=$(mktemp -d -t)
Import & edit the secret key
Get your backup media and import the main secret key:
gpg --import masterkey.asc
gpg --edit-key jon@jonwebb.dev
In the GPG prompt, select each subkey (*
appears next to selected keys):
gpg> key 1
gpg> key 2
gpg> key 3
Set a new expiration for the subkeys, and save:
gpg> expire
gpg> save
Backup public key:
gpg -o pubkey-$(date +%F).asc -a --export jon@jonwebb.dev # publish to your website/keyservers!
Now yeet your backup media back to the nether realm.
Nuke the working directory
gpg --delete-secret-key jon@jonwebb.dev
sudo reboot
Use the renewed subkeys
For systems that already possess subkeys, it’s only required to update the public key:
gpg --import pubkey-${BACKUP_DATE}.asc
Revoking the secret key
In the event your secret key is compromised or lost, it can be revoked using the certificate generated earlier.
gpg --import revoke.asc
gpg -o pubkey-$(date +%F).asc -a --export jon@jonwebb.dev # publish to your website/keyservers!
Revoking a subkey
In the event that one or more subkeys are compromised, they can be revoked individually.
Create temporary working directory
export GNUPGHOME=$(mktemp -d -t)
Import & edit the secret key
Get your backup media and import the main secret key:
gpg --import masterkey.asc
gpg --edit-key jon@jonwebb.dev
In the GPG prompt, select one or multiple subkeys to revoke (*
appears next to selected keys):
gpg> key 1
gpg> key 2
gpg> key 3
Generate a revokation certificate for the subkeys, and save:
gpg> revkey
gpg> save
Now generate new subkeys as needed.
Backup public key:
gpg -o pubkey-$(date +%F).asc -a --export jon@jonwebb.dev # publish to your website/keyservers!
Now yeet your backup media back to the nether realm.
Nuke the working directory
gpg --delete-secret-key jon@jonwebb.dev
sudo reboot
To generate new subkeys, go back to steps
Side quest: backing secret key to ✨ paper ✨
paperkey allows creating a copy of only the actually secret portions of the secret key, which, combined with the public key (from a backup, your website, or a keyserver) can be used to restore the entire key.
Storing only the actually secret portions of the key means it can be reasonably backed up to paper/QR.
Create secret key paper backup
Using paperkey
:
gpg --export-secret-key jon@jonwebb.dev | paperkey --output masterkey-paper.asc
Create QR code backup
Using paperkey
and
qrencode
(generating multiple QR codes due to file size):
gpg --export-secret-key jon@jonwebb.dev | paperkey --output-type raw | qrencode --8bit -Sv 40 --o masterkey-paper.qr.png
Note: zbarimg expects data stored in multiple codes to be in the same image. If the QR codes are stored in multiple files, they can be concatenated:
convert masterkey-paper.qr-01.png masterkey-paper.qr-02.png +append master-key-paper.qr.png
Decode QR code backup with
zbarimg
zbarigm --raw -Sbinary | paperkey --pubring public-key.asc | gpg --import
See the Arch wiki for additional useful instructions.