UP | HOME

Published: 2018-10-29

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

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.

  1. Choose the 1st option (RSA and RSA) for the kind of key
  2. 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.
  3. 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.
  4. 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
  1. Generate QR code from the revocation certificate and save to PNG file
  2. 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.
  3. 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).

  1. Import the backup file. Make sure the file is readable by your user account (you might need to modify the file permissions)
  2. List the keys to make sure everything looks good
  3. Edit the recently imported key
  4. Trust the new key
  5. 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.

  1. Call adduid command
  2. Enter the alternative email address
  3. The new UID will have unkown trust status
  4. Select the new UID (#2)
  5. The star (*) indicates the selected UID
  6. Call the trust command
  7. Set trust level to 5
  8. Save your changes
  9. Review UIDs
  10. The newly added UID has been set as the default. We want to change that.
  11. Select the other UID
  12. Correct UID selected
  13. Call primary command to set the selected ID as primary/default
  14. 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

TODO Disaster recovery

Revoke keys on keyserver

Generate brand new key pair

Notify individuals you’ve previously shared with


Keywords: gpg

Modified: 2018-10-29 14:03:27 +08

Copyright (c) 2018 John Louis Del Rosario

Emacs 26.1 (Org mode 9.1.9)