Introduction

This "book" contains information about how I use a Yubikey (actually several Yubikeys) to store my PGP and SSH secret keys.

I've written several different pages over the past few years which document various parts of this, however this is an attempt to bring all of this information together in a single place.

๐Ÿšง UNDER CONSTRUCTION ๐Ÿšง

This "book" is "in progress", but I am not finished writing it yet. If you find this site useful in its current state, uhhhh... great, I'm glad I can help?

Otherwise ... please be patient. This is one of several things I'm working on in my spare time.

Overall Process

There are two major steps in the process.

Load keys on to a YubiKey

The first part of the process is getting the secret parts of a PGP key, on to a YubiKey. This may include creating a PGP key.

This will generally only need to be done once for each YubiKey. Because the YubiKeys only contain secret keys, changes to a key's expiration date or identities will not require any updates to the YubiKeys.

โš ๏ธ If you already have a PGP key

One of the biggest reasons for putting your secret keys on a YubiKey is to avoid having your PGP or SSH secret keys be on the disks of your workstations. Even if you delete them, remember that there are ways to "un-delete" files.

If your current secret keys are already on your workstations' disks, you may want to consider generating new keys from scratch, and doing it under Tails so that the secret keys are never written to a non-encrypted disk.

The safest way I've found to avoid having your PGP secret keys ever exist on a computer's disk, is to use Tails. This is a "Live" Linux environment which runs from a USB stick. Its persistent storage feature provides a way to store actual secret key files somewhere (so you have a backup in case a YubiKey is lost or broken), and because the persistent storage is encrypted, anybody who finds your Tails stick(s) won't be able to access the key files.

I use Tails to manage my own PGP keys. The directions on this site will explain (hopefully clearly) how I do this.

Configuring Workstations

The second part of this will be configuring each workstation where you (or others) plan to use YubiKeys for PGP and SSH.

This is something you may end up needing to do multiple times, depending on how many machines you use on a regular basis.

About this book

Operating Systems

Most of my personal computers are running macOS, with one laptop and a few servers running Linux. As such, the directions in this book will primarily focus on macOS and Linux.

I only own one machine running windows, specifically for programming a few older ham radios for which non-windows programming software is not available. This computer has never been connected to any network (at least not since the last time I re-formatted the disk to install the OS), and ... now that I think about it, I haven't even powered that machine on in over two years.

So this book isn't going to cover windows.

Created with mdbook

This "book" is being created using a program called mdbook, which allows me to write the content using Markdown and have it converted to an HTML format that I think looks nice, especially with a few minor customizations.

And rather than making the same customizations every time I start a new "book" (I have several, both at work and for non-work), I created a template containing a newly created book with my customizations already in place.

โ‡’ https://github.com/kg4zow/mdbook-template/

Feedback

I would appreciate any feedback you may have to offer about this book.

  • Email: jms1@jms1.net

License

Creative Commons License

This book is licensed under a Creative Commons Attribution 4.0 International License.

Short version, you're free to use or copy the information, so long as you tell people that I originally wrote it.

โ‡’ legal mumbo jumbo

Background Information

The pages in this section will provide some background information, in case you're not famliar with some of the systems we'll be dealing with.

About PGP

PGP, or "Pretty Good Privacy", is an encryption program developed by Phil Zimmerman in the early 1990's. It was one of the first programs to make public-key cryptography "easy" to use. The program was "freeware", meaning you could use it without paying a license fee, and the source code was available so that people could inspect it, and so that you could compile it on your own machines. However, it wasn't quite what we would now call "open source".

At the time, any cryptographic software which used keys longer than 40 bits was classified as a "munition" by the US State Department, and could not legally be sent out of the country using electronic means (i.e. downloading, email, IRC, etc.) PGP was capable of using keys up to 2047 bits long at the time, so the US Justice Department opened an investigation into the author. The investigation was eventually dropped after Daniel J. Bernstein (the author of qmail and djbdns) sued the United States over crypto export laws, and won, however Zimmerman's life was pretty rough for a while there.

Zimmerman ended up forming a company, PGP Incorporated, and tried to make a living by selling licenses. The company ended up being sold and re-sold a few times, and the original PGP product is now owned by Broadcomm, who does not appear to have any kind of product offering around it.

OpenPGP

OpenPGP is the message format originally used by the PGP software. It has been standardized as RFC 4880, and many people have written software which implements this standard.

GnuPG

GnuPG is the name of a program which implements the OpenPGP standard.

GnuPG is pretty much "the standard" PGP software used on almost all Linux distributions, and is available for macOS, windows, and several other operating systems. You can also download the source code and compile it for just about any other OS as well.

And unlike the original PGP software, GnuPG is "open source" software, available under the GNU GPLv3 license.

pgp and gpg

pgp is the name of the primary executable from the original PGP software.

gpg is the name of the primary executable from the GnuPG software. It was originally written to try and maintain compatibility with the command line options from the original pgp program, however it supports a LOT of features that pgp did not, so there are a lot of additional options.

You may also see references to a gpgv command. This is a stripped-down version of gpg which only verifies signatures.

Other Sites

I don't claim to be a great expert with PGP/GnuPG, only that I've been using it for a long time. A lot of the things I mention in this book came from other web sites. Some of these other sites are ...

Public-key Cryptography

Shared-key cryptography refers to a system where the key used to encrypt a message, is also used to decrypt the message. This is also referred to as "symmetrical" encryption, since the same key is used for both encryption and decryption.

Shared-key systems are useful for encrypting "data at rest", such as files on a backup disk. They can also be useful when sending messages, if both parties already know the key.

However, if you don't already have a shared key with the people you're communicating with, you need to generate one, and then you need to figure out a way to give them the key, without also sharing it with the entire world.

Public-key cryptography uses a different type of algorithm, where each user has a pair of keys. The algorithms have an interesting mathematical property where, if a message is encrypted using one of the keys in a given pair, the resulting encrypted message can only be decrypted using the other key from the same pair. The key which encrypted the message, cannot decrypt it.

This is also referred to as "asymmetrical" encryption, since different keys are used for encryption and decryption.

As an example, if Alice encrypts a message using Bob's public key, she can send the resulting encrypted message using any mechanism she likes, including chat, email, posting it on social media, or even having it printed on a billboard next to the highway. However the message gets transferred, only Bob's secret key can decrypt it.

โ„น๏ธ Who are Alice and Bob anyway?

The names Alice, Bob, Charlie, and so forth, are commonly used in examples which talk about encrypted messaging. The names are used because they start with A, B, C, and so forth. These are normally "the good guys", who are just trying to exchange secret messages with each other.

You may also see the name Mallory, who is traditionally "the bad guy". Mallory may be trying to read the encrypted messages, send fake messages that look like they came from one of the good guys, or otherwise interfere with how the system is designed. (I think I remember reading somewhere they wanted a name starting with "M" for "malicious"?)

Digital Signatures

A digital signature provides a way for people to verify ...

  • that a message hasn't been changed since it was "signed".

  • that a message really did come from the person who the signature claims that it came from.

They work like encrypted messages, but with the keys "swapped".

If Alice wants to send a "signed" message, she would ...

  • Create a message.

  • Calculate the hash of the original message. (Some signature schemes may include more information than this.)

  • Encrypt the hash using her own secret key, and add her public key to that.

The result, comprised of the encrypted hash and a public key, is known as a Digital Signature, or just a signature. When she sends the original message, she sends the digital signature along with it.

When somebody receives the message and wants to verify signature, they would ...

  • Decrypt the signature, using the public key it came with.

  • Calculate their own hash of the original message.

  • Compare the hash they calculated against the hash from within the signature. If they match, they can be sure that the message was not changed since that signature was created.

  • If they already know Alice's public key, they can compare the public key from the signature against the public key that they already know belongs to Alice. If they match, they can be sure that Alice is the person who created the signature.

In practice it's a little more complicated than this, but if you undersood this example, you understand the basic concept of how digital signatures work.

Anatomy of a PGP key

As mentioned above, PGP uses pairs of keys - one public and one secret. However, a "PGP key" is actually a set of key pairs, with almost all PGP keys having two or more individual key pairs.

In the examples below, we'll look at my own PGP key.

$ gpg --list-keys --with-subkey-fingerprints 49B9FD3BB4422EBB
pub   rsa4096 2019-03-21 [SC] [expires: 2024-01-01]
      E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB
uid           [ultimate] John Simpson <jms1@jms1.net>
uid           [ultimate] John Simpson <kg4zow@mac.com>
uid           [ultimate] John Simpson <kg4zow@kg4zow.us>
sub   rsa4096 2019-03-21 [E] [expires: 2024-01-01]
      3C8EC9C7B067A4C542F9727D795C2CF824364755
sub   rsa4096 2019-03-21 [S] [expires: 2024-01-01]
      77DEBB0C8C7FBAFF1E0E70DCE9E44ED30E2F2445
sub   rsa4096 2019-03-21 [A] [expires: 2024-01-01]
      7A6B95B6BF897A6497165AE436823233F8D09EB7

Yes, this is the actual PGP key I use on a regular basis.

If you like, you can download the key from here. You can also download and import it to your local keyring using a single command like so:

curl -s https://jms1.pub/jms1.pub.asc | gpg --import

If you're reading this on/after 2024-01-01, I will probably have updated the expiration dates, and may have forgotten to update this web page as well. If you're feeling generous, let me know via Keybase chat - my Keybase username is jms1.

Identities

PGP keys may contain one or more "identities". Each identity usually consists of a name and and email address, however they can be any arbitrary Unicode string.

In addition, an identity may also be a JPEG image. This is logically similar to how a drivers license or passport would contain your picture on it. I did this once in the past - it was fun to play with but ended up being more trouble than it was worth, so I don't bother anymore. (Besides ... let's be honest, nobody wants to look at my face.)

In the example above, each uid line is an identity. As you can see, each one is my name and an email address.

Keys and Sub-keys

Every PGP key has a "primary key" pair, and may have one or more sub-key pairs. These are normally referred to as just "keys" rather than "key pairs".

In the example above, the pub line is the primary key, and each sub lines is a sub-key.

Each key or sub-key has one or more "capability flags", which tell what the intended use of that key is. These flags are listed in square brackets, after the date the key was issued.

These flags are:

  • Certification [C] - This key is meant to be used for digitally signing other PGP keys or sub-keys. (The same key may also have the [S] capability as well.)

    The [C] flag is always attached to a PGP key's "primary" key, and is never attached to any sub-key.

  • Signing [S] - This key or sub-key is meant to be used for digitally signing messages.

  • Encryption [E] - This sub-key is meant to be used for encrypting messages.

  • Authentication [A] - This sub-key is meant to be used for authentication, including SSH.

In a "normal" PGP key, the primary key will have the [CS] flags (meaning both [C] and [S]), and there will be a single sub-key with the [E] flag. As you can see, my own key has a few extra sub-keys on it.

Key IDs

In the example above, the lines just below pub and sub contain long hex numbers. Those are "fingerprints", which are hashes of that key pair's public key.

The fingerprint of the primary key pair is called the Key ID. In this case, the Key ID is E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB.

Most gpg commands will require a Key ID. This long value can always be used, however some shorter values which can be used as well, so long as they are unique within the keyring.

Key IDDescription
E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB160-bit Key ID
49B9FD3BB4422EBB64-bit Key ID, aka long
B4422EBB32-bit Key ID, aka short

As you can see, the shorter values are the "low bits" from the full Key ID.

Be careful using short values, as the chances of two keys' fingerprints having the same low 32 bits (i.e. 1 in 2ยณยฒ) are a LOT higher than the chances of two keys having the same 160-bit fingerprint (i.e. 1 in 2ยนโถโฐ).

In addition, you can also use an identity, or part of an identity, as a Key ID, so long as only one key in your keyring matches what you entered. This means if you only have a single key containing "jms1" in it, you could use "jms1" as an identity.

If you're not sure, you can run something like "gpg --list-keys jms1" and make sure it only lists the one key. If it lists more than one, you should find some difference between them and use something more specific. (Or just, you know, use the full 160-bit Key ID.)

Keyrings

Every PGP program has a "keyring". This is a set of files containing public and secret keys. A keyring will usually keep the public and secret keys in different files, however the files will be in the same directory.

On systems which support multiple users, each user has their own keyring directory. For GnuPG, this is a directory called ".gnupg" under the user's home directory.

If you need to use a different directory, you can create a GNUPGHOME environment variable whose value points to the directory you want to use. (This is actually something I do when I'm working on documentation like this and need to create "dummy" keys without touching the real keyring on my computer.)

Certifications

Almost every PGP key has one or more identities. And anybody in the world can create a PGP key which contains any identity they like. If you find a PGP key online with the name "Tim Cook <tim.cook@apple.com>", how do you know if that's really his key or not? (Or more likely, if you find several hundred keys online with that identity, how do you tell which ones, if any, are real?)

PGP keys can be certified, or "signed", by other PGP keys.

A certification is a digital signature, made by another PGP key. The idea is, if you're able to verify that signature, and you already "trust" the key which created the signature, you can feel more confident in "trusting" the key which was signed.

For example ...

  • You find a PGP key online which has the name and email address of a co-worker.

  • You didn't get the key directly from them, so you're not sure if it's really their key or not. (Remember, anybody can create a PGP key with any name and email address.)

  • The key you found online was signed by my key.

  • You already know and "trust" my key.

    Maybe I gave you my Key ID in person, maybe you imported it directly from my Keybase account, maybe the Key ID matches the Key ID printed on a business card that I handed to you (I used to do this), maybe you physically met me in person at a "key signing party" and verified a photo ID or something ... whatever the reason, the point is:

    • You trust that it's really my key.

    • You trust that I understand how key-signing works, well enough to NOT sign other peoples' keys without first verifying that the key I'm signing, really belongs to them.

Because you "trust" my key (in this example), as long as you're able to verify the signature on the key you found, you can be fairly confident that the key you found really does belong to that co-worker.

Technically, identities are being certified.

Each signature certifies that the PGP key really belongs to the person named by that identity. If a key starts with one identity, gets a few signatures, and then has additional identities added to it, the existing signatures on the first identity do not automatically apply to the new identities.

Smartcards

A "smartcard" is a physical card, containing a "smart chip". These chips are actually miniature computers. The chip has a processor, a small amount of storage (usually measured in kilobytes), and a set of I/O lines used to talk to a card reader, which is usually attached to a computer. These are similar to the SIM cards used by many mobile phones, and the security chips used by most credit cards.

An "OpenPGP Card" is a smartcard (or other device, like a YubiKey) whose chip has two things:

  • Storage on the chip itself, which can store PGP keys or sub-keys.

  • Software on the chip to perform the encryption and decryption operations needed by PGP.

The card performs the PGP operations which need secret keys (decryption and signing) using the keys stored within the chip. This means that the secret keys never need to be sent to the computer.

The OpenPGP Specification describes the API (protocol, language, etc.) used when talking to OpenPGP Cards. Several dozen companies around the world make cards or other devices which implement this API. GnuPG is capable of interacting with any of them.

YubiKey 5 Series

This "book" talks about the YubiKey 5 series, which implements the "OpenPGP Card" standard.

Almost everything in this book which mentions a YubiKey, could also apply to any other device which implements the OpenPGP Card standard.

Older YubiKey devices

The older YubiKey 4 and YubiKey Neo devices also implemented the OpenPGP specification, however they did not support ED25519 keys, and they are limited to 2048-bit RSA keys.

In addition, some YubiKey Neo devices may have older software with a security issue. At the time they were replacing the affected YubiKey Neo devices for free (and in fact they replaced mine), however this replacement program was ended in 2019. (If you're still using an old YubiKey Neo, it's really time to upgrade.)

PGP Operations

I found myself going into a LOT more detail while writing the About PGP (aka GnuPG) page, and realized that a lot of what I was writing was more than just information about GnuPG, it was information about how to use GnuPG.

For now I'm creating a separate page to cover these things. Knowing me, I suspect that over time this will grow into separate pages for different operations. For now, the information has already been written,

NOTE: This page is only meant as a quick reference. Knowing me, I may go into more detail (maybe too much detail?) about some things than I do about others. If anything is not clear or not covered, (1) please let me know, and (2) consult the official documentation.

โ‡’ https://www.gnupg.org/documentation/index.html

Primary Operations

These are the four primary operations that people use PGP for.

Encrypting messages

  • gpg -e or --encrypt

Decrypting messages

  • gpg -d or --decrypt

Signing messages

  • gpg -s or --sign
  • gpg -b or --detach-sign
  • gpg --clearsign or --clear-sign

Verifying signatures

  • gpg --verify

Key Management

These operations are used when copying PGP keys to/from other people.

Generate a new key

  • gpg --gen-key or --generate-key

    • Prompts for name and email, uses defaults for key algorithms and expiration dates.
    • Generates a primary key with usage flags [SC], and subkey with [E].
  • gpg --full-gen-key or --full-generate-key

    • Prompts for all necessary data.
    • Generates a primary key with usage flags [SC], and subkey with [E].
  • gpg --quick-gen-key or --quick-generate-key

    • Identity, key algorithm, usage flags, and expiration date are all specified as command line arguments.
    • Generates a primary key with usage flags named on command line.
    • Expire date format: YYYYmmddTHHMMSS (UTC) or YYYY-mm-dd (12:00:00 UTC on that date)
    • Does not generate any subkeys, use gpg --quick-add-key (which also requires key algorithm, usage flags, and expiration date as command line arguments).

Export keys

The usual way to share keys with other people is to "export" them from a keyring to a file, and distribute that file. (This is exactly what I did to make the https://jms1.pub/jms1.pub.asc file.) Exported keys can be in one of two formats:

  • A binary format, containing a series of raw PGP packets.

  • An "ASCII-armored" format, containing only "printable" characters.

    These files can be sent via email, copy/pasted in chat sessions, or printed on paper and later manually typed (if your typing is that accurate, and you have that kind of patience) without worrying about the key being corrupted in the process.

I normally use the ASCII-armored format, unless there's a speicific reason to need the binary format.

$ gpg --export -a E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBFyT6EQBEADKXl/ss7pG15/rknrVSynsA9IlfNSrIPehmPerbvZfpv+hWgtO
hcizxTMUzPfe7P+jDuSyyVaKlFT8jSt2roOqOTtRbFr+jf0hQr+w1RbmqZvpgUON
KXFcY8xadqDdLn5s62IuCRoEyQsibz8buT0O7tarC2g8xtZeRoYX/iQYVykAuhYb
...
vucHCnsaTICZ+cvzhcNDr8eRAhgjTohjEntWcW1Ze22PML80cCYBWh52m0GrgZV2
nWq+bvEf7LllpTqBooNhuxs118Y75MhUWr8kiMZDFG6fiyJ5ALe6lh9ff/EMe4oF
mTBzKPfsw37Ap4X612y24g==
=oYGV
-----END PGP PUBLIC KEY BLOCK-----

The full output from this command, including the -----BEGIN PGP PUBLIC KEY BLOCK----- and -----END PGP PUBLIC KEY BLOCK----- lines, can be shared with others.

Exporting to a file

You can use the normal shell redirection mechanism (i.e. the ">" operator) to save the output to a file.

$ gpg --export -a E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB > jms1.pgp.asc

This file is used in some of the other examples below.

If you're using Keybase, you will find this file in the /keybase/public/jms1/ directory (which is the "document root" for the jms1.pub web site, thanks to the magic of Keybase Sites).

Exporting multiple keys

Note that you can export a single block containing multiple public keys, by specifying multiple Key IDs, or by specifying a single identifier that matches multiple keys. Examples:

  • gpg --export -a 49B9FD3BB4422EBB 101F51733306FCFB

    Two explicit Key IDs. 49..BB is my currently active key, as shown above. 10..FB is an old key which was revoked several years ago after a floppy disk (remember those?) containing a backup copy of the secret key file went missing from my desk at work one day.

  • gpg --export -a jms1@jms1.net

    Identifier matching multiple keys. The keyring on this computer currently has six keys with this email address, some of which are expired (and I don't plan to extend them), one of which is revoked, and the others I just don't use anymore.

Import keys

If you receive an exported key, you can "import" it to your keyring.

Importing from a file

If the file is stored in a file, you can import the file like so:

$ gpg --import jms1.pub.asc
gpg: key 49B9FD3BB4422EBB: 6 signatures not checked due to missing keys
gpg: key 49B9FD3BB4422EBB: public key "John Simpson <jms1@jms1.net>" imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg: no ultimately trusted keys found

So if you're using Keybase, you can import my public key like so:

$ gpg --import /keybase/public/jms1/jms1.pub.asc

Importing from another command

If you run some other command which outputs a PGP key, you can import the key from the first command's output.

$ curl -s https://jms1.pub/jms1.pub.asc | gpg --import
gpg: key 49B9FD3BB4422EBB: "John Simpson <jms1@jms1.net>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

In this example, my keyring already had the key so it didn't actually do anything other than showing the contents of the downloaded file.

Importing via copy/paste

If you found a PGP key somewhere (on a web page, in a text file, wherever) you can COPY the key block, and PASTE it into your keyring. To do this ...

  • Highlight and COPY the key from wherever you found it. Be sure to include the -----BEGIN PGP PUBLIC KEY BLOCK----- and -----END PGP PUBLIC KEY BLOCK----- lines.

  • Run gpg --import and hit ENTER. The computer will be waiting for you to enter something.

  • PASTE.

  • Type whatever character tells your shell that the input is finished. For most Linux/macOS shells, this is CONTROL-D. (I remember it being CONTROL-Z for MS-DOS, so it might be the same for windows? Again, I don't use windows so I can't really say for certain.)

The process will look something like this:

$ gpg --import
<PASTE>
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBFyT6EQBEADKXl/ss7pG15/rknrVSynsA9IlfNSrIPehmPerbvZfpv+hWgtO
...
nWq+bvEf7LllpTqBooNhuxs118Y75MhUWr8kiMZDFG6fiyJ5ALe6lh9ff/EMe4oF
mTBzKPfsw37Ap4X612y24g==
=oYGV
-----END PGP PUBLIC KEY BLOCK-----
<CONTROL-D>
gpg: key 49B9FD3BB4422EBB: "John Simpson <jms1@jms1.net>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

Keyring Management

These operations are used to manage the keyring on your computer.

Technically, importing and exporting keys (above) also involve the keyring, however I think of those two operations differently than the ones below.

List keys

List the public keys on your keyring.

  • gpg -k or --list-keys or --list-public-keys
    • --with-colons option in scripts
    • --with-sig-check or gpg --check-sigs

List the secret keys on your keyring.

  • gpg -K or --list-secret-keys

Show keys

If you find a PGP key block, you can see its contents without importing it into your keyring.

$ gpg --show-key /keybase/public/jms1/jms1.pub.asc
pub   rsa4096 2019-03-21 [SC] [expires: 2024-01-01]
      E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB
uid           [  full  ] John Simpson <jms1@jms1.net>
uid           [  full  ] John Simpson <kg4zow@mac.com>
uid           [  full  ] John Simpson <kg4zow@kg4zow.us>
sub   rsa4096 2019-03-21 [E] [expires: 2024-01-01]
sub   rsa4096 2019-03-21 [S] [expires: 2024-01-01]
sub   rsa4096 2019-03-21 [A] [expires: 2024-01-01]

You can also pipe the output of another command (which prints) a PGP key block) into gpg --show-keys.

$ curl -s https://jms1.pub/jms1.pub.asc | gpg --show-keys
pub   rsa4096 2019-03-21 [SC] [expires: 2024-01-01]
      E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB
uid           [  full  ] John Simpson <jms1@jms1.net>
uid           [  full  ] John Simpson <kg4zow@mac.com>
uid           [  full  ] John Simpson <kg4zow@kg4zow.us>
sub   rsa4096 2019-03-21 [E] [expires: 2024-01-01]
      3C8EC9C7B067A4C542F9727D795C2CF824364755
sub   rsa4096 2019-03-21 [S] [expires: 2024-01-01]
      77DEBB0C8C7FBAFF1E0E70DCE9E44ED30E2F2445
sub   rsa4096 2019-03-21 [A] [expires: 2024-01-01]
      7A6B95B6BF897A6497165AE436823233F8D09EB7

Delete keys

Deletes keys from your keyring.

  • gpg --delete-keys
    • only deletes public keys
  • gpg --delete-secret-keys
    • delete secret keys before deleting public keys
  • gpg --delete-secret-and-public-key
    • I didn't know this option existed until I wrote this. ๐Ÿ˜Ž

Notes

  • This only deletes keys from your keyring. If other people have the key you're deleting, they will still have it, and the key will still be just as valid as it was before you "deleted" it.

  • If you delete one of your own secret keys, you won't be able to decrypt messages which were encrypted using that key (unless you have a backup of the secret key and import that.)

๐Ÿ›‘ If one of your secret keys has been compromised (or you just don't want to use it anymore), you should create and send out a revocation certificate rather than just deleting it.

Certifications

Certifications are signatures applied to other PGP keys. If you "sign" somebody's PGP key, you are telling the world that you believe the key you're signing, really belongs to the person whose identity it says.

Show the signatures on a key

You can use "gpg --list-sigs" to show the signatures on a key.

$ gpg --list-sigs E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB
pub   rsa4096 2019-03-21 [SC] [expires: 2024-01-01]
      E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB
uid           [  full  ] John Simpson <jms1@jms1.net>
sig 3        49B9FD3BB4422EBB 2023-01-01  [self-signature]
sig          4630606F0B2F31A6 2019-03-21  John Simpson <email@$DAYJOB>
sig          A7EC1FBAB3B50007 2019-03-21  John Simpson <jms1@jms1.net>
uid           [  full  ] John Simpson <kg4zow@mac.com>
sig 3        49B9FD3BB4422EBB 2023-01-01  [self-signature]
sig          4630606F0B2F31A6 2019-03-21  John Simpson <email@$DAYJOB>
sig          A7EC1FBAB3B50007 2019-03-21  John Simpson <jms1@jms1.net>
uid           [  full  ] John Simpson <kg4zow@kg4zow.us>
sig 3        49B9FD3BB4422EBB 2023-01-01  [self-signature]
sig          4630606F0B2F31A6 2019-03-21  John Simpson <email@$DAYJOB>
sig          A7EC1FBAB3B50007 2019-03-21  John Simpson <jms1@jms1.net>
sub   rsa4096 2019-03-21 [E] [expires: 2024-01-01]
      3C8EC9C7B067A4C542F9727D795C2CF824364755
sig          49B9FD3BB4422EBB 2019-03-21  [self-signature]
sig          49B9FD3BB4422EBB 2020-03-14  [self-signature]
sig          49B9FD3BB4422EBB 2020-12-06  [self-signature]
sig          49B9FD3BB4422EBB 2021-12-31  [self-signature]
sig          49B9FD3BB4422EBB 2023-01-01  [self-signature]
sub   rsa4096 2019-03-21 [S] [expires: 2024-01-01]
      77DEBB0C8C7FBAFF1E0E70DCE9E44ED30E2F2445
sig          49B9FD3BB4422EBB 2019-03-21  [self-signature]
sig          49B9FD3BB4422EBB 2020-03-14  [self-signature]
sig          49B9FD3BB4422EBB 2020-12-06  [self-signature]
sig          49B9FD3BB4422EBB 2021-12-31  [self-signature]
sig          49B9FD3BB4422EBB 2023-01-01  [self-signature]
sub   rsa4096 2019-03-21 [A] [expires: 2024-01-01]
      7A6B95B6BF897A6497165AE436823233F8D09EB7
sig          49B9FD3BB4422EBB 2019-03-21  [self-signature]
sig          49B9FD3BB4422EBB 2020-03-14  [self-signature]
sig          49B9FD3BB4422EBB 2020-12-06  [self-signature]
sig          49B9FD3BB4422EBB 2021-12-31  [self-signature]
sig          49B9FD3BB4422EBB 2023-01-01  [self-signature]

You will notice that ...

  • All identities and subkeys should have signatures made by the primary key. (These are shown as [self-signature] in the output.)

  • Only identities will have signatures made by other PGP keys.

    If a key has multiple identities, it's entirely possible that each identity will have a different list of signatures. (Unfortunately this isn't true for this particular key, that would have made for a good example.)

  • Subkeys will have "signatures" which tell when they expire. If a key's expiration date has been changed over time (i.e. "renewed"), there may be multiple signatures with different dates. GnuPG always uses the last date (in chronological order) as the expiration date.

Note that the dates on each signature are when the signatures were created. Each key's current expiration date is shown as [expires: 2024-01-01] on the pub or sub lines.

Check the signatures on a key

The gpg --list-sigs command only shows the signatures on a key, it doesn't actually "do the math" to verify which signatures are actually valid.

  • gpg --check-sigs

    This command will "do the math" and verify that the signatures are valid.

Signing somebody else's key

When somebody "signs" a key, they are asserting that the key belongs to the person matching that identity.

  • gpg --sign-key

    • Your signature will be included if you export the key, or send it to a keyserver.
    • Same as the gpg --edit-key command's sign sub-command.
  • gpg --lsign-key

    • Your signature will NOT be included if you export the key or send it to a keyserver.

    • Same as the gpg --edit-key command's lsign sub-command.

      I'm sure that there are cases where you may want to do this, however I personally have never found one. Every time I've ever signed somebody else's PGP key, it was a normal "exportable" signature.

Trust

View trust levels

  • shown in key listings

  • values

    • undef or undefined
    • never
    • revoked
    • expired
    • marginal
    • full
    • ultimate
    • err

Assign a trust level

  • gpg --edit-key ... sign or lsign sub-commands

    This adds a signature to the target key. Assuming the key you're signing it with is trusted, the target key will be "trusted by association".

  • gpg --edit-key ... trust sub-command

    This will manually set a trust value for the target key. You can do this instead of, or in addition to, signing the key.

Revocation

A Revocation Certificate is a special message which tells other PGP clients to no longer trust a PGP key. This are needed when ...

  • The secret key has been compromised, i.e. if somebody steals a copy of your secret key.

  • You have lost access to the secret key, and no longer have the ability to sign or decrypt messages using that key.

  • The key didn't have an expiration date, and you've decided not to use it anymore.

  • Any other case where you don't want to use a particular key anymore, and need to try and inform the rest of the world not to use it.

When a revocation certificates is "imported" into a computer's keyring ...

  • Any gpg commands will refuse to encrypt messages to that key.

  • If your keyring has the corresponding secret key, you will still be able to decrypt messages using the key. This includes new messages from others who don't know not to use the key anymore, because they haven't imported the revocation certificate into their keyring yet.

    In this case, you should make it a point to send them a copy of the revocation certificate, so they can import it into their keyring, and their PGP software will know not to use that particular key anymore.

  • Signatures created using the key can still be verified, but the output will report that the key has been revoked, so the user can take this into account in deciding whether or not to trust the signature.

Create ahead of time

Revocation certificates are signed by the primary key of the PGP key they are revoking. However, if you need to revoke a PGP key becuase the secret key is no longer available, you won't be able to create a revocation certificate.

The solution is to create a revocation certificate ahead of time, and not distribute it until you need it.

When you do this, you should store it somewhere that ...

  • You won't lose it. The same Tails USB sticks where you have backups of the secret keys will work for this.

  • Only people that you trust will be able to access them. If you don't trust anybody with the passphrase for your Tails USB sticks' persistent storage, you could copy the revocation certificate to a non-encrypted USB stick, and store it with a family member that you really trust, or in a safety deposit box at a bank, with instructions to share the revocation certificate with the world in case something happens and you're no longer around.

๐Ÿ›‘ Do not share revocation certificates unless you MEAN to revoke the key.

Once a revocation certificate has been imported into somebody's keyring (or even worse, sent to a key server) there is no way to "undo the revocation". Your only choice will be to generate a new key pair ... and if your previous key was signed by others, your new key would need to be signed by those others as well.

If a revocation certificate "escapes", that key is done.

Default revocation certificate

Recent versions of GnuPG will generate a revocation certificate and store it under your .gnupg/ directory automatically. For example, I just created a new dummy key (in a Docker container running Debian 11).

root@41ab46aa18b6:~# gpg --quick-generate-key 'Dummy key <please@dont-spam.us>' rsa4096 default 20240101T000000
...
gpg: key 5239E161BB5A6B70 marked as ultimately trusted
gpg: directory '/root/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/F25DB69FA96FBA5BDBB0A96F5239E161BB5A6B70.rev'
public and secret key created and signed.

Note that this key cannot be used for encryption.  You may want to use
the command "--edit-key" to generate a subkey for this purpose.
pub   rsa4096 2023-05-20 [SC] [expires: 2024-01-01]
      F25DB69FA96FBA5BDBB0A96F5239E161BB5A6B70
uid                      Dummy key <please@dont-spam.us>

Note the "gpg: revocation certificate stored as ..." message. This tells you the filename where it stored the revocation certificate.

Contents

If you look at the contents of a revocation certificate, you will see that it explains what the file is and which key it revokes, along with the revocation certificate itself.

root@41ab46aa18b6:~# cat /root/.gnupg/openpgp-revocs.d/F25DB69FA96FBA5BDBB0A96F5239E161BB5A6B70.rev
This is a revocation certificate for the OpenPGP key:

pub   rsa4096 2023-05-20 [SC] [expires: 2024-01-01]
      F25DB69FA96FBA5BDBB0A96F5239E161BB5A6B70
uid          Dummy key <please@dont-spam.us>

A revocation certificate is a kind of "kill switch" to publicly
declare that a key shall not anymore be used.  It is not possible
to retract such a revocation certificate once it has been published.

Use it to revoke this key in case of a compromise or loss of
the secret key.  However, if the secret key is still accessible,
it is better to generate a new revocation certificate and give
a reason for the revocation.  For details see the description of
of the gpg command "--generate-revocation" in the GnuPG manual.

To avoid an accidental use of this file, a colon has been inserted
before the 5 dashes below.  Remove this colon with a text editor
before importing and publishing this revocation certificate.

:-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: This is a revocation certificate

iQI2BCABCgAgFiEE8l22n6lvulvbsKlvUjnhYbtaa3AFAmRpWbkCHQAACgkQUjnh
Ybtaa3DIGw/+MosNoXYWnbwU/dQ4XxMuBDaLXY5bqipW5W+lcIAZdIvSAyqBIOQA
8Uonv9A0c2wh8S/HYMIVBWebBzFBaaiv1WxokGDLZNfdYLbWIbEcjQgopqijzHNA
MLp4ieqm2iOkphV/A1qOofLqzmqYhUTxrs/5MFnR0GSq6pHUYXbH0LkmUjyyecDb
xoaaAjeBsmqmHivr27CrgHesckTsTvQJE648KKpq+6fMWx1+6/mdQR4sa4arlhm0
ANkAgzMxZiUlrmXyanVaeOzg+WMSjOrDnf1NMAEBA1BAEfoez90Q7ifqb+FrLWuV
P216PclCvepC3zDZobqS5at3cRruw4Td26sWNelVaypQFNIvGBNjH7DX1u4Ehhem
mtwjv7f41lO/mO0j5H47wQ3/jsoFwAG94zE6uH5BfkAbAMSMdzUDYsSk7nGqECd0
f27cdp8DnXbEHkEJqN2Z90F1IMyChF6UxR1bPC22n0xeUgjSlQwuFQyVjLLlUtne
VoK54IVu7GQHYQuLzsof+1AKQwkMnjt5n4LpwG/frxsCjlP1IrYXkz9WJkUwTWHw
slXkCyPEh9cs4cUnzOXUMxkbxGmt2HG+s4MdXwOkKS4IAmNJTBpVZFcvg9frRLFZ
KWg8XvhpnCa5l8GY1cOd6xfQiODZyJ7ng8JG5Zbkg9uzgFNnRLD92I0=
=eO+y
-----END PGP PUBLIC KEY BLOCK-----

As you can see, other than the Comment: line it looks like any other PGP PUBLIC KEY BLOCK. (The Comment: line is actually optional, the flag which makes it a revocation certificate is part of a PGP packet within the blob of text.)

Generate a revocation certificate

If you don't have the default revocation certificate, or if you need to create another one so you can specify a reason, you can use "gpg --gen-revoke".

root@41ab46aa18b6:~# gpg --gen-revoke 5239E161BB5A6B70 > revocation.txt

sec  rsa4096/5239E161BB5A6B70 2023-05-20 Dummy key <please@dont-spam.us>

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? 3
Enter an optional description; end it with an empty line:
> Example for documentation
>
Reason for revocation: Key is no longer used
Example for documentation
Is this okay? (y/N) y
ASCII armored output forced.
Revocation certificate created.

Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable.  But have some caution:  The print system of
your machine might store the data and make it available to others!
root@41ab46aa18b6:~#

Import a revocation certificate

In order for a revocation certificate to take effect, it needs to be imported into the user's keyring.

Check the file

Revocation certificates are normally generated with an extra colon in front of the "-----BEGIN" line, so that if somebody runs the wrong command they won't import it by accident. If you look at the file, it tells you about this.

...
To avoid an accidental use of this file, a colon has been inserted
before the 5 dashes below.  Remove this colon with a text editor
before importing and publishing this revocation certificate.

:-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: This is a revocation certificate
...

If the colon is there, open the file with your favourite text editor and remove it. You can also use this sed one-liner to remove it.

$ sed -i -e 's/^://' FILENAME

Import the file

This is just like importing a PGP public key from a file.

$ gpg --import FILENAME
gpg: key 3DEC8A7990B2DDB1: "Revoked key <please@dont-spam.us>" revocation certificate imported
gpg: Total number processed: 1
gpg:    new key revocations: 1
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: next trustdb check due at 2024-01-01

Send a revocation certificate

In order for others to be aware that the key has been revoked, you need to send the key to them.

First, a short story.

Once upon a time, there was a network of PGP key servers, called SKS. People around the world were free to upload their keys to these servers, and they were free to search for and download keys from them. Best of all, the key servers were constantly synchronizing with each other, so if you uploaded a key to one server, you could be reasonably sure that every other key server in the world would have a copy of that key within about half an hour. And if somebody stood up a new keyserver and added it to the network, it would also have all of the same keys that the other servers did.

It was really cool, everybody was able to share keys through the keyserver network.

Then some joker discovered that if they add a couple hundred thousand signatures to a key, it would make GnuPG "hang" while trying to process all of the signatures. And in true anklebiter fashion, rather than reporting the bug so it could be fixed, they decided to "poison" a bunch of public keys which were already widely distributed, and upload the signatures into the keyserver network.

After doing this, anybody who received or refreshed these keys from the network, also received these hundreds of thousands of signatures, and their GnuPG software started hanging.

Because there is no way to remove keys (or signatures) from the keyserver network, they had to shut down the entire keyserver network. In addition, anybody who had already imported one of the poisoned keys had to deal with fixing their GnuPG installation (i.e. finding and deleting the keys from their keyring, or deleting their entire keyring and starting over from scratch).

This is why we can't have nice things.

At the moment (2023-05-20), there is a single keyserver online, using keyserver software which doesn't allow hundreds of thousands of signatures. GnuPG 2.4.1 is internally overriding the hostname keys.gnupg.net to point to that keyserver. Their documentation recommends using this as the keyserver. This keyserver works, however I don't like the idea that there's only one keyserver. (I also don't like that it's owned by canonical, but ... that's different discusson.)

There are other keyservers out there.

  • pgp.mit.edu was one of the very first PGP keyservers. I didn't realize until just now that it was still working, the last time I tried it was throwing all kinds of internal errors ... but I just tried it again, and it appears to be working again. It even has a copy of one of my ancient PGP keys (from 1996), even though gpg can't process it anymore.

  • keys.openpgp.org will store and distribute keys, however you have to verify the email addresses in the keys' identities before you can find the keys using that email address.

Configure GnuPG

  • In $HOME/.gnupg/dirmngr.conf

    keyserver hkp://keys.gnupg.net
    
  • In $HOME/.gnupg/gpg.conf

    keyserver hkp://keys.gnupg.net
    

    For recent versions of GnuPG, having keyserver in the gpg.conf file is supposed to be deprecated. I have it in both files, things seem to work, and I'm not seeing any warnings or error messages because of it, so for now I plan to keep this line in both files.

Send to keyserver

Make sure the revocation certificate has been imported into your keyring.

root@41ab46aa18b6:~# gpg -k
...
pub   rsa4096 2023-05-20 [SC] [revoked: 2023-05-20]
      781C908E54FF164A5873E7533DEC8A7990B2DDB1
uid           [ revoked] Revoked key <please@dont-spam.us>
...

For a fully-revoked key, you should see [revoked: YYYY-MM-DD] on the pub line, and [revoked] on every uid line. (There is a way to revoke an individual identity or subkey, but it doesn't involve using a revocation certificate.)

Then ...

$ gpg --send-key 781C908E54FF164A5873E7533DEC8A7990B2DDB1
gpg: sending key 3DEC8A7990B2DDB1 to hkp://keyserver.ubuntu.com

Other

Send the revocation file out using whatever other mechanism works. You can email it, you can send it out via chat, you can post it on a web site ... whatever works. Basically, whatever mechanism you used to distribute the key in the first place, do the same thing again with the revocation certificate.

And when you talk to people who have sent you PGP-encrypted emails in the past, be sure to tell them that the key was revoked, and where they can find a copy of the revocation certificate.

โ„น๏ธ If you're sending the revocation certificate file out, be sure to remove the colon from the "-----BEGIN" line first. That way the people who receive the file won't have to edit the file, they can just import it.

About SSH

Key-based authentication

  • public/secret keys
  • ssh-agent
  • $HOME/.ssh/authorized_keys files

Other

  • algorithms - need to match what's available from GnuPG
  • keys are just numbers, they have no identities or expire dates
  • SSH CAs - more trouble than they're worth?

Make SSH use gpg-agent

ssh-agent

OpenSSH is the defacto "standard" for SSH clients and servers on Linux and macOS. (This is apparently true for newer versions of windows as well.)

The ssh program normally uses a program called ssh-agent to hold SSH secret keys in memory. The ssh-agent program actually performs the encryption operations necessary to authenticate SSH connections, without ssh needing to know the actual secret key.

On most systems, ssh-agent is started as part of each user's login process. When it starts, it creates a "Unix Domain Socket". The full pathname to this socket ends up being stored in an SSH_AUTH_SOCK environment variable, which ends up being inherited by other processes within the user's login session.

Unix Domain Sockets work the same way that a network socket works, but ...

  • Unix sockets can only be used to communicate with other processes on the same machine.

  • Instead of each endpoint being an IP address and port number, the endpoint is a filename on the local filesystem.

Programs like ssh, scp, and sftp use the SSH_AUTH_SOCK environment variable to find the agent. If this variable doesn't exist, ssh will not be able to use an agent, and will only be able to authenticate using passwords or secret key files stored on the local disk.

The protocol (or "language") that SSH clients use when talking to ssh-agent is fairly simple, although it doesn't seem to be widely documented. The best thing I've been able to find every time I've looked for it is an IETF draft document which "expired" in 2020 ... which doesn't make it any less valid, it just means that the document hadn't been updated for six months (which is probably a good thing, it means the document didn't need to be updated.)

macOS

macOS 10.5 and later set things up to start an ssh-agent process as part of each user's login process. The underlying mechanics are different for different macOS versions, and the filename of the Unix socket is randomly generated, but the result is that every process running as part of the user's login session, will inherit an SSH_AUTH_SOCK environment variable pointing to that Unix socket.

With macOS 10.15 and later, the SIP (System Integrity Protection) mechanism makes it difficult (and in later versions, impossible) to make macOS not start ssh-agent automatically.

Linux

Most Linux distributions do something similar, especially if the login session involves a GUI desktop environment. If it doesn't happen automatically, it's usually fairly simple to edit your "login scripts" (such as a .bashrc file) to either start an agent, or find an existing agent process, and export the SSH_AUTH_SOCK environment variable for you.

Note that I haven't needed to mess with this stuff in at least ten years, and I don't honestly remember any details about it.

gpg-agent

GnuPG has a program called gpg-agent which performs the same kind of in-memory caching, but for for PGP keys.

The gpg-agent program can be configured to open a unix socket and speak the ssh-agent protocol. If you do this, gpg-agent will be able to perform the same signing operations that ssh-agent does, using any of the following:

  • SSH secret key files (such as "id_rsa") from disk.
  • PGP authentication subkeys from your keyring.
  • PGP authentication subkeys stored on a smartcard, such as a YubiKey.

So what we want to do is make all SSH clients talk to gpg-agent instead of ssh-agent. SSH clients use the SSH_AUTH_SOCK environment variable to find the agent, so ...

If we make the SSH_AUTH_SOCK environment variable point to the Unix socket that gpg-agent opens, when an SSH client tries to talk to ssh-agent, it will actually be talking to gpg-agent.

Ultimately, we need to make the SSH_AUTH_SOCK variable to point to the Unix socket file that gpg-agent creates.

macOS

Back in 2018, I figured out how to stop macOS from starting the ssh-agent process, and how to make the login process set the SSH_AUTH_SOCK environment variable point to the socket created by gpg-agent. This worked for a while, but then SIP came along (and later APFS with its immutable filesystems) and that approach didn't work anymore.

Then I found this article, which explains how to "do it the other way around". Instead of trying to change what macOS does, we can replace the Unix socket file with a symbolic link, pointing to the Unix socket where gpg-agent is listening for connections from SSH clients.

This is so much simpler than what I had originally come up with.

About YubiKey

A YubiKey is a USB security key made by Yubico.

The current generation of YubiKeys, known as the YubiKey 5 Series, can provide several security-related services, including ...

  • FIDO U2F
  • FIDO2/WebAuthn
  • PIV/Smart Card emulation
  • OpenPGP

Different keys are available with different options for connecting to a host device, including USB-A, USB-C, Lightning (used on iPhones and iPads), and NFC.

Yubico also sells other security keys which look very similar, and which cost less, however not all of them support OpenPGP. In particular, the "Security Key" and "YubiKey Bio" devices do not support OpenPGP.

If you're planning to order any YubiKey devices, be careful to order devices which support OpenPGP. At the moment, this means only the YubiKey 5 series.

The YubiKey 5 FIPS and YubiKey 5 CSPN series are just YubiKey 5 devices which have undergone additional testing and certification for (FIPS โ†’ US, CSPN โ†’ French/German) government use. If you're not working with one of these government agencies, don't spend the extra money.

Ordering a YubiKey

The best way to order YubiKeys is to order them directly from Yubico.

โ‡’ Yubico Store - YubiKey 5 Series

If you plan on having multiple YubiKeys, you'll probably need a way to tell them apart. Yubico sells "YubiStyle Covers", which stick to the YubiKeys and make it easier to tell which one is which. (I use blue for my personal keys and green for work keys.)

โ‡’ Yubico Store - Accessories

Buying from other suppliers

๐Ÿ›‘ TL;DR: DON'T.

When you buy a YubiKey, you want it to have the most current firmware available. Ordering from YubiKey directly is the only way to be 100% sure that the YubiKeys you receive will have the most current firmware.

I learned this the hard way.

The very first YubiKey I ever had was a "YubiKey Neo" that I ordered from Amazon. The key they sent had apparently been sitting in a warehouse for a year and a half before they shipped it to me, and one of the firmware updates during that time fixed a bug in the OpenPGP code.

When I contacted Yubico about this, they asked me for the YubiKey's serial number and then sent me a new one with the then-current firmware, free of charge. THAT'S customer service.

Ever since this, every YubiKey I've purchased (maybe a dozen?) has been directly from Yubico.

About Tails

โ‡’ Tails

Tails is a "live" Linux distribution designed around privacy and security. Instead of permanently installing it on a machine, you run it by booting a USB stick, It will run on almost any 64-bit Intel computer - I've run it on everything from an old "netbook" to a 27" iMac.

When Tails starts up, it connects to Tor, and then forces all network traffic to use Tor. This way, anything network traffic you generate within Tails (viewing web pages, reading email, sending messages, etc.) will appear to "come from" a random Tor exit node, somewhere around the world. In fact, different network connections will take different paths through the Tor network, and will appear to be in different parts of the world (so an email server might see you "from" Germany, a chat server might see you "from" Australia, and different web pages might see you "from" different countries as well.)

Persistent Storage

Tails runs from a USB stick, and does not get "installed" on the computer. It might have access to whatever hard disks happen to be in the computer, but you can run Tails on a machine which has no hard disks at all. (I know a few people who do this.)

Because some people may need to store files on a permanent basis, Tails offers a way to set up a "Persistent Storage" partition on the USB stick. Tails itself uses about 8 GB, if the USB stick is larger than this you can use the remainder of the USB stick as Persistent Storage.

Persistent Storage is stored in an encrypted partition on the USB stick. The encryption uses LUKS and DMCrypt, which are the standard system for Linux disk encryption.

When Tails first boots, the greeter (the first screen you see, where it asks about your language and keyboard formats) will check the USB stick to see if a Persistent Storage partition exists. If so, it will show an input field where you can enter its passphrase. If you enter the correct passphrase, it will unlock the partition and when you start Tails, the persistent files will "exist" where they were before.

Requirements

To run Tails, you will need a USB stick, 16 GB or larger. Tails itself will use part of this, and you can set the rest of it up as an encrypted "Persistent Storage" partition. This gives you a secure place to store files that you don't want to lose, such as the PGP secret key files you'll be storing on YubiKeys.

โ„น๏ธ You can install Tails on an 8 GB stick, but Tails itself takes up almost all of that, and there won't be enough room to set up a Persistent Storage partition. For the purposes of this book, the USB sticks need to be 16 GB or larger.

Most of my Tails sticks are 64 GB or larger. I have one 8 GB stick, which I normally use as a dedicated "Tails Installer" stick (although once in a while I use it for web browsing when I don't need Persistent Storage).

For this "book", we will be using a Tails stick with the Persistent Storage feature. The idea is, this will be the only place (other than the YubiKeys) where your secret key files will exist. Once you install the secret keys on the YubiKeys, you can lock this USB stick up in a vault in case you ever need it.

Notes

  • You should probably have more than one USB stick, so you can store secure backups in other locations. These backups will also have Tails on them, with their own encrypted Persistent Storage.

  • Make sure the USB sticks are made by a reputable manufacturer, such as Sandisk, PNY, or Kingston. There are a lot of "cheap" USB sticks out there from vendors with obviously made-up names (like "PomRee" or "BlimFang") that I wouldn't trust to copy files from one computer to another in the same room.

    There are also "fake" drives out there, which may claim to hold 512 GB but really only hold 32 GB, and there's no way to tell until you try to store more than 32 GB and it starts throwing I/O errors.

    Trust me, you do NOT want to lose your PGP secret key files because a cheap (or fake) USB stick failed when you needed it.

  • Make sure the USB sticks are "USB 3.0" or faster. You can run Tails from a USB-2 stick, but it will boot and run really slowly.

    If the machine where you plan to run Tails has USB-3 (or faster) ports, it is totally worth it to spend a few extra dollars and get USB sticks which can do USB-3. I'm looking at Amazon (on 2023-05-21) and the difference between USB-2 and USB-3 drives is only a dollar or two at the most - and some of the name-brand USB-3 sticks are less expensive than USB-2 sticks.

  • Be sure to plug the USB-3 stick into a USB-3 port. Otherwise it'll run at USB-2 speed, and you'll want to bang your head on the desk.

    I have a little Dell Inspiron 11-3162 "netbook" with both USB-2 and USB-3 ports, and I made this mistake exactly once. It took this little machine almost four minutes just to get to the initial Tails "Greeter" screen. After I moved the USB stick to a USB-3 port it booted up in about 45 seconds. Let's just say, now I know that the USB port on the left is USB-3 and the one on the right is USB-2.

    I don't understand why Dell chose to mix USB-3 and USB-2 ports on the same machine. Maybe they figured most people would plug a mouse into the right side and not need a high-speed port there, and wanted to save a few pennies on the cost of a USB controller chip?

Set up Tails

Setting up Tails involves downloading an image file, "burning" it to a USB stick, and booting a machine from that.

Before you dive in, make sure you have the following:

  • One or more USB sticks, 16 GB or larger. These will be erased, and when the process is done they will be dedicated to Tails.

  • A machine with a 64-bit Intel processor, which can boot from that USB stick. Tails does not work on 32-bit machines, or on Apple Silicon (or other CPU architectures).

    Note that the machine doesn't have to be one of your primary workstations. I have a little "netbook" that I keep around specifically for running "live" environments like this.

Install Tails

Tails already has their own documentation for how to do this, so rather than going into a whole lot of detail, I'll refer you there.

โ‡’ Tails - Install Tails

Installing Multiple Tails sticks

If you're making multiple Tails sticks, and the computer you're using has enough USB-3 ports, the easiest thing will be to download and create the first one, boot into that, and use the "Tails Installer" app within Tails to install the others. (Obviously, the computer will need enough USB ports for this.)

Directions for how to "Install Tails using Tails" are explained on the same "Install Tails" page linked above. See the links in the grey box just below the four green boxes at the top of the page. (This is based on what the site looks like on 2023-05-22, depending on when you're reading this the page may look different.)

Notes

  • The "Tails Installer" app will not set up a Persistent Storage partition on the USB stick where it installs Tails. You will need to boot into that Tails stick and set up Persistent storage there. (This is covered below.)

  • If the "source" Tails stick has a Persistent Storage partition, the "Tails Installer" app will not copy it. If you like, you can reboot that Tails stick and not unlock the Persistent Storage, so it can't copy it.

  • If the "target" Tails stick already has a Persistent Storage partition, the "Tails Installer" app will ask whether you want to just upgrade Tails on that stick (which will not touch that Persistent Storage partition), or fully wipe the USB stick and do a fresh installation of Tails (which will delete that Persistent Storage partition.)

Persistent Storage

Once you've created your Tails stick, the next step will be to configure "Persistent Storage". This creates an encrypted partition on the Tails stick and sets things up so that much of your "home directory" is actually stored there, so that the next time you boot that Tails stick (and unlock the storage), the files you had stored there will be there again.

If you're setting up multiple Tails sticks, you will need to boot into each one and do this process.

This Persistent Storage partition is going to be the only place where your PGP secret keys will exist "on disk".

The Persistent Storage feature has several features for which it can store data. I normally enable the following:

  • Persistent Folder - This is a generic directory called Persistent in the Tails user's home directory. You can use it to store any arbitrary files you like.
  • Network - This will remember your wifi passwords.
  • Tor Browser Bookmarks
  • Thunderbird Email Client
  • GnuPG - โš ๏ธ MAKE SURE THIS IS ENABLED. โš ๏ธ
  • SSH Client
  • Additional Software
  • Dotfiles

Feel free to enable whatever features you think you might use. Again, the important thing for this book is to enable GnuPG.

Like above, Tails already has their own documentation for how to do this, so I'll refer you there.

โ‡’ Tails - Persistent Storage

Backups

After your PGP keys have been created, it's a good idea to have one or more backups, in case your Tails stick is damaged, lost, or stolen. (I have three backups - one in a fire safe at home, one in a safety deposit box at the credit union, and one stored at the home of a family member in another part of the country.)

Again, here's the link to the official Tails documentation. ๐Ÿ˜Ž

โ‡’ Tails - Making a backup of your Persistent Storage

Set up PGP Key and YubiKey

Before you start, you will need to boot into Tails and make sure your persistent storage is active.

After that, the child pages will explain how to do the following:

  • Generate a PGP key pair
  • Add an authentication subkey
  • Export public keys
    • to public URL
    • to keyserver (need to configure keyserver first?)
    • to second USB stick?
    • email?
  • Write the secret keys to a Yubikey
    • also write URL for public key
    • also configure forcesig
  • Make sure the new key is backed up

Configure GnuPG

Once you're running under Tails with the Persistent Storage partition unlocked, there are a few GnuPG settings you should configure.

Key ID display format

This will make GnuPG show all keys as their full 160-bit fingerprints, rather than the 32- or 64-bit "short" versions.

This isn't technically required, however I recommend doing this. The chances of a collision (i.e. two different PGP keys which have, or appear to have, the same fingerprint) are much smaller when you're seeing the full fingerprint.

In $HOME/.gnupg/gpg.conf

  • Replace "keyid-format 0xlong" with "keyid-format none".

    # Display long key IDs
    #keyid-format 0xlong
    keyid-format none
    

    โ„น๏ธ At first glance this may seem strange, but this option controls how key IDs are displayed immediately after the algorithm (i.e. "rsa4096/0xDEADBEEF" vs "rsa4096/0xBADDF00DDEADBEEF"). The option below will make gpg show the full fingerprints, in a format without any extra spaces, so we don't need to see a "short version" of the Key ID.

  • Replace "with-fingerprint" with "with-subkey-fingerprint".

    # List all keys (or the specified ones) along with their fingerprints
    #with-fingerprint
    with-subkey-fingerprints
    

Old format:

pub   ed25519/0x5A6C4588132E97A6 2023-05-23 [C] [expires: 2024-01-01]
      Key fingerprint = 2A9E 767B A8BD E849 331B  4064 5A6C 4588 132E 97A6
uid                   [ultimate] Sample <please@dont-spam.us>
sub   ed25519/0x91EF268465FA9390 2023-05-23 [S] [expires: 2024-01-01]
sub   rsa4096/0xB17819416F1A3202 2023-05-23 [E] [expires: 2024-01-01]

New format:

pub   ed25519 2023-05-23 [C] [expires: 2024-01-01]
      2A9E767BA8BDE849331B40645A6C4588132E97A6
uid           [ultimate] Sample <please@dont-spam.us>
sub   ed25519 2023-05-23 [S] [expires: 2024-01-01]
      76581737ABBD19552BFC7D8D91EF268465FA9390
sub   rsa4096 2023-05-23 [E] [expires: 2024-01-01]
      57DAE100A563EDF02E3C71EAB17819416F1A3202

Keyserver

The PGP keyserver that Tails configures by default is a Tor "onion" address which connects to keys.openpgp.org. This keyserver allows keys to be uploaded, and other people can download them if they know the Key ID, but the keys are not "searchable" by name or email address until those identities are verified.

Generate a PGP key

There are thousands of web pages out there which explain how to generate a PGP key, in varying levels of detail. I'm not going to go into too much detail about how to do it, but I will briefly cover a few ways here - three methods use the command line, and one uses a GUI (which, to be honest, I don't recommend - at least not for creating keys.)

Passphrases

When you create a PGP key (or subkey), you will be asked to create a passphrase. This passphrase is used to encrypt the secret key, within the keychain files on disk. Using a strong passphrase means that if somebody manages to steal a copy of the keychain files from your workstation, the passphrase is the only thing keeping them from having access to your secret keys.

In this case, you may think that it's okay to use a weak (or no) passphrase, since the secret keys will only ever exist "on disk" within a Tails Persistent Storage partition. Resist that temptation. Having a passphrase on the secret key, plus the LUKS encryption of Tails Persistent Storage, is more secure than either one by itself.

Also, when you're creating sub-keys, it is possible to give sub-keys different passphrases than the primary key. This is a BAD IDEAโ„ข๏ธ, because the interface which asks you to enter passphrases doesn't do a very good job of explaining which passphrase (primary key, or which sub-key) it's looking for.

  • Using the same passphrase for the primary key and all subkeys will save yourself a lot of confusion.

  • When this is all done and you're using the YubiKey, you won't be entering this passphrase anyway - you'll be entering a PIN code for the YubiKey.

The KEYID shell variable

In the directions below, after generating a new key, there will be a step to save the Key ID in a shell variable. It will look something like this:

KEYID="xxxxxxxx"

This is because the directions in this book, after the key is generated, will use $KEYID to represent this value. If you save the Key ID to a variable like this, you will be able to literally type $KEYID where you see it in the commands, or you may be able to copy/paste the commands as-is. (Within the same shell where you saved the KEYID value, of course.)

The KEYID variable is not used or required by GnuPG, it's just something that I do when I'm working on keys to make my own life easier. There is no requirement to use this variable, I just find it saves some typing (or copy/pasting).

Command Line - "Quick" Options

The gpg command has options to generate keys and subkeys without being prompted. These options also allow you to specify an exact expiration date and time. (These are the options I normally use.)

Unlike the "normal" options, the quick options only generate one key or subkey at a time. This can be a bit more tedious, but it also makes it possible to build a PGP key exactly the way you want it.

Primary key

The gpg --quick-gen-key command will generate a new primary key with no subkeys.

amnesia@amnesia:~$ gpg --quick-gen-key 'Sample <please@dont-spam.us>' ed25519 cert 2024-01-01
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 0x5A6C4588132E97A6 marked as ultimately trusted
gpg: revocation certificate stored as '/home/amnesia/.gnupg/openpgp-revocs.d/2A9E767BA8BDE849331B40645A6C4588132E97A6.rev'
public and secret key created and signed.

pub   ed25519 2023-05-23 [C] [expires: 2024-01-01]
      2A9E767BA8BDE849331B40645A6C4588132E97A6
uid                      Sample <please@dont-spam.us>

amnesia@amnesia:~$

The "Key ID" is the "Key fingerprint" value, with no spaces. Save this to a shell variable, you will need it later in the directions.

KEYID="2A9E767BA8BDE849331B40645A6C4588132E97A6"

Also note the filename where the revocation certificate was stored, you will need it when you create backup files for the new key.

Signing subkey

On most "normal" PGP keys, the primary key has both [SC] flags, which means it can be used both for signing messages and certifying other PGP keys.

The command above used cert as the "usage" argument, so this primary key only has the [C] flag. This is because we are specifically creating a different subkey for signing messages, so we don't have to store the primary key on the YubiKey.

There are other advantages to creating a key this way, namely that if the signing key is compromised, we can revoke just that subkey and add a new one, without having to generate a whole new PGP key.

amnesia@amnesia:~$ gpg --quick-add-key $KEYID ed25519 sign 2024-01-01
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.
amnesia@amnesia:~$

As noted above, you should use the same passphrase here that you used for the primary key.

Encryption subkey

Then add the encryption subkey. Note that ed25519 keys cannot be used for encryption, so I'm using rsa4096 instead.

amnesia@amnesia:~$ gpg --quick-add-key $KEYID ed25519 encr 2024-01-01
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.
amnesia@amnesia:~$

As noted above, you should use the same passphrase here that you used for the primary key.

Command Line - Prompt for Everything

This command will prompt you for ALL options.

The only limitation is, you can't give it an explicit expiration date and time. You have to set the expiration date as "now plus something",

Example:

amnesia@amnesia:~$ gpg --full-gen-key
gpg (GnuPG) 2.2.27; Copyright (C) 2021 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.

gpg: keybox '/home/amnesia/.gnupg/pubring.kbx' created
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)
  (14) Existing key from card
Your selection? 1

โš ๏ธ The DSA algorithm is deprecated.

It is still being used, however it's being "phased out" and should not be used when creating new keys, unless you have a specific need to interact with systems using older versions of GnuPG or other PGP software.

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 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) 1y
Key expires at Wed 22 May 2024 01:06:28 PM UTC
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.

Real name: Fake Name
Email address: please@dont-spam.us
Comment: sample
You selected this USER-ID:
    "Fake Name (sample) <please@dont-spam.us>"

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.

When it finishes generating the primary key, it will pop up a window asking for a passphrase.

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.

When it finishes generating the encryption subkey, it will pop up another window asking for a passphrase. As noted above, you should use the same passphrase here that you used for the primary key.

gpg: /home/amnesia/.gnupg/trustdb.gpg: trustdb created
gpg: key 5C0FA82B7673184B marked as ultimately trusted
gpg: directory '/home/amnesia/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/amnesia/.gnupg/openpgp-revocs.d/48C991CBCFFE74BC9216C57D5C0FA82B7673184B.rev'
public and secret key created and signed.

pub   rsa4096 2023-05-23 [SC] [expires: 2024-05-22]
      48C991CBCFFE74BC9216C57D5C0FA82B7673184B
uid                      Fake Name (sample) <please@dont-spam.us>
sub   rsa4096 2023-05-23 [E] [expires: 2024-05-22]

amnesia@amnesia:~$

This command's output already includes the full Key ID as a single value. This makes it easier to save the Key ID to a shell variable.

KEYID="48C991CBCFFE74BC9216C57D5C0FA82B7673184B"

Also make a note of the filename where the revocation certificate was stored, you will need it when you create backup files for the new key.

Command Line - Super Simple

This only prompts you for your name and email, then uses default values for the encryption algorithms, key sizes, and expiration date.

There's nothing really wrong with keys generated this way, I just prefer to have more control over the properties of the key itself.

gpg --gen-key

At the moment (2023-05-22, Tails 5.13) the default values are:

  • Primary key: RSA-3072 with [SC] flags
  • Subkey: RSA-3072 with [E] flag
  • Both keys expire "two years from now"

Save the Key ID to a shell variable.

KEYID="5619B048F0714513369541C3386766684B12A817"

Also note the filename where the revocation certificate was stored, you will need it when you create backup files for the new key.

Kleopatra

Tails comes with a very basic PGP keyring manager called Kleopatra. It can perform many of the basic operations, but it's ... limited. In particular, it doesn't offer a way to add subkeys after a key is created.

I strongly recommend using the command line to create a key pair, but if you really want to use it, you will find it on the menu here:

โ‡’ Applications โ†’ Accessories โ†’ Kleopatra

Menu

When you run Kleopatra, it will show you a list of the keys in your keyring. Tails starts off with several PGP keys used by the Tails project itself. You should not delete these.

Generate a new key

โ‡’ File โ†’ New Key Pair... (Ctrl+N)

Choose Format

  • Create a personal OpenPGP key pair

Enter Details

  • Enter your name and email

  • If you click the "Advanced Settings" button

    • You can choose the algorithm and (for RSA) key size. Default is RSA-3072.

      โš ๏ธ The DSA algorithm is deprecated.

      Do not use it when creating new keys.

    • You can choose the key's capabilities. Default is "everything other than authentication", which is fine.

      โš ๏ธ Do not turn on "Authentication" here.

      If you do this, the generated key will have the [A] flag on the primary key, which is ... less than ideal? You don't want to use the primary key for anything other than certifying other keys if you can help it.

      Also, the next page in this book shows you how to add an authentication subkey.

    • You can manually choose the expiration date. Default is "two years from now".

    • Click "OK"

  • Click "Next >".

Review Parameters

  • This will show you a brief summary of the key you're about to create.

  • If you turn on the "Show all details" checkbox, it will show you more details.

  • Click "Create"

Enter a passphrase for the key, and enter the same passphrase again to verify that you've typed it correctly.

Once it finishes generating the key, it will show a window with the new key's fingerprint, and offer buttons to make a backup (of just the secret key), send the public key via email, or upload the public key to a key server.

Created

Highlight and copy the KEYID value from this window, and then in a command line window, create a KEYID shell variable.

KEYID="xxxxxxxx"

Back in Kleopatra, click "Finish" when you're finished.

List the key

amnesia@amnesia:~$ gpg -k $KEYID
pub   ed25519 2023-05-23 [C] [expires: 2024-01-01]
      2A9E767BA8BDE849331B40645A6C4588132E97A6
uid           [ultimate] Sample <please@dont-spam.us>
sub   ed25519 2023-05-23 [S] [expires: 2024-01-01]
      76581737ABBD19552BFC7D8D91EF268465FA9390
sub   rsa4096 2023-05-23 [E] [expires: 2024-01-01]
      57DAE100A563EDF02E3C71EAB17819416F1A3202

amnesia@amnesia:~$

Add an Authentication Subkey

This key will be used as

Get Key ID

If you don't already have it, get the primary Key ID of the new key.

gpg -k email@domain
  • long number immediately below pub line

Get the full Key ID, you will need it. It may help to save the Key ID to a shell variable.

KEYID="2A9E767BA8BDE849331B40645A6C4588132E97A6"

Add subkey

gpg --quick-add-key $KEYID rsa4096 auth 2024-01-01

Algorithm

  • rsa4096 - Use this in most cases.
  • ed25519 (newer) - Use this if you know that every device you'll need to SSH into, supports ed25519 SSH keys.
  • rsa2048 (older) - Use this if you'll need to SSH into devices which can't handle 4096-bit keys

Usage

  • auth

Expiration date

  • Use the same expiration date that you used when creating the primary key.
amnesia@amnesia:$ gpg --quick-add-key $KEYID rsa4096 auth 2024-01-01
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.
amnesia@amnesia:$

List key

Now when you list the key, you should see the [A] subkey.

amnesia@amnesia:~$ gpg -k $KEYID
pub   ed25519 2023-05-23 [C] [expires: 2024-01-01]
      2A9E767BA8BDE849331B40645A6C4588132E97A6
uid           [ultimate] Sample <please@dont-spam.us>
sub   ed25519 2023-05-23 [S] [expires: 2024-01-01]
      76581737ABBD19552BFC7D8D91EF268465FA9390
sub   rsa4096 2023-05-23 [E] [expires: 2024-01-01]
      57DAE100A563EDF02E3C71EAB17819416F1A3202
sub   rsa4096 2023-05-28 [A] [expires: 2024-01-01]
      4D645B49D8F7B625BFE2D98C5CC7D6A411BED246

amnesia@amnesia:~$

Export PGP Public Key

If you plan to use PGP for anything other than just SSH (i.e. to send and receive encrypted and/or signed messages, to digitally git commits, etc.) you will need to give your PGP public keys to other people, so they can use it to encrypt messages to you, and to verify signatures you have created.

Export to a file

$ gpg --export -a -o $KEYID.pub $KEYID

This will create a file called $KEYID.pub, containing the public key. The -a tells it to create an "ASCII-armored" file, meaning it will only use ASCII characters which can safely be sent via email. The filename doesn't necessarily have to have any specific name, however the normal convention is to use a name ending with ".pub" or ".pub.asc".

As an example of what the file looks like, here's my public key ...

$ cd /keybase/public/jms1/
$ cat E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB.pub.asc
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBFyT6EQBEADKXl/ss7pG15/rknrVSynsA9IlfNSrIPehmPerbvZfpv+hWgtO
hcizxTMUzPfe7P+jDuSyyVaKlFT8jSt2roOqOTtRbFr+jf0hQr+w1RbmqZvpgUON
KXFcY8xadqDdLn5s62IuCRoEyQsibz8buT0O7tarC2g8xtZeRoYX/iQYVykAuhYb
...
NG8yXw5ainqDMeu2xJZ6WfjT6GdYhRFvS77nBwp7GkyAmfnL84XDQ6/HkQIYI06I
YxJ7VnFtWXttjzC/NHAmAVoedptBq4GVdp1qvm7xH+y5ZaU6gaKDYbsbNdfGO+TI
VFq/JIjGQxRun4sieQC3upYfX3/xDHuKBZkwcyj37MN+wKeF+tdstuI=
=GgCy
-----END PGP PUBLIC KEY BLOCK-----

Send to a Keyserver

Tails pre-configures GnuPG to use the Tor "onion" address of keys.openpgp.org as its keyserver.

This keyserver allows keys to be uploaded, and other people can download them if they know the Key ID, but the keys are not "searchable" by name or email address until those identities are verified. (My own key is verified.)

Tails forces all network traffic to use Tor, so using a .onion address as a keyserver works just fine.

To send a key ...

amnesia@amnesia:~$ gpg --send-key $KEYID
gpg: sending key 5A6C4588132E97A6 to hkp://zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad.onion

I did send this key to the keyserver, and then downloaded it from the keyserver. This worked, however the key that I downloaded had been modified.

  • The identities had been removed, because the identity hasn't been verified.

  • The usage flags on the primary key appear to have been changed from [C] to [SCA]. I'm not sure why or how this happened.

Because of this, I'm not really happy with using this particular keyserver.

Change the keyserver

To use the same keyserver that GnuPG defaults to ...

  • Back up the existing GnuPG config files.

    amnesia@amnesia:~$ cd ~/.gnupg/
    amnesia@amnesia:~$ mkdir .dist
    amnesia@amnesia:~$ cp -av *.conf .dist/
    'dirmngr.conf' -> '.dist/dirmngr.conf'
    'gpg-agent.conf' -> '.dist/gpg-agent.conf'
    'gpg.conf' -> '.dist/gpg.conf'
    amnesia@amnesia:~$
    
  • Edit the dirmngr.conf file.

    I normally use nano, if you're more comfortable with some other editor (such as vi) then feel free to use that instead.

    amnesia@amnesia:~$ nano dirmngr.conf
    

    Find and comment out the existing keyserver line, and replace it with this:

    keyserver https://keyserver.ubuntu.com
    

    Save the changes.

  • Kill the dirmngr process. (The next time gpg needs it, it will start a new one, which will read the new config file.)

    amnesia@amnesia:~$ gpgconf --kill dirmngr
    
  • Send the key to the keyserver.

    amnesia@amnesia:~$ gpg --send-key $KEYID
    gpg: sending key 5A6C4588132E97A6 to https://keyserver.ubuntu.com
    
  • From another machine, visit https://keyserver.ubuntu.com/, enter the Key ID (in this case 5A6C4588132E97A6), and click the "Search Key"

Notes

Export ...

  • to file
    • exported public key file from backup
  • send to keyserver (need to configure keyserver first?)

Copy the file ...

  • to second USB stick?
  • send via email?
  • copy to SSH server?
  • other?

Load Keys into YubiKey

This page covers setting up the YubiKey and loading your PGP keys into it.

Initial Setup

These are things you should do when you start using a new YubiKey.

Reset the OpenPGP app

If you want to "erase" everything about OpenPGP from the YubiKey and "start fresh", you can reset the OpenPGP app. Doing this will erase any keys stored in the YubiKey, and reset the PINs back to their factory-original state (which are explained below.)

Note that this is the only way to recover if you have entered the wrong Admin PIN too many times and totally locked up the OpenPGP app.

Yubico's documentation explains how to reset the OpenPGP app. Rather than trying to copy it, I'll just point you there.

โ‡’ Resetting the OpenPGP Application on the YubiKey

Set PINs

If you have not already done so, you should set your own PIN and Admin PIN codes.

  • The PIN code is what you will use on a regular basis, to do things like generate signatures, decrypt messages, or perform SSH authentication. If somebody enters the wrong PIN code too many times, the OpenPGP app will lock itself, and you will need to use the Admin PIN code (or PUK code, if you set one) to "unlock" the PIN.

    โ„น๏ธ For a new (or newly reset) YubiKey, this is 123456.

  • The Admin PIN code is used to load PGP keys into the YubiKey, or to change the YubiKey's OpenPGP settings. It can also be used to unlock the PIN code after the wrong PIN was entered too many times.

    Note that it cannot be used to perform the day-to-day operations that you would normally use the PIN code for, and it cannot be used to "force-set" the PIN code. If you don't know the PIN code,

    โ„น๏ธ For a new (or newly reset) YubiKey, this is 12345678.

  • There is a third code, known as an "Reset Code". (You may also see the term "PUK code", which is the term used with the SIM cards used with GSM phones.)

    If this code is set, it can be used to "unlock" the PIN code after too many invalid attempts, without allowing access to change settings or load new keys.

    โ„น๏ธ For a new (or newly reset) YubiKey, this code is not set.

โ„น๏ธ These PINs only apply to the OpenPGP app.

If you use the same YubiKey for FIDO2, U2F, or PIV/CCID, and those systems require you to set up a PIN, they each have their own PINs which are totally separate from the PINs you use for OpenPGP.

Set Admin PIN

$ gpg --change-pin
gpg: OpenPGP card no. D27600012401xxxxxxxxxxxxxxxxxxxx detected

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 3

At this point your workstation will ask for the following, usually as separate prompts:

  • The current Admin PIN (it will probably just say "the Admin PIN").
  • The new Admin PIN.
  • The new Admin PIN again, to verify that you typed it correctly.
PIN changed.

Set PIN

Next, set the PIN you'll use on a regular basis in order to generate signatures, decrypt messages, or perform SSH authentication.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 1
  • Enter the current PIN.
  • Enter the new PIN.
  • Enter the new PIN again.

Note that if the current PIN was wrong, this command will fail, you will receive a "Error changing the PIN: Bad PIN" error, and the PIN failure counter will be updated. If you enter the wrong PIN too many times (usually 3, although this can be changed), the PIN will be "locked" and cannot be used without resetting it.

PIN changed.

Set a Reset Code

Once the PIN is set, you may want to set a Reset Code, but it isn't any less secure if you don't.

Personally I don't have one, but if I were managing YubiKeys for a company and might need to help a user who locked their YubiKey by entering the wrong PIN too many times, and they weren't able to physically bring the YubiKey to me, I would definitely want to be able to give them a code which unlocks their PIN without giving them full access to change everything on the card.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 4
  • Enter the Admin PIN (which you just set above).
  • Enter the new Reset Code.
  • Enter the new Reset Code again.
PIN changed.

โ„น๏ธ Using the Reset Code

If you ever lock your normal PIN and need to use the Reset Code to reset it, do the following:

  • gpg --card-edit
  • admin (to enable admin-level commands)
  • unblock

For the record, I've only ever done this once, while writing this documentation, to make sure it worked as advertised. It accepted the PUK and allowed me to set a new PIN, which also reset the "bad PIN" counter back to zero.

Finished

When you're finished setting the PIN codes, use "q" to finish.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? q

Personalize the Card

This section will involve storing information on the YubiKey which identifies you as the owner of the key.

$ gpg --card-edit

Enter some basic info about the "owner" of the card, along with their preferred language. This information is stored on the YubiKey, and will be visible to anybody who runs "gpg --card-info" or "gpg --card-edit" while the YubiKey is plugged in.

gpg/card> name
Cardholder's surname: Simpson
Cardholder's given name: John

gpg/card> login
Login data (account name): j..1@j....net

gpg/card> lang
Language preferences: en

You can also enter a URL where the corresponding public key can be downloaded. Doing this allows you to use the "gpg --edit-card" command's "fetch" sub-command to load your public keys into a new computer's keyring. PGPCards only hold secret keys - they don't hold public keys, user IDs, signatures, or expiration dates.

This is not required. If you don't have, or don't want, a copy of your public key saved on a web site somewhere, feel free to skip this step.

gpg/card> url
URL to retrieve public key: https://jms1.pub/jms1.pub.asc

You can also set a flag which tells the YubiKey to require the PIN to be entered, every time a signature is generated. Without this, you will be asked for the PIN the first time you generate one, and the YubiKey will "stay unlocked" and generate more signatures as requested, until it is unplugged from the computer.

gpg/card> forcesig

To see the updated state of the card, just hit RETURN at the "gpg/card>" prompt.

gpg/card>

Reader ...........: Yubico Yubikey 4 OTP U2F CCID
Application ID ...: D27600012401xxxxxxxxxxxxxxxxxxxx
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 06940447
Name of cardholder: John Simpson
Language prefs ...: en
Sex ..............: unspecified
URL of public key : https://jms1.pub/jms1.pub.asc
Login data .......: j..1@j....net
Signature PIN ....: forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]

When you're happy with the settings, use "q" to exit the "gpg --card-edit" command.

gpg/card> q

Remove and re-insert the Yubikey.

From this point forward, you will need to enter the PIN in order to make use of any keys, and you will need to enter the Admin PIN in order to load keys or change settings.

Load secret keys

The YubiKey's OpenPGP app has three "slots", each of which can hold the secret half of a PGP key or subkey. The slots are intended for keys with the Signature, Encryption, and Authentication flags. Be sure the keys you load into each slot have the appropriate capability flag (i.e. if a subkey only has the [E] capability, don't load it into a slot other than the Encryption slot).

Which keys need to be sent?

If you only plan to use the YubiKey for SSH, you only need to load an Authentication key on the YubiKey. If you also plan to use the YubiKey for other PGP operations, you should load encryption and signature keys as well.

How do you clear the key from a slot?

I'm only aware of two ways to do this.

  • Load a different key into the same slot, which overwrites whatever key is currently there.

  • Reset the OpenPGP app. This clears all of the slots.

    Of course, you then have to set everything up from scratch again. I've done this several times, once you're used to it the longest part of the process is waiting for Tails to finish booting on that ancient netbook with the world's slowest supposedly USB-3 port... ๐Ÿ˜’

Open the PGP key

Use "gpg --edit-key" to work with the key.

$ gpg --edit-key 6353320118E1DEA2F38EAE806B2EDC90B5C6DC30
gpg (GnuPG/MacGPG2) 2.2.0; Copyright (C) 2017 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.

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <j..1@v......com>
[ultimate] (2)  John M. Simpson <j..1@j....net>

gpg>

We will be using the key command below to select or de-select subkeys. This command toggles the selection status of a subkey.

  • Each subkey is "numbered", although the numbers are not shown. Entering "key 1" will toggle the asterisk on the first "ssb" entry, and so forth.

  • It is possible to have multiple subkeys selected at the same time, however only one key or subkey can be selected when sending them to the YubiKey.

  • If no subkeys are selected (as in the example above), the primary key will be considered as selected, even though it will not have an asterisk after the "sec" label.

Be very careful about which key or subkey is selected when sending keys to the YubiKey.

Load the Authentication key

Make sure the Authentication subkey (the one with "usage: A") is the only one selected.

gpg>

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <j..1@v......com>
[ultimate] (2)  John M. Simpson <j..1@j....net>

gpg> key 2

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb* rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <j..1@v......com>
[ultimate] (2)  John M. Simpson <j..1@j....net>

gpg>

As you can see, there is now an asterisk next to the second subkey, which has the "A" capability, and there are no asterisks on any other subkeys.

Send the selected sub-key to the Authentication slot on the Yubikey (or the "card", as gpg calls it.)

gpg> keytocard
Please select where to store the key:
   (3) Authentication key
Your selection? 3

gpg>

Load the encryption key

In this case, we want to send the subkey with the "E" capability, so first turn off the asterisk on the authentication subkey, then turn on the asterisk on the encryption subkey.

gpg>

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb* rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <j..1@v......com>
[ultimate] (2)  John M. Simpson <j..1@j....net>

gpg> key 2

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <j..1@v......com>
[ultimate] (2)  John M. Simpson <j..1@j....net>

gpg > key 1

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb* rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <j..1@v......com>
[ultimate] (2)  John M. Simpson <j..1@j....net>

gpg>

Next, send the key to the card.

gpg> keytocard
Please select where to store the key:
   (2) Encryption key
Your selection? 2

gpg>

Load the signature key

For this key, you're going to need a key or subkey with the "S" capability.

  • In most cases, the primary key will be the only one with the "S" capability. If so, use the key command to make sure that NO subkeys have an asterisk next to them. (The example below shows this.)

  • If you have a separate signing subkey, make sure that key is selected.

gpg>

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb* rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <j..1@v......com>
[ultimate] (2)  John M. Simpson <j..1@j....net>

gpg > key 1

sec  rsa4096/0x6B2EDC90B5C6DC30
     created: 2017-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/0x297E5961AB566594
     created: 2017-05-27  expires: never       usage: E
ssb  rsa4096/0xBA6C2A169C6C0F60
     created: 2017-11-10  expires: never       usage: A
[ultimate] (1). John M. Simpson <j..1@v......com>
[ultimate] (2)  John M. Simpson <j..1@j....net>

gpg>

Send the key to the YubiKey.

gpg> keytocard
Really move the primary key? (y/N) y
Please select where to store the key:
   (1) Signature key
   (3) Authentication key
Your selection? 1

gpg>

Exit

Technically we're finished, BUT ... we need to be careful.

This next command will quit out of the "gpg --card-edit" command, and it will ask if you want to save changes. IF YOU SAY YES, the secret keys you just installed on the YubiKey will be REMOVED from the secret keyring files on the computer.

Unless you are 100% sure that's what you want to do (i.e. if you have a known-good backup of the secret keys), BE SURE TO SAY NO.

gpg> q
Save changes? (y/N) n
Quit without saving? (y/N) y

Now if you query the card, you will see the keys in the three slots.

$ gpg --card-status

Reader ...........: Yubico Yubikey 4 OTP U2F CCID
Application ID ...: D27600012401xxxxxxxxxxxxxxxxxxxx
Version ..........: 2.1
Manufacturer .....: Yubico
Serial number ....: 06940447
Name of cardholder: John Simpson
Language prefs ...: en
Sex ..............: unspecified
URL of public key : https://jms1.net/6B2EDC90B5C6DC30.pub.asc
Login data .......: j..1@j....net
Signature PIN ....: not forced
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
Signature key ....: 6353 3201 18E1 DEA2 F38E  AE80 6B2E DC90 B5C6 DC30
      created ....: 2017-05-27 22:28:31
Encryption key....: 0660 766F 2768 F41F D4B9  1DB7 297E 5961 AB56 6594
      created ....: 2017-05-27 22:28:31
Authentication key: BBA5 C6BB 23D2 B53B 0D0F  6C0B BA6C 2A16 9C6C 0F60
      created ....: 2017-11-10 23:29:14
General key info..: pub  rsa4096/0x6B2EDC90B5C6DC30 2017-05-27 John M. Simpson <j..1@v......com>
sec   rsa4096/0x6B2EDC90B5C6DC30  created: 2017-05-27  expires: never
ssb   rsa4096/0x297E5961AB566594  created: 2017-05-27  expires: never
ssb   rsa4096/0xBA6C2A169C6C0F60  created: 2017-11-10  expires: never

Note that the information under "General key info" is coming from the keyring files on your computer. If you run "gpg --card-status" on a computer whose keyring doesn't have your file yet, the last line will be ...

General key info..: [none]

Back up the new PGP key

Once your PGP key and subkeys have been created, you NEED to make one or more backups of the key.

Backup the Tails stick

The easiest and most obvious way is to make a backup of your Tails stick. This way if something happens to your primary Tails stick, you can boot the backup just like you did with the primary, and make a new backup from there if needed.

โ‡’ Making a backup of your Persistent Storage.

Export to files

Another option, which you can do if you're not using Tails, is to export the public and secret keys, and a revocation certificate, and store them somewhere safe. This could mean another USB stick (preferably encrypted, but definitely not physically accessible to others). It could also mean a directory under /keybase/private/YOURNAME/.

Personally, I have a backup of my Tails stick stored in a fire safe at home, an encrypted USB stick in a safety deposit box at the credit union, and another encrypted USB stick in the fire safe of a family member in another part of the country.

Public Keys

If you exported your public key in order to send to other people, this is exactly the same operation. Feel free to copy that file into your backup location.

For the purposes of this section, I'm going to assume that you're using Tails, and are backing up the key files to the /home/amnesia/Persistent/gpg-backup/ directory.

$ mkdir -p ~/Persistent/gpg-backup/$KEYID
$ cd ~/Persistent/gpg-backup/$KEYID

Once you're in this directory, export the public key to a file.

$ gpg --export -a -o $KEYID.pub.asc $KEYID

โ„น๏ธ This file can be freely shared with the world, and in fact you will probably end up doing this at some point.

Secret Keys

When you export a secret key, the exported file will still be protected using the passphrase. This can be a problem if, two years from now when you need to restore from that backup, you've also forgotten what the passphrase was.

There are two solutions to this:

  • Store the passphrase in a text file with the exported secret key files.

    Be very careful if you do this, especially if you're using the same passphrase for other things (including other PGP keys). If somebody manages to get your backed-up files, not only would they have this PGP key, they would also have access to everything else you may be protecting with that passphrase.

    If you're going to do this, skip over the "Remove the passphrase" and "Add the passphrase again" sections below, and only use the "Export the secret keys" section.

  • Remove the passphrase before exporting the key, and then add the passphrase again afterward.

I normally remove the passphrase before exporting secret keys. I figure storing the passphrase with the secret key is just as insecure as not having a passphrase, and when/if the time comes that I need to restore the secret key, not having to deal with a passphrase will just make things a little bit easier at that time.

Remove the passphrase

Removing a passphrase is just changing the passphrase to an empty value.

$ gpg --edit-key $KEYID
...
gpg> passwd

Pay attention to what each "pinentry" prompt is asking you.

  • The FIRST password prompt will need the current passphrase.

  • For all of the remaining password prompts, don't enter a password.

  • When it asks (a few times) if you're really sure you want to do that, obviously say yes.

gpg> q

Export the secret keys

$ gpg --export-secret-key -a -o $KEYID.sec.asc $KEYID

If you've removed the passphrase, this will not ask for a passphrase, it will just create the output file.

๐Ÿ›‘ These files should not be shared with ANYONE.

Obviously.

Add the passphrase again

$ gpg --edit-key $KEYID
...
gpg> passwd

This is just like before, but "in reverse". And where the current password is empty, it won't ask you to enter it - it'll just ask for the new password, once for the primary key and once for each subkey.

๐Ÿ›‘ BE VERY CAREFUL to enter the same password for all of them.

It is possible to have different passwords for each key or subkey, but things get really confusing if you do that.

Revocation Certificate

Every backup should include a copy of a revocation certificate.

When you first created the primary key, there should have been a line like this in the output:

gpg: revocation certificate stored as '/home/amnesia/.gnupg/openpgp-revocs.d/0123456789ABCDEF0123456789ABCDEF01234567.rev'

If so, copy this file into the backup.

$ cp /home/amnesia/.gnupg/openpgp-revocs.d/$KEYID.rev .

Otherwise, we need to generate a new revocation certificate. This one is just going to sit there in the backup in case it's ever needed, so we're not going to enter a reason.

$ gpg --gen-revoke -o $KEYID.rev.asc $KEYID

sec  rsa4096/7EC2200541FD4588 2023-05-06 derp

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? 0
Enter an optional description; end it with an empty line:
>
Reason for revocation: No reason specified
(No description given)
Is this okay? (y/N) y
ASCII armored output forced.
Revocation certificate created.

Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable.  But have some caution:  The print system of
your machine might store the data and make it available to others!

Sharing a Revocation Certificate

This file should not be shared with the world at large. However, should think about giving a copy to somebody that you really trust, with instructions to share it with the world if something happens and you're no longer around.

Things to consider ...

  • The person you trust with the revocation certificate will be able to share it with the world. They will not be able to decrypt or sign messages.

  • If something happens and you're no longer around, you probably want the revocation certificate to be sent out, so that people who have your public key will know not to use it anymore.

  • If anybody imports the revocation certificate, and then shares your public key, the "revoked" status will also be shared.

  • Even better (or worse?), if somebody uploads your now-revoked public key to a keyserver, the "revoked" status will permanently be in that keyserver. And if that keyserver synchronizes with other keyservers, they will all consider the key to be revoked. And anybody who downloads or updates the public key from those keyservers, will also consider the key to be revoked.

You want your friend to have access to it so they can share it, but you also need to trust them not to share it unless you're not around anymore.

Copying the files

Once you have these files, you need to send them "out of Tails". There are a few ways to do this.

Keybase

It's not the easiest thing in the world, but it is possible to run Keybase within Tails. At some point I plan to make a "book" like this one, but for now I have a one-page document with notes about how to do it.

โ‡’ /keybase/public/jms1/notes/Tails/Keybase on Tails.md

If you are running Keybase on Tails, create a directory under /keybase/private/YOURNAME/ and copy the files there.

Encrypted USB stick

If the only computers which will need to access the encrypted USB stick are running Linux (including Tails), you can encrypt it using LUKS.

โ‡’ Tails - Creating and using LUKS encrypted volumes

If other operating systems will need to access the encrypted USB stick, you'll need to use VeraCrypt instead. VeraCrypt is available for Linux, macOS, and windows. It's a fork of an earlier system called TrueCrypt, which is no longer maintained.

Tails comes with software which can open existing VeraCrypt volumes, but it cannot create them. You will need to create an encrypted volume using VeraCrypt on another system, and then mount that volume under Tails.

โ‡’ Tails - Using VeraCrypt encrypted volumes

Whether you're using LUKS or VeraCrypt, the overall process is the same ...

  • Mount the encrypted USB stick. (This is covered by the Tails documentation linked above.)

  • Copy the files into the encrypted USB stick.

    I recommend creating a directory within the encrypted USB stick, to keep these files together and to keep them separate from other things you may wish to store.

  • Un-mount the encrypted USB stick. (This is covered by the Tails documentation linked above.)

SSH

This obviously depends on having a machine that you can SSH into.

Creating an encrypted tarball

To do this, we're going to create a PGP-encrypted message containing a ZIP file.

Before we can do this ... Tails doesn't come with the zip command installed, so we'll need to install it first.

$ sudo apt update
...
$ sudo apt install zip

If you turned on the "Additional Software" item when configuring Persistent Storage, you will get a pop-up message asking whether you want to "Install Only Once", or "Install Every Time" you boot Tails. Either way, it's up to you.

Once the command is installed, you can create the PGP-encrypted ZIP file like so ...

$ cd ~/Persistent/gpg-backup/$KEYID/
$ zip -9 - $KEYID.* | gpg -ear RECIPIENT -o newkey.zip.asc
  • RECIPIENT is the identity of whoever needs to be able to decrypt the file. This can be a Key ID, or it can be a name or email, if the keyring only has a single key matching.

    You can use gpg -k RECIPIENT before creating the tarball if you need to verify that the keyring only has one matching key.

This will create a file called newkey.zip.asc, containing the message. If you look at the file, you will see that it starts with "-----BEGIN PGP MESSAGE-----", and contains a big block of random-looking characters.

This file can safely be sent via SSH, email, chat, or any other method. It can only be decrypted by RECIPIENT.

Sending the file

Copy the file using the scp command, like you would any other file.

$ scp newkey.txt hostname.server.xyz:

Email

See above for directions on how to create a PGP-encrypted message containing a tarball of the key files.

Assuming you followed those directions, and you have Thunderbird set up to send and receive email, you can email the newkey.zip.asc file to yourself.

Set up Workstation

Install and Configure GnuPG

This page will cover installing and configuring the GnuPG software.

Install GnuPG

macOS

Only one GnuPG

A lot of the problems I've seen people have with using GnuPG on macOS are caused by having multiple GnuPG programs installed on the machine at the same time.

I normally use Homebrew (see below) on every machine, and some of the packages I normally install have gnupg as a dependency. Homebrew usually ends up installing it anyway, so I have found it easier to just install GnuPG via Homebrew.

The most common "other" GnuPG installation is GPGTools (also knows as "MacGPG", "MacPGP", etc.) This distribution includes some GUI tools for managing keyrings, a System Preferences widget to configure the gpg command, and a non-free plug-in which handles PGP operations within Mail.app (to make it easier to send and received signed and encrypted emails).

The problems people have with multiple instances of gpg are usually caused by the directories in PATH being in different orders for different processes. Even if you've taken the time to lovingly hand-craft your free-range organic .bashrc (or .zshrc) file so it always puts the directories in a certain order, the fact is that not every process on the machine is going to use the shell-rc files from your home directory.

The only way I've found to ensure that every process on the machine uses the same gpg program, is to make sure the machine only has one gpg program to begin with.

The directions in this book were written using GnuPG installed by Homebrew. They will probably work with the GPGTools version of gpg, however I haven't tried it myself - I haven't used GPGTools in several years (i.e. since I discovered Homebrew).

If you already have GPGTools installed and want to use the Homebrew version instead, start by using the directions on this page to uninstall GPGTools.

โ‡’ Uninstall GPGTools

Uninstalling GPGTools will not affect the contents of your keyring files, although you may have to go through the config files in your $HOME/.gnupg/ directory and change a few paths after installing the Homebrew packages (this is covered below).

Homebrew

Homebrew describes itself as "The Missing Package Manager for macOS", and IMHO this is a pretty accurate statement. It provides a way to easily install most of the open-source packages commonly available for Linux, using a command line interface similar to the yum, apt, or pacman commands you would have on a Linux system.

I usually end up needing Homebrew on every macOS machine anyway, so I've gotten into the habit of just installing it on all of my machines.

Homebrew's web site has directions for how to install it. (It's easy, just copy and paste one command from the web page into your shell.)

โ‡’ Homebrew

Check your PATH

Once Homebrew is installed, open a new Terminal window and make sure the directory where Homebrew installs things, is listed in your PATH. This will normally be /usr/local/bin for Intel machines, or /opt/homebrew/bin for ARM (Apple Silicon) machines.

$ which brew
/opt/homebrew/bin/brew
$ echo "$PATH" | tr : '\n' | grep $( brew --prefix )
/opt/homebrew/bin

If you find that you need to update your .bashrc or .zshrc file to make sure the Homebrew path is in the right order, now is the time to do that.

Install gnupg and pinentry-mac

Once Homebrew is installed, this command will install GnuPG and the "PIN entry" program you'll need in order to securely enter passphrases under macOS.

brew install gnupg pinentry-mac

Once it's installed, you can run "gpg --version" to see what version you're running.

(jms1@jms1Air) 29 ~ $ gpg --version
gpg (GnuPG) 2.4.0
libgcrypt 1.10.2
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /Users/jms1/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

Linux - Debian 11

This command will install GnuPG. Once of its dependencies will be pinentry-curses, which provides a "PIN entry" program that uses a terminal window to prompt you for passphrases.

apt install gnupg2

Once it's installed, you can run "gpg --version" to see what version you're running.

root@a4a47a903855:/# gpg --version
gpg (GnuPG) 2.2.27
libgcrypt 1.8.8
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /root/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

Note that the terminal-mode pinentry program requires you to set up a GPG_TTY environment variable, so that it knows where to show the prompt. You may want to add the following to your .bashrc file.

export GPG_TTY=$( tty )
gpg-connect-agent updatestartuptty /bye > /dev/null

Linux - CentOS 7

CentOS 7 normally installs GnuPG2 on every machine. You can verify whether it's already installed or not ...

[root@0e0ef5dcbfcf /]# rpm -q gnupg2 pinentry
gnupg2-2.0.22-5.el7_5.aarch64
pinentry-0.8.1-17.el7.aarch64

If it isn't installed, you can run this to install it.

yum install gnupg2 pinentry

Once it's installed, you can run "gpg --version" to see what version you're running.

[root@0e0ef5dcbfcf /]# gpg --version
gpg (GnuPG) 2.0.22
libgcrypt 1.5.3
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: ~/.gnupg
Supported algorithms:
Pubkey: RSA, ?, ?, ELG, DSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

โ„น๏ธ The GnuPG version in the CentOS 7 repos is rather old.

Some of the configuration options mentioned below may not work.

As with Debian, the terminal-mode pinentry program requires you to set up a GPG_TTY environment variable, so that it knows where to show the prompt. You may want to add the following to your .bashrc file.

export GPG_TTY=$( tty )
gpg-connect-agent updatestartuptty /bye > /dev/null

Configure GnuPG

The GnuPG software is configured using files in each user's $HOME/.gnupg/ directory. There are two ways to update these files: using the gpgconf command, and manually editing the files.

In many versions of GnuPG, the gpgconf command doesn't recognize many of the options that can exist in the config files, so I normally edit the files by hand.

$HOME/.gnupg/gpg.conf

This file configures the gpg command itself.

Configure a default signing key

If you already have one or more PGP keys, once they're imported into your keyring you can choose one to be the default key, which will automatically be used when creating signatures.

This option normally uses a Key ID, however it can also take a name, as long as the name is unique within your keyring.

default-key     E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB

Some gpg commands print a copyright message when they start. This option disables that notice.

no-greeting

Key ID display

  • This option will make gpg commands which show keys, show the full key fingerprints of the primary and sub-keys.

    with-subkey-fingerprint
    
  • This option will make gpg commands not include a shortened version of the fingerprint when printing the algorithm (i.e. rsa4096 instead of rsa4096/B4422EBB).

    keyid-format    none
    

Together, they make the output look like this:

$ curl -s https://jms1.pub/jms1.pub.asc | gpg --show-key
pub   rsa4096 2019-03-21 [SC] [expires: 2024-01-01]
      E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB
uid                      John Simpson <jms1@jms1.net>
uid                      John Simpson <kg4zow@mac.com>
uid                      John Simpson <kg4zow@kg4zow.us>
sub   rsa4096 2019-03-21 [E] [expires: 2024-01-01]
      3C8EC9C7B067A4C542F9727D795C2CF824364755
sub   rsa4096 2019-03-21 [S] [expires: 2024-01-01]
      77DEBB0C8C7FBAFF1E0E70DCE9E44ED30E2F2445
sub   rsa4096 2019-03-21 [A] [expires: 2024-01-01]
      7A6B95B6BF897A6497165AE436823233F8D09EB7

$HOME/.gnupg/gpg-agent.conf

Configure the "PIN entry" program

When gpg-agent needs to read a secret key from the keyring, it will need to ask the user to enter their passphrase. It does this by running a "PIN entry" program. There are different "PIN entry" programs out there - some work by opening a GUI dialog, some work by clearing the terminal window and "drawing" what looks like a dialog, and others may use other methods.

You need to configure gpg-agent and tell it what program to use to ask the user for the key's passphrase.

macOS - Homebrew

To use the pinentry-mac program installed by Homebrew, first find the full path to the pinentry-mac program ...

$ which -a pinentry-mac
/opt/homebrew/bin/pinentry-mac

Then edit (or create) the gpg-agent.conf file and add this line:

pinentry-program /opt/homebrew/bin/pinentry-mac

Configure secret key retention time

GnuPG uses a program called gpg-agent to hold secret keys in memory for a certain length of time. This means if you're going to be executing multiple gpg commands which require the same key, you won't have to enter the key's passphrase over and over again.

You can configure how long gpg-agent will remember the keys before deleting them from memory. (The values are in seconds.)

  • default-cache-ttl = how long keys will be held in memory before being removed. Every time a key is used, the key's "timer" is reset. Default is 600 (ten minutes). I normally use 10-30 seconds.

  • max-cache-ttl = maximum length of time that any key will be held in memory, even if it has been used recently. Default is 7200 (two hours).

default-cache-ttl       30
max-cache-ttl           30

โ„น๏ธ These settings only affect secret keys read from the disk.

Secret keys stored in a YubiKey are never sent to the computer, so gpg-agent cannot hold them in memory.

Configure the SSH agent

The gpg-agent program can "speak the same language" as ssh-agent.

Add this option to enable support for SSH.

enable-ssh-support

When gpg-agent is working with SSH secret keys, it can also hold them in memory for a certain length of time, like it does with PGP keys. You can configure how long it holds these keys using these options. (These values are also in seconds.)

  • default-cache-ttl-ssh = how long SSH keys will be held in memory before being removed. Each time a key is used, the key's "timer" is reset. Default is 1800 (half an hour).

  • max-cache-ttl-ssh = maximum length of time that any key will be held in memory, even if it has been used recently. Default is 7200 (two hours).

default-cache-ttl-ssh   0
max-cache-ttl-ssh       0

โ„น๏ธ These settings only affect SSH secret keys read from the disk.

Secret keys stored in a YubiKey are never sent to the computer, so gpg-agent cannot hold them in memory.

Restart gpg-agent

If you made any changes to the gpg-agent.conf file, you need to restart the gpg-agent process.

$ gpg-connect-agent killagent /bye
OK closing connection
$ gpg-connect-agent /bye
gpg-connect-agent: no running gpg-agent - starting '/opt/homebrew/Cellar/gnupg/2.4.0/bin/gpg-agent'
gpg-connect-agent: waiting for the agent to come up ... (5s)
gpg-connect-agent: connection to the agent established

Make ssh use gpg-agent

macOS

Make sure the SSH_AUTH_SOCK environment variable was set when you logged into the computer.

$ echo $SSH_AUTH_SOCK
/private/tmp/com.apple.launchd.6WLhL9ld6F/Listeners

This path will be different every time you (log in? reboot? not sure), and this value will be inherited by every process which is part of your desktop environment. This includes all of the shells in your terminal windows, any programs you run by double-clicking something from a Finder window, and so forth.

When you log in, the system creates a Unix socket with a random name, runs a copy of ssh-agent and makes it listen on that Unix socket.

Switch the socket

What we're going to do is remove that Unix socket, and create a symbolic link in its place, pointing to the Unix socket where gpg-agent is listening.

ln -sf $HOME/.gnupg/S.gpg-agent.ssh $SSH_AUTH_SOCKET

Once you do this, if any process under your login session needs to talk to ssh-agent, it will actually be talking to gpg-agent instead.

The only problems with this are ...

  • Any programs which try to make use of ssh-agent before you do this, will still be talking to the real ssh-agent (which macOS has no way to totally disable).

  • You have to remember to do this every time you log in.

Switch the socket automatically

You can make the system replace the socket with the symlink automatically by creating a "LaunchAgent". These are programs which launchd automatically runs when you log in.

Create $HOME/Library/LaunchAgents/net.jms1.gpg-agent-symlink.plist with the following contents:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/ProperyList-1.0/dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>net.jms1.gpg-agent-symlink</string>
    <key>ProgramArguments</key>
    <array>
      <string>/bin/sh</string>
      <string>-c</string>
      <string>/bin/ln -sf $HOME/.gnupg/S.gpg-agent.ssh $SSH_AUTH_SOCK</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>

If you're using Keybase, you can copy this file.

cd ~/Library/LaunchAgents/
cp /keybase/public/jms1/net.jms1.gpg-agent-symlink.plist .

If not, you can download this file. (Note: the curl option is an uppercase letter "O", not a digit "zero".)

cd ~/Library/Launchagents/
curl -O https://jms1.pub/net.jms1.gpg-agent-symlink.plist

When you create this file, you may get a pop-up notification from macOS.

background-item

This is expected, and can be ignored.

โ„น๏ธ It's unfortunate that macOS only identifies the item as "sh". If you look in Settings โ‡’ General โ‡’ Login Items, you will see the item identified as just "sh". And you may see other items identified as just "sh" as well, with no way to tell which one is which.

I've tried to figure out how to give it a different name, but there doesn't seem to be any documentation about how to control the name. If I find out any more about this, I'll update this page.

After creating this file, tell launchd to run it, and to run it automatically every time you log in.

launchctl load net.jms1.gpg-agent-symlink.plist

Debian 11

TODO

CentOS 7

TODO

Import PGP Public Key

If you using a new machine that you plan to use on a regular basis, you may want to add your PGP public key to the machine's keyring. One reason you might want to do this is so you can then export the authentication subkey as an SSH public key. (This is explained on the Export SSH Public Key page.)

Importing keys is done using the "gpg --import" command.

The examples below all show the results as "unchanged", because the computer where I ran the commands already had my key in the keyring.

Import from a file

If you have a copy of your public key, you can import that file directly.

$ gpg --import jms1.pub.asc
gpg: key 49B9FD3BB4422EBB: "John Simpson <j..1@j....net>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

Import via download

If you have a copy of your public key on a public web server, you can download and import it in a single command, like so.

$ curl -s https://jms1.pub/jms1.pub.asc | gpg --import
gpg: key 49B9FD3BB4422EBB: "John Simpson <j..1@j....net>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

Import via fetch

If you stored a URL for your public key when setting up your YubiKey, gpg can download and import the key from that URL automatically.

Run "gpg --card-edit", and use the fetch command.

$ gpg --card-edit
...
URL of public key : https://jms1.pub/jms1.pub.asc
...

gpg/card> fetch
gpg: requesting key from 'https://jms1.pub/jms1.pub.asc'
gpg: key 49B9FD3BB4422EBB: "John Simpson <jms1@jms1.net>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

gpg/card> q

Export SSH Public Key

For every machine that you'll need to SSH into, you will need to install your SSH public key. Normally this would be a file with a name like "id_rsa.pub", however because the key is actually a PGP subkey, that file doesn't exist.

There are two ways to "extract" an SSH public key from a PGP authentication subkey.

Using "ssh-add -L"

This is the easy way.

While the YubiKey is plugged in, run "ssh-add -L" and it will print the public keys for every secret key known to your "SSH agent" (which in our case is actually gpg-agent).

$ ssh-add -L
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDhVIFZFwb0EoFsKRUrp0LTra3w6F06H2SLnE2NqQ0N
LFm1vtXPey9byXnKsxaWnMdqzPCrgUQypA1pIl1IYzmjdH/UO9H0bW3fxg/9+YyT1u9bl2TdVw8yZb30
/A0qV6ddOylWC42pFeEKOhzEFSU6PXiaJE2zNhOfmAcqB0r6mhTuQ5a754UMYu8254Bh1XUbEXm/Tpt7
K+1xIs4dTIVerL+7U55husgoMQ2HB6DcGSzfqpBwon208ll8ERhxkIBpwVKPfC1eJeyiuUgJOVp69O+r
TnPQ/oYzzX1kXCSfdOpBDZpu9oCQPAtRwjF9YfX7AK645qF4ua17cPRYmFTTa9d65E+VfGIbhgD0zpfM
6rnLU+XeZV3jqegxzphl7xNX2vOOlNYTDBGD7+izQV9a5AehoPkZ3MIM5JNzfzK3uEFduyD2L9RLJ3Tl
s2uCYOe7TjRfasbvY/rzgn3LAnF2nX3l46ckgsxJk9m2duvmHdsLYBzGMpnWOlzE+CWHnvdewhoUTXe4
fR0pkd5a7josJm5giBtUNgrUC4JevV5yWU2SY+5u0mePeaQLWjKW3vroZpmM1jPpYDcU4xL7JqJJzltb
bL90TAvlKXGRJXEt9t46SfulTGURp9n5yDP2xS8yapdI6NvFW/5bV5rEgltYwgi+evwOVnvi1eTUAkjI
Pw== cardno:12_345_678

The "cardno:12_345_678" at the end is a comment, and can be changed when adding the file to an authorized_keys file. I normally give my public keys comments like "j..1@j....net 2019-03-21 YubiKey Blue" instead of the serial number, so that if an authorized_keys file contains multiple lines, I can tell which one is which. (This particular key is stored on a YubiKey with blue stickers on the front and back.)

For example ...

$ cd ~/.ssh/
$ ssh-add -L >> id_rsa.pub
$ nano id_rsa.pub
  • Replace the "cardno:12_345_678" with a comment describing which public key this is.

You can then add this to your $HOME/.ssh/authorized_keys file on each machine you will need to log into.

$ cd ~/.ssh/
$ cat id_rsa.pub >> authorized_keys

Note that there is no way to get an "id_rsa" (without the ".pub") file. Such a file would contain the secret key, and the whole point of storing the keys on a YubiKey is because the secret keys cannot be extracted.

Using "gpg --export-ssh-key"

This is the method you'll have to use if your PGP key has more than one subkey with the [A] capability.

Key ID

If your PGP key has more than one subkey with the [A] capability, you will need to use the fingerprint of that specific subkey. (The key I use at work has two authentication keys - one ed25519 and one rsa4096.)

$ gpg --list-keys --with-subkey-fingerprints jms1
pub   rsa4096 2019-03-21 [SC] [expires: 2024-01-01]
      E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB
uid           [ultimate] John Simpson <j..1@j....net>
uid           [ultimate] John Simpson <k....w@m...com>
uid           [ultimate] John Simpson <k....w@k......us>
sub   rsa4096 2019-03-21 [E] [expires: 2024-01-01]
      3C8EC9C7B067A4C542F9727D795C2CF824364755
sub   rsa4096 2019-03-21 [S] [expires: 2024-01-01]
      77DEBB0C8C7FBAFF1E0E70DCE9E44ED30E2F2445
sub   rsa4096 2019-03-21 [A] [expires: 2024-01-01]
      7A6B95B6BF897A6497165AE436823233F8D09EB7

This key has only a single [A] subkey, so I could use any of them, but for this example I'm going to use the fingerprint of that subkey.

$ gpg --export-ssh-key 7A6B95B6BF897A6497165AE436823233F8D09EB7
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDhVIFZFwb0EoFsKRUrp0LTra3w6F06H2SLnE2NqQ0N
LFm1vtXPey9byXnKsxaWnMdqzPCrgUQypA1pIl1IYzmjdH/UO9H0bW3fxg/9+YyT1u9bl2TdVw8yZb30
/A0qV6ddOylWC42pFeEKOhzEFSU6PXiaJE2zNhOfmAcqB0r6mhTuQ5a754UMYu8254Bh1XUbEXm/Tpt7
K+1xIs4dTIVerL+7U55husgoMQ2HB6DcGSzfqpBwon208ll8ERhxkIBpwVKPfC1eJeyiuUgJOVp69O+r
TnPQ/oYzzX1kXCSfdOpBDZpu9oCQPAtRwjF9YfX7AK645qF4ua17cPRYmFTTa9d65E+VfGIbhgD0zpfM
6rnLU+XeZV3jqegxzphl7xNX2vOOlNYTDBGD7izQV9a5AehoPkZ3MIM5JNzfzK3uEFduyD2L9RLJ3Tls
2uCYOe7TjRfasbvY/rzgn3LAnF2nX3l46ckgsxJk9m2duvmHdsLYBzGMpnWOlzE+CWHnvdewhoUTXe4f
R0pkd5a7josJm5giBtUNgrUC4JevV5yWU2SY+5u0mePeaQLWjKW3vroZpmM1jPpYDcU4xL7JqJJzltbb
L90TAvlKXGRJXEt9t46SfulTGURp9n5yDP2xS8yapdI6NvFW/5bV5rEgltYwgi+evwOVnvi1eTUAkjIP
w== openpgp:0xF8D09EB7

The output is one long line of text (or not so long, for ed25519 keys). The last part, "openpgp:0xF8D09EB7", is a human-readable comment and can be changed without hurting anything.

Maintenance

The pages in this section cover how to perform "maintenance" when managing your PGP keys using a YubiKey.

Change PGP Key Expiration Date

  • Boot into Tails with Persistent Storage unlocked

  • Open Terminal

  • Set KEYID to full fingerprint of primary

    KEYID="E3F7F5F76640299C5507FBAA49B9FD3BB4422EBB"
    
  • Set new expire date on primary key

    gpg --quick-set-expire $KEYID 2025-01-01
    
  • Set new expire date on all subkeys

    gpg --quick-set-expire $KEYID 2025-01-01 '*'
    

    Note: if you're letting one or more subkeys expire, instead of '*' specify the full fingerprint of each subkey whose expiration date you DO want to change.

  • Export PUBLIC key again.

    • wherever/however you exported the key when creating it

    • secret keys do not change, so they don't need to be backed up again