In an increasingly online world, we’ve become accustomed to being able to download anything from anywhere. Usually, we never think twice about where that download is coming from or who is on the other side, or even worse, who might be listening in or changing things in flight. Sometimes that doesn’t really matter. Like this site. There’s no dynamic content in this site and it’s built using HUGO. Nothing can really change (unless your government or ISP is censoring this site). But sometimes it really matters. You need to make sure you’re going to your bank’s website. You need to make sure that you’re putting your password in the real amazon.com. With the web, we use SSL for this. It’s the padlock in the upper right hand corner of your browser that says “Connection Secured” whenever you go anywhere these days. But how do we secure files and make sure they were put there by someone we trust?
GPG (The GNU Privacy Guard) is a software that lets us do this. It’s based on a “web of trust” that helps to ensure that no broken, compromised, or otherwise expired keys should ever break the trust of any other keys. That’s a fancy way of saying that it is decentralized. There’s a lot of buzz about that right now! With GPG, people generate their own Master Certifying Key, from which they can create various sub keys to encrypt, authenticate, or sign files and messages. The certifying key is used to sign other keys as well, which says that they are trusted. So, if I have a friend, Bob, and we sign each other’s keys, we are saying to the whole web of trust that anything that Bob trusts, I trust, and anything that I trust, Bob trusts. This is transitive. So if Bob also trusts Sam the same way that I trust Bob, then I will as well. However, there’s some additional protections, where this relationship is weaker, and will require multiple indirect relationships to be trusted, so no one link in the chain will affect all others.
That was a lot of talk about keys, but not a lot about encryption, which is the meat and potatoes of GPG. Keys give us the ability to encrypt, sign, and authenticate. So let’s get started.
# Generating a Master Certifying Key
- First, we have to generate our new keys. This is best done on an
air-gapped computer that will never touch the internet again. However, this is
not necessary to use GPG, it just keeps your master key much more Secure
by removing the opportunity for a data leak. Use the command
gpg --expert --full-generate-key
to generate a new key. You’ll get a prompt asking you to select a key type. Select option 8 to generate an RSA key. (there are other options, but they’re not as widely in use right now).
gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
(1) RSA and RSA
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(9) ECC (sign and encrypt) *default*
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(13) Existing key
(14) Existing key from card
Your selection?
- Next, the program is going to ask us
what capabilities we want for our key. We want to toggle everything off except
for
Certify
, and type q when finished.
Possible actions for this RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Sign Certify Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
- Next, we have to set our key length. It’s wise to make our key as long as possible so we can be prepared for the future, but it can make encryption slower. It depends on the key type. In my case, the longest is 4096, so I’ll select that.
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
- Next, we need to select when the key is set to expire. I chose “never” because I keep my key secret and air-gapped. If you don’t keep your key air-gapped, I’d advise you set some expiry date a few years in the future so in case it gets compromised, the damage that could be done is minimal. It will ask to confirm, and you’ll have to confirm your choices.
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)
Key does not expire at all
Is this correct? (y/N)
- Next, we’ll have to give it our real information. Anonymity is not really an option here unless you have a pseudonym. I don’t, so I’m using my real name and a test email from my domain. Again, you’ll be asked to confirm.
GnuPG needs to construct a user ID to identify your key.
Real name: Matthew Krueger
Email address: example@matthewkrueger.com
Comment: Matthew's Example Master Certifying Key for Website
You selected this USER-ID:
"Matthew Krueger (Matthew's Example Master Certifying Key for Website) <example@matthewkrueger.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?
-
We’ll now be asked to enter a password for our master key. This is VITALLY important if you’re not keeping your key air-gapped, as this will encrypt your key when not in use. Since this is a demo, I’m not going to enter anything here. Every OS and implementation of GPG will be different, so follow the prompts it gives you. Once again, I’d like to emphasize the VITAL importance of choosing a unique, complex, and random password for your key. I keep mine written down on a physical piece of paper that never touched a copy machine (they spy on you), and I sent copies to my family across the state. While that’s a bit extreme, similar concepts are still good to follow, especially offsite backups. You don’t want to lose your key. Ever.
-
Lastly, GPG will generate our key and give us some information. The line pub contains a number,
64CFA56B02F7B2E484B09BE29F9F051089326E60
. That is our key ID. This is how we identify keys. We’re now ready to generate some sub keys that we can actually use.
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: WARNING: server 'keyboxd' is older than us (2.4.3 < 2.4.5)
gpg: Note: Outdated servers may lack important security fixes.
gpg: Note: Use the command "gpgconf --kill all" to restart them.
gpg: WARNING: server 'keyboxd' is older than us (2.4.3 < 2.4.5)
gpg: Note: Outdated servers may lack important security fixes.
gpg: Note: Use the command "gpgconf --kill all" to restart them.
gpg: directory '/Users/mkrueger/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/Users/mkrueger/.gnupg/openpgp-revocs.d/64CFA56B02F7B2E484B09BE29F9F051089326E60.rev'
public and secret key created and signed.
pub rsa4096 2024-05-01 [C]
64CFA56B02F7B2E484B09BE29F9F051089326E60
uid Matthew Krueger (Matthew's Example Master Certifying Key for Website) <example@matthewkrueger.com>
- We can confirm our key is generated by checking our keyring. We do this by
using the command
gpg --list-keys
. Here’s my keyring. If you notice, we’re missing a few things. Our key we just generated only has a C. But my real key has three keys labelsub
below, that each have an expiry date, as well as an S, E, and A. We’ll explore these sub-keys next.
pub rsa4096 2024-05-01 [C]
64CFA56B02F7B2E484B09BE29F9F051089326E60
uid [ultimate] Matthew Krueger (Matthew's Example Master Certifying Key for Website) <example@matthewkrueger.com>
pub rsa4096 2024-01-05 [C]
E7444039BF585550BD8AA0F504A3D43F84760AC0
uid [ultimate] Matthew Krueger (Matthew's Master Certifying Key) <contact@matthewkrueger.com>
sub rsa4096 2024-01-05 [S] [expires: 2027-01-04]
sub rsa4096 2024-01-05 [E] [expires: 2027-01-04]
sub rsa4096 2024-01-05 [A] [expires: 2027-01-04]
# Generating Subkeys
-
First, we’ll get our list of keys again. Use
gpg --list-keys
for this. Since we’re working on our example key, I’ll use my first selection,64CFA56B02F7B2E484B09BE29F9F051089326E60
. We can also use the last 16 digits of this key for short this is called the keyID. (There’s also a short keyID that’s the last 8 digits) -
Next, we’ll use the fingerprint to edit our key. You’ll need your Master key password at this point. Enter it when it prompts you. At this point, we’ll be in a terminal for GPG. We can ask it for help with
help
!gpg --expert --edit-key <your key>
is the command we need for this operation.
sec rsa4096/9F9F051089326E60
created: 2024-05-01 expires: never usage: C
trust: ultimate validity: ultimate
[ultimate] (1). Matthew Krueger (Matthew's Example Master Certifying Key for Website) <example@matthewkrueger.com>
gpg> help
gpg> help
quit quit this menu
save save and quit
help show this help
fpr show key fingerprint
grip show the keygrip
list list key and user IDs
uid select user ID N
key select subkey N
check check signatures
sign sign selected user IDs [* see below for related commands]
lsign sign selected user IDs locally
tsign sign selected user IDs with a trust signature
nrsign sign selected user IDs with a non-revocable signature
adduid add a user ID
addphoto add a photo ID
deluid delete selected user IDs
addkey add a subkey
addcardkey add a key to a smartcard
keytocard move a key to a smartcard
keytotpm convert a key to TPM form using the local TPM
bkuptocard move a backup key to a smartcard
delkey delete selected subkeys
addrevoker add a revocation key
addadsk add an additional decryption subkey
delsig delete signatures from the selected user IDs
expire change the expiration date for the key or selected subkeys
primary flag the selected user ID as primary
pref list preferences (expert)
showpref list preferences (verbose)
setpref set preference list for the selected user IDs
keyserver set the preferred keyserver URL for the selected user IDs
notation set a notation for the selected user IDs
passwd change the passphrase
trust change the ownertrust
revsig revoke signatures on the selected user IDs
revuid revoke selected user IDs
revkey revoke key or selected subkeys
enable enable key
disable disable key
showphoto show selected photo IDs
clean compact unusable user IDs and remove unusable signatures from key
minimize compact unusable user IDs and remove all signatures from key
* The 'sign' command may be prefixed with an 'l' for local signatures (lsign),
a 't' for trust signatures (tsign), an 'nr' for non-revocable signatures
(nrsign), or any combination thereof (ltsign, tnrsign, etc.).
gpg>
- Now, that’s a lot of stuff. But what we’re mainly interested in is adding
a subkey to this. If we check the help page, this is under the
addkey
command. Type that in, and then enter option 8 for an RSA subkey. This should look pretty similar, as we’re just repeating the process of generating a new key, and we’ll follow the same exact steps.
gpg> addkey
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
(14) Existing key from card
Your selection?
- Follow the steps as above, toggling everything off but
sign
. You’ll notice the option forcertify
isn’t here. Only Master keys can certify. We’ll also want 4096 bit security. Expiry wise, these are more likely to be useful expiring after a year or so. I have mine set to expire after 3 years since I keep my keys on a FIPS hardware security key (something I’ll cover in a later post). I’d advise around a year. Make sure to set a password for this key as well. This is VITALLY important just as with the main key. Since this is a demo key, I am not going to be adding one here.
Possible actions for this RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection?
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 Thu May 1 02:04:32 2025 EDT
Is this correct? (y/N) y
Really create? (y/N) y
- Repeat this process, toggling everything but
encrypt
on the second key, and everything butAuthenticate
on the third. After this is complete, you should see an output that looks like below. Typesave
to save the keys.
sec rsa4096/9F9F051089326E60
created: 2024-05-01 expires: never usage: C
trust: ultimate validity: ultimate
ssb rsa4096/8D65232E2D447C4A
created: 2024-05-01 expires: 2025-05-01 usage: SR
ssb rsa4096/F77E8401DB3453FB
created: 2024-05-01 expires: 2025-05-01 usage: ER
ssb rsa4096/A63FDD38204FB63E
created: 2024-05-01 expires: 2025-05-01 usage: AR
[ultimate] (1). Matthew Krueger (Matthew's Example Master Certifying Key for Website) <example@matthewkrueger.com>
- Now we’re done! We have GPG keys in our keyring. We’ll talk about offloading these keys to physical security keys later, as well as talk about how to actually use the keys to do cool things like encrypting and decrypting messages. We’ll also upload our key to a keyserver.
While human written and reviewed, parts of this article were written with the assistance of Generative AI tools.