OpenPGP Part 2: Create Your Primary Key
In this post we’re going to create a Primary Key which will be the root of all our keys. It will be the source of trust and how we generate all other keys needed.
I am not, and do not claim to be a security expert. I’ve just spent a lot of time researching this and trying to implement best practices. I have made my best effort to ensure this information is accurate and up to date at the time of writing with all references provided. If you find a mistake whether small or egregious please let me know so I can improve this content.
Quick Refresh and Terminology
The first step in creating your security playbook is generating keys. Before we get into it let’s take a brief moment to review this public service announcement:
- Public Key: Share with others. No need to keep it secret.
- Private Key: NEVER EVER EVER EVER SHARE WITH ANYONE…..EVER.
Let’s also review some terminology we’ll be using.
- Key - this is a wildly overloaded term you will see tossed around. Most often when you see the term “key” used it refers to either 1) a public/private key pair or 2) a keyblock which is often referred to as your “PGP public key”. In the second case this could also be referred to as a certificate as it contains a bunch of information in addition to your primary public key.
- Public Key - The public-facing portion of a key pair. This can be shared with others.
- Private Key - The super secret, never-to-be-shared portion of a key pair. Don’t do it! Don’t you even think about sharing it!
- UID - User ID. This is a name + email + optional comment which comprises a universal identity.
- Primary Key - This is the public/private key pair “key” that is the root of your universal identity. The private portion should be treated as the most secret, secure part of all your keys and identity.
- Subkey - This is a public/private key pair “key” that is signed and administered by a Primary Key.
- Keychain - A set of keys composed of the Primary Key along with all linked, signed, subkeys.
While each of these terms could warrant an extensive blog post, that is not my intention with this series. I want to provide enough information so you understand what is going on but focus on the practical implementation thus making this a playbook more than a textbook.
A Calming Word Before Starting
As you go through all of these steps remember that nothing is permanent. You are not making a binding, non-reversible life decision….yet 😂. The point being, you can perform these steps to get a feel for how things work and then completely blow it all away and do it again. One thing that held me up when I first got started was that these things felt so serious and permanent. They aren’t at this stage so follow along and don’t worry about messing anything up.
Where it does get permanent is later on when you start to use your keys in important, production flows or when you publish your OpenPGP Key to a keyserver. At that point you need to know what you are doing but for now just flex the muscles a bit and get a feel for things. When the time comes to get serious you’ll be more confident in the flows and how things work having practiced them.
Additionally, I would encourage you to go through this entire series with a “throwaway” keychain that you are free to play with and screw up. That’s how we learn.
Follow Along with Docker
To illustrate how to do this completely from scratch I’ll be using Docker and the bookworm-slim
image which is the latest stable release at the time of writing. Following along this way has a few advantages. It allows you to get acquainted with the OpenPGP techniques as part of the playbook without having to install anything on your local machine besides Docker. It’s ephemeral. You can follow along, create keys, try some stuff, make mistakes and then blow the whole thing away. You can get as crazy as you want without having to worry about messing up your main environment.
To get started install Docker and then run the following command to open up a new shell session in a container:
1
docker run -it --rm debian:bookworm-slim /bin/bash
NOTE: The
--rm
in this command means that once you exit the container it will be deleted. This also means you will lose all of your work and have to start fresh next time you launch. If you want to re-enter the container later and keep your work, i.e. installed dependencies and generated keys, remove--rm
from the command.
Install gpg
Run the following commands to install gpg
.
1
2
3
apt update
apt upgrade
apt install gnupg2
Validate it was installed properly by running:
1
gpg --version
1
2
3
4
5
6
7
8
9
10
11
12
13
14
gpg (GnuPG) 2.2.40
libgcrypt 1.10.1
Copyright (C) 2022 g10 Code GmbH
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
Generate A Primary Key
This will be the root of your keychain and identity. It contains your universal ID as well as the root key pair.
1
gpg --full-generate-key
Here is the output of the command showing the options selected:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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 <------------------------------- RSA for encryption
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096 <------------ 4096 for max security
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) 0 <-------------------------- No expiration
Key does not expire at all
Is this correct? (y/N) y <------------------------- Confirm no expiration
GnuPG needs to construct a user ID to identify your key.
Real name: Fake McFakerton
Email address: me@fake.com
Comment:
You selected this USER-ID:
"Fake McFakerton <me@fake.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o <------ Ok to confirm
During this process you will be prompted to enter a passphrase. This is an additional layer of security on top of your Primary Key. Even if your Primary Key is stolen an attacker needs to unlock it with the passphrase to use it. For this reason you should pick a strong passphrase.1
You will have to occasionally enter this passphrase to perform operations with your Primary Key.
Congratulations!!! You just created a Primary Key and universal identity. All of this is deposited, in an encrypted way, locally in the ~/.gnupg folder. It resides on your machine (or, in our case, in a Docker container). We will address this later as it presents a security vulnerability.
1
ls -al ~/.gnupg/
1
2
3
4
5
6
7
8
9
10
11
12
# total 28
# drwx------ 4 root root 4096 Jan 11 22:33 .
# drwx------ 1 root root 4096 Jan 11 22:30 ..
# srwx------ 1 root root 0 Jan 11 22:33 S.gpg-agent
# srwx------ 1 root root 0 Jan 11 22:32 S.gpg-agent.browser
# srwx------ 1 root root 0 Jan 11 22:32 S.gpg-agent.extra
# srwx------ 1 root root 0 Jan 11 22:32 S.gpg-agent.ssh
# drwx------ 2 root root 4096 Jan 11 22:33 openpgp-revocs.d
# drwx------ 2 root root 4096 Jan 11 22:33 private-keys-v1.d
# -rw-r--r-- 1 root root 2471 Jan 11 22:33 pubring.kbx
# -rw------- 1 root root 32 Jan 11 22:30 pubring.kbx~
# -rw------- 1 root root 1240 Jan 11 22:33 trustdb.gpg
Parameter Explanations
There are lots of opinions about how to construct a Primary Key and, as you can imagine, those opinions get very heated. Ultimately you have to decide for yourself what parameters to use but here is an explanation of why, as of this writing, I chose the settings above.
No Comment
I was convinced to the leave the comment portion off of my UID based on a single online comment. The blogger basically explained that any comment can reveal information about yourself to the world and the lack of a comment has no drawbacks. Good enough for me. A lot of security is obscurity so I go with no comment. If you want to include a comment on yours, go for it. It’s unlikely to lead to a major security breach.
Why RSA over ECC?
Lots of people say RSA is too old, or insecure and that ECC is the future. In general, ECC keys give you the same or more security as RSA with much smaller signatures but RSA is more backward compatible.2 RSA is still NIST-approved3 and you can always generate ECC signing subkeys which we will do later on.
No custom gpg.conf?
Many sites recommend “more secure” settings in the config file for GPG. But even the OpenPGP Best Practices4 guide advises to use the defaults now.
If you had previously tweaked your configurations, you should consider starting over with a base configuration, so you do not have outdated recommendations that are less secure than the defaults.
No expiration?
This is another one of those “After lots of reading I was convinced this is fine” moments. We will have expirations on our subkeys but for the Primary Key it doesn’t make much sense to me personally. This is where I remind you I am not an industry expert and highly recommend you do what is best for you based on your own research. The Primary Key will mostly be kept in “offline” storage. Meaning, it won’t be readily accessible and will only be used for certification operations and only by me. If you set an expiry you’ll have to get your Primary Key out of offline storage every X days/months/years to renew it. If this tradeoff is worth it to you then absolutely set an expiration period.
Inspecting Our Key(s)
Now, I lied a little bit. You didn’t just create a Primary Key. You actually created a Primary Key and an encryption subkey. Let’s take a look with the following command:
1
gpg --list-secret-keys
1
2
3
4
5
------------------------
sec rsa4096 2024-01-11 [SC]
880B60A6A060D5C5E16EB97CFCB1C79A7216CD97
uid [ultimate] Fake McFakerton <me@fake.com>
ssb rsa4096 2024-01-11 [E]
We actually have TWO keys! This output shows us the following:
- sec - Our primary key with capabilities [SC] (signing and certification)
- uid - Our UID name and email. The “[ultimate]” means our identity has ultimate trust
- ssb - A secret subkey with the (E)ncryption capability.
KEY ID: You will need your Primary Key id to perform other operations. It is the last 8 bytes of the fingerprint from the sec section. So in this example the fingerprint is 880B60A6A060D5C5E16EB97CFCB1C79A7216CD97 so the key id is 7216CD97.
By default gpg
is helping us do the right thing. You can construct a Primary Key that has all of the capabilities of certification, authentication, signing, and encryption but this is a terrible security practice. GPG helps us by creating an encryption subkey by default (can be overriden if you want). While our Primary Key has the “signing” capability by default we will want to create our own subkey for that which we’ll do in our next series post.
A Great Foundation
At this point you’ve laid the basic foundation for your online security playbook. You have generated a secure Primary Key and encryption subkey. Additionally, you’ve created a UID which, at some later point, you can decide to publish broadly for others to use. In the next post we’ll finish up our key creation by building a series of subkeys that will be able to handle all of our use cases of signing, encryption/decryption, and authentication.
Is this content helpful? Join the community and get the Production ESP32 newsletter. Concise, actionable content right in your inbox.
References
NIST Digital Identity Guidelines discuss the strength of normal language passphrases. ↩
This post has a nice breakdown of choosing between RSA and ECC. A little dated but still relevant. ↩
FIPS 186-5 is the most recent publication from NIST. These are the world’s foremost experts in cryptography. Their guidance should always outweigh JonnyPants69 on StackOverflow. Believe industry experts, not random bloggers like me. ↩
Comments powered by Disqus.