Managing PGP keys
Table of Contents
Goal
My motiviation for digging into proper PGP key management is that I am
going to start using Password Store (a.k.a. pass
) for password
management. It uses PGP to encrypt secrets, so I need to make sure I
am able to manage my keys properly lest I lose access to all my
passwords! I already lost an old key I created a few years ago and I
don’t want that to happen again.
I don’t really use or intend to use PGP-signed messages for communication, but being ready to be able to do so is an added bonus.
My setup is as follows:
- two laptops running Linux
- Both are used as “main” machines. I like to switch working on either of them every few weeks. It forces me to organize my data in a way that does not rely on a single point of failure. Plus it’s fun trying out different Linux distros :)
- an Android device
- for the Android client of Password Store with OpenKeychain
Recommended reading
Generate new private/public key pair
First make sure you have GPG version 2 installed. On some Linux
distributions, the gpg
command is for version 1 and a separate
gpg2
command for version 2. On my machine only version 2 is
installed and it is available via the gpg
command.
$ gpg --version gpg (GnuPG) 2.2.10 libgcrypt 1.8.3 ...
The following command takes you through multiple steps to generate a new private/public key pair.
- Choose the 1st option (RSA and RSA) for the kind of key
- A key size of 2048 or 4096 is recommended (the bigger the better)
- I chose 2048 here because I plan to get a YubiKey NEO in the future and it can only import keys of size 2048.
- It is good practice to choose an expiry date of less than 2 years
- An expiry is important especially for cases where you’ve lost your private key or forgot your passphrase. Without an expiry, your public keys remain valid forever and anyone who had your old keys will continue to use them.
- Having an expiry also forces you to refresh your memory on how to manage your keys, perform any updates or cleanups needed, and review your backups.
- Your email will be used as the ID of they key
- If you have other email addresses (e.g. work email), you can add them as alternative IDs afterwards. This is the recommended way of relating multiple email addresses to a PGP key, instead of creating separate keys for each email address.
Not shown in the command prompts below is the entry of a strong and unique passphrase. Note the deliberate use of the term “passphrase” instead of “password”, this is to emphasize the importance of using multiple words and not just one. Make sure it is something you will be able to commit to memory and retain it for a long time. This passphrase is your last line of defense when your private key is compromised.
$ gpg --full-generate-key Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) Your selection? 1 RSA keys may be between 1024 and 2048 bits long. What keysize do you want? (2048) 2048 Requested keysize is 2048 bits 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? (0) 8m Key expires at Mon 24 Jun 2019 02:43:57 PM +08 Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: John Louis Del Rosario Email address: john@delrosario.org Comment: You selected this USER-ID: "John Louis Del Rosario <john@delrosario.org>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy. We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy. gpg: key F3B8AFC253F78AA8 marked as ultimately trusted gpg: revocation certificate stored as '/home/john/.gnupg/openpgp-revocs.d/326B86D9A765F7585378190AF3B8AFC253F78AA8.rev' public and secret key created and signed. pub rsa4096 2018-10-27 [SC] [expires: 2019-06-24] 326B86D9A765F7585378190AF3B8AFC253F78AA8 uid John Louis Del Rosario <john@delrosario.org> sub rsa4096 2018-10-27 [E] [expires: 2019-06-24]
Generate revocation certificate
It is strongly recommended to generate a revocation certificate in advance even if you have no plans to revoke your keys any time soon. If you lose your private key for any reason (i.e. lost backups or forgotten passphrase), this pre-created revocation certificate will be the only way to “delete” your invalid keys from the keyservers.
I’ve already made this mistake a few years ago when I didn’t understand the implications of pushing my key to a keyserver. As expected, I eventually lost my private key (no backups of course) and now my public key will remain on the keyservers and continue to make a mess of things forever.
Make sure to keep it in a safe place, otherwise anyone who has access to this file can revoke your still valid keys! Once a key is revoked, it cannot be unrevoked. You should treat this revocation certificate similar to how you treat the private key.
$ gpg --output ~/john@delrosario.org.revoke.asc --gen-revoke john@delrosario.org sec rsa4096/F3B8AFC253F78AA8 2018-10-27 John Louis Del Rosario <john@delrosario.org> Create a revocation certificate for this key? (y/N) y Please select the reason for the revocation: 0 = No reason specified 1 = Key has been compromised 2 = Key is superseded 3 = Key is no longer used Q = Cancel (Probably you want to select 1 here) Your decision? 1 Enter an optional description; end it with an empty line: > I've either lost my private key or forgotten my passphrase. Sorry. > Reason for revocation: Key has been compromised I've either lost my private key or forgotten my passphrase. Sorry. Is this okay? (y/N) y ASCII armored output forced. Revocation certificate created.
Backups
The following command exports a plain-text backup of the private key.
$ gpg --export-secret-key --armor --output ~/john@delrosario.org.backup-secret-key.asc
Backup to digital media
There are multiple options for this one. You could backup to a USB flash drive, CD, DVD, or SD card. Choose the ones where you are confident that you will be able to use in the future. It’s not a bad idea either to backup to different media for redundancy.
Find a spare USB flash drive or SD card and reformat it. Copy both the backup file and revocation certificate generated earlier into this device.
Keep the device(s) in a locked box and/or drawer, because you don’t want anyone to accidentally reformat it, or worse, access the private key and revocation certificate.
Note that we are not encrypting the device(s), since your private key is already encrypted with the passphrase provided earlier, and it is unlikely that we will remember the password to decrypt contents in the future.
Backup on paper
I don’t trust the cheap USB flash drive to be able to last especially if it is left locked away unattended for a long time, so it is a good idea to have a second form of backup that is more resilient.
An analog paper backup will be more difficult to restore than the digital one, but it is better than finding out the USB flash drive no longer works or you don’t have access to a DVD drive and having no other alternative. You could even laminate the paper afterwards to help protect it against time and the elements.
When printing the backups, make sure to use a printer you trust (i.e. your own home printer) and not some printer in an internet cafe.
Generate print-friendly versions of the backup and revocation files
You could print the backup and revocation files in plain-text directly, but in order to restore them later you would have to manually type in the contents of the files!
Instead we will generate a QR code from the contents of the files so we can just scan or take a photo of the backups to get the digital versions back.
Download the qrencode
program then run the following commands.
$ qrencode -r john@delrosario.org.revoke.asc -o john@delrosario.org.revoke.png -d 300 -8 $ split -b 1024 -d john@delrosario.org.backup-secret-key.asc john@delrosario.org.backup-secret-key.asc. $ qrencode -r john@delrosario.org.backup-secret-key.asc.00 -o john@delrosario.org.backup-secret-key.asc.00.png -d 300 -8 $ qrencode -r john@delrosario.org.backup-secret-key.asc.01 -o john@delrosario.org.backup-secret-key.asc.01.png -d 300 -8 $ qrencode -r john@delrosario.org.backup-secret-key.asc.02 -o john@delrosario.org.backup-secret-key.asc.02.png -d 300 -8
- Generate QR code from the revocation certificate and save to PNG file
- The private key backup is too large to fit into one QR code, so we
split it into multiple pieces of 1024 bytes each
- Feel free to adjust the size (
-b
argument) of each piece. You want to balance the size and the number of pieces. Too large, and the resulting QR image becomes too dense and you’ll have a higher chance of errors during printing or scanning. Too small, and you’ll end up with too many separate images.
- Feel free to adjust the size (
- Generate QR codes for the 1st, 2nd, and 3rd (etc.) pieces of the private key
When you print the PNG files, you should label each page to indicate the purpose of the image. This is particularly important for the secret key backup since we will need to concatenate the pieces in the correct order.
Restoring the private key onto a new machine
Restoring from digital backup
Take the 2nd laptop and mount the backup USB flash drive onto it. First check and make sure you are able to read the backup files.
In the commands below, the machine I am restoring on is running
Slackware 14.2 which has a slightly older version of GnuPG (gpg2
version 2.0.31).
- Import the backup file. Make sure the file is readable by your user account (you might need to modify the file permissions)
- List the keys to make sure everything looks good
- Edit the recently imported key
- Trust the new key
- Save your changes
$ gpg2 --import /mnt/backup-media/john@delrosario.org.backup-secret-key.asc gpg: keyring `/home/john/.gnupg/secring.gpg' created gpg: keyring `/home/john/.gnupg/pubring.gpg' created gpg: key BB782F00: secret key imported gpg: /home/john/.gnupg/trustdb.gpg: trustdb created gpg: key BB782F00: public key "John Louis Del Rosario <john@delrosario.org>" imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1) gpg: secret keys read: 1 gpg: secret keys imported: 1 $ gpg2 --list-keys /home/john/.gnupg/pubring.gpg ----------------------------- pub 2048R/BB782F00 2018-10-28 [expires: 2019-06-25] uid [ unknown] John Louis Del Rosario <john@delrosario.org> uid [ unknown] John Louis Del Rosario <john2x@gmail.com> sub 2048R/86D878EC 2018-10-28 [expires: 2019-06-25] $ gpg2 --edit-key john@delrosario.org gpg (GnuPG) 2.0.31; Copyright (C) 2015 Free Software Foundation, Inc. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Secret key is available. pub 2048R/BB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: unknown validity: unknown sub 2048R/86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ unknown] (1). John Louis Del Rosario <john@delrosario.org> [ unknown] (2) John Louis Del Rosario <john2x@gmail.com> gpg> trust pub 2048R/BB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: unknown validity: unknown sub 2048R/86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ unknown] (1). John Louis Del Rosario <john@delrosario.org> [ unknown] (2) John Louis Del Rosario <john2x@gmail.com> Please decide how far you trust this user to correctly verify other users' keys (by looking at passports, checking fingerprints from different sources, etc.) 1 = I don't know or won't say 2 = I do NOT trust 3 = I trust marginally 4 = I trust fully 5 = I trust ultimately m = back to the main menu Your decision? 5 Do you really want to set this key to ultimate trust? (y/N) y pub 2048R/BB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: ultimate validity: unknown sub 2048R/86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ unknown] (1). John Louis Del Rosario <john@delrosario.org> [ unknown] (2) John Louis Del Rosario <john2x@gmail.com> Please note that the shown key validity is not necessarily correct unless you restart the program. gpg> save
Restoring from paper backup
To restore from your paper backups, scan the different pieces and read them with a QR code scanner. Once you have the text contents, concatenate them back into one file to get back the original backup file and follow the same steps as restoring from a digital backup.
It is a good idea to test restoring, especially the paper backups. You
don’t want to find out later that your backups don’t work at all. Try
to scan the QR codes and compare the contents with the original files
(using diff
) to verify data integrity.
Restoring the private key onto an Android device
You first need to restore the key on a laptop so you can re-export the
secret key with the --armor
parameter.
The de facto app on Android to manage PGP keys is OpenKeychain. You need to securely transfer the exported private key to the Android device. On Linux this requires to mount the device via MTP. It is not recommended to transfer the file via Bluetooth as that is an insecure channel. Once the backup is on the device, you can import the file into OpenKeychain.
Sharing the public key
Adding an alternative user ID
As mentioned previously, I foolishly published my old keys to a keyserver and lost the primary key. So now using my (real) primary email address (john2x@gmail.com) will cause problems for other people. That’s why I chose to use a different primary email address (john@delrosario.org) to minimize the issue.
But I still want my Gmail account to be related to my key since majority of my communication will be done via Gmail.
- Call
adduid
command - Enter the alternative email address
- The new UID will have
unkown
trust status - Select the new UID (#2)
- The star (
*
) indicates the selected UID - Call the
trust
command - Set trust level to 5
- Save your changes
- Review UIDs
- The newly added UID has been set as the default. We want to change that.
- Select the other UID
- Correct UID selected
- Call
primary
command to set the selected ID as primary/default - Save again
$ gpg --edit-key john@delrosario.org Secret key is available. sec rsa2048/0424951EBB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: ultimate validity: ultimate ssb rsa2048/ABE79E9F86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ultimate] (1). John Louis Del Rosario <john@delrosario.org> gpg> adduid Real name: John Louis Del Rosario Email address: john2x@gmail.com Comment: You selected this USER-ID: "John Louis Del Rosario <john2x@gmail.com>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O sec rsa2048/0424951EBB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: ultimate validity: ultimate ssb rsa2048/ABE79E9F86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ultimate] (1) John Louis Del Rosario <john@delrosario.org> [ unknown] (2). John Louis Del Rosario <john2x@gmail.com> gpg> uid 2 sec rsa2048/0424951EBB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: ultimate validity: ultimate ssb rsa2048/ABE79E9F86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ultimate] (1) John Louis Del Rosario <john@delrosario.org> [ unknown] (2)* John Louis Del Rosario <john2x@gmail.com> gpg> trust sec rsa2048/0424951EBB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: ultimate validity: ultimate ssb rsa2048/ABE79E9F86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ultimate] (1) John Louis Del Rosario <john@delrosario.org> [ unknown] (2)* John Louis Del Rosario <john2x@gmail.com> Please decide how far you trust this user to correctly verify other users' keys (by looking at passports, checking fingerprints from different sources, etc.) 1 = I don't know or won't say 2 = I do NOT trust 3 = I trust marginally 4 = I trust fully 5 = I trust ultimately m = back to the main menu Your decision? 5 Do you really want to set this key to ultimate trust? (y/N) y gpg> save $ gpg --edit-key john@delrosario.org Secret key is available. sec rsa2048/0424951EBB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: ultimate validity: ultimate ssb rsa2048/ABE79E9F86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ultimate] (1). John Louis Del Rosario <john2x@gmail.com> [ultimate] (2) John Louis Del Rosario <john@delrosario.org> gpg> uid 2 sec rsa2048/0424951EBB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: ultimate validity: ultimate ssb rsa2048/ABE79E9F86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ultimate] (1). John Louis Del Rosario <john2x@gmail.com> [ultimate] (2)* John Louis Del Rosario <john@delrosario.org> gpg> primary sec rsa2048/0424951EBB782F00 created: 2018-10-28 expires: 2019-06-25 usage: SC trust: ultimate validity: ultimate ssb rsa2048/ABE79E9F86D878EC created: 2018-10-28 expires: 2019-06-25 usage: E [ultimate] (1) John Louis Del Rosario <john2x@gmail.com> [ultimate] (2)* John Louis Del Rosario <john@delrosario.org> gpg> save
If you want, you can create a new backup after adding a new UID. This is not required though, as when you do restore from an old backup that didn’t have the new UID yet, you could just re-add the UID with no problems. Alternatively you could export a new public key and then import it after restoring the old backup, this will bring in the new data and bring you back to the latest state.
Sharing with individuals
To generate a plain-text public key, run the following command.
$ gpg --export --armor john@delrosario.org > john@delrosario.org.pub
You can then send this key to your friends/contacts. The communication channel does not need to be secure since it is a public key and can only be used to encrypt messages, but it is still recommended for recipients of the public key (i.e. your friends/contacts) to verify the owner of the public key (otherwise they might be sending encrypted messages to an impostor!).
You could even publish the public key on your website so your visitors can have easy access to it and is an easy way to “verify” ownership of the public key. Just make sure your website and the page containing the public key is using TLS/SSL otherwise the contents can’t be trusted.
Uploading to a keyserver
Once you’re confident in your ability to properly manage your PGP keys, you can publish your public key to a keyserver. Just be absolutely sure you have a revocation certificate ready before you do so!
$ gpg --send-keys john@delrosario.org
Renewing expiration dates
Keys can be renewed even after their expiration dates. All that’s needed is the private key (even if it’s expired) and its passphrase to be able to update the expiry date metadata of the keys.
$ gpg --edit-key john@delrosario.org Secret key is available. sec rsa4096/F3B8AFC253F78AA8 created: 2018-10-27 expires: 2019-06-24 usage: SC trust: ultimate validity: ultimate ssb rsa4096/F6E3BF3D1AA856AC created: 2018-10-27 expires: 2019-06-24 usage: E [ultimate] (1). John Louis Del Rosario <john@delrosario.org> [ultimate] (2) John Louis Del Rosario <john2x@gmail.com> gpg> expire Changing expiration time for the primary key. 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? (0) 1y Key expires at Sun 27 Oct 2019 03:34:15 PM +08 Is this correct? (y/N) y sec rsa4096/F3B8AFC253F78AA8 created: 2018-10-27 expires: 2019-10-27 usage: SC trust: ultimate validity: ultimate ssb rsa4096/F6E3BF3D1AA856AC created: 2018-10-27 expires: 2019-10-27 usage: E [ultimate] (1). John Louis Del Rosario <john@delrosario.org> gpg> save
Export new public key
After updating the expiry date, don’t forget to generate a new public key and update your friends/contacts to use the new public key, and update the public key hosted on your website, and if you published to a keyserver, sync the new key.
$ gpg --export --armor john@delrosario.org > john@delrosario.org.pub $ gpg --send-keys john@delrosario.org