Generate Secure OpenPGP Keys
In this post we're going to discuss how to securely generate OpenPGP keys.
Secure Environment
When generating OpenPGP keys it's recommended to use as secure of an environment as possible to limit the attack surface. One way to do this is to generate the keys using a Live Operating System (LiveOS) like Tails.
If you want to make sure your keys are generated in a secure environment, then you should first Install Tails on a USB which will be used to run Tails from.
When starting Tails you should disable all wireless networking on startup which prevents the system from connecting to the internet. If you have the knowledge and skills, then it's also recommended to remove any wireless networking cards from the device that you're connecting the USB to.
You can also remove any secondary storage like Hard Disk Drives (HDDs), SATA Solid State Drives (SSDs), and NVMe SSDs which prevents anything from potentially being saved to long term storage.
Hardened GPG Configuration
Before generating the OpenPGP keys you should also make sure your GPG configuration has been hardened, i.e., the options in the gpg.conf
file have been set up to be more private and secure.
You can take a look at the Hardened GPG Configuration post for a recommended hardened configuration as well as links to other hardened configurations.
If you’re using Tails or some other security focused OS to generate the OpenPGP keys, then the GPG configuration should already be sufficiently hardened.
Photo Preparation
You can add a photo to the key which can be a photo of the owner of the key, a photo of a pseudonym, a photo of an organization, etc.
If you want to add a photo to your key, then you should first make sure the image has the proper resolution, quality, file type, and that all metadata is removed from the image.
Once your image meets the proper criteria, then you can use, e.g., another USB which you can use to transfer the image to Tails.
The image should ideally be as close to 240x288 as possible, it should be compressed so it doesn't take up too much data, the image type of JPEG is required, and the metadata of the image should be removed as well.
We'll demonstrate how to get an image to meet the proper criteria using ImageMagick which you should install if you want to follow along.
The following command keeps the image in the same orientation and converts it to a JPEG:
mogrify -auto-orient -format jpeg your-photo.image-extenstion
This command resizes the image to be as close to the specified resolution without changing the aspect ratio:
mogrify your-photo.jpeg -resize 240x288 your-photo.jpeg
If you prefer for the image to be the specified resolution regardless of if the original aspect ratio is maintained then you can run the following command:
mogrify your-photo.jpeg -resize 240x288! your-photo.jpeg
To reduce the quality of the image which reduces the data the image takes up you can run the following command:
mogrify your-photo.jpeg -quality 50 your-photo.jpeg
If the image is still too large when adding it to the key you can continue to decrease the value until the image is an appropriate size.
If you have to resize the image after attempting to add it to the key, then be sure to restart the edit key prompt which we'll go over in more detail below and remove the metadata again before adding the photo.
To remove the metadata from the image we'll be using the Exiftool.
Here's how to remove all of the metadata from the image using the following command:
exiftool -all= your-photo.jpeg
If the image has metadata associated with it the original image will be moved to the following file your-photo.jpeg_original
which you can delete if you no longer want the original image.
Generating a Passphrase
Before generating the primary key, we're going to first generate a passphrase for the key which you'll need to enter whenever you need to access the key.
The passphrase will prevent any unauthorized access to the key when it's encrypted, so it should be a strong passphrase which will make it difficult to brute force.
To come up with a strong passphrase you can, e.g., open up KeePassXC which should be available if you're using Tails, navigate to the password generator, then generate a strong password or passphrase. Be sure to use the password quality check to make sure it's secure.
It's also recommended to write down the passphrase and/or store it in a secure password manager like KeePassXC in case you forget it. Just make sure you secure all written copies of the passphrase as well as any password manager you decide to save the passphrase in.
Here are some recommendations for password managers:
Generating the Primary Key
Now that we have a secure environment and we have a strong passphrase, we're ready to generate the primary key.
Once Tails has booted, we can open up a terminal and run the following command:
gpg --expert --full-generate-key
The --expert
option allows us to set the capabilities for the primary key and the --full-generate-key
command allows us to use a fully featured key generation dialog which means we can specify our preferred characteristics for the key.
Choosing the Kind of Key
After running the command, you should see output similar to the following:
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)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(9) ECC and ECC
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(13) Existing key
(14) Existing key from card
Your selection?
We're going to be using the eighth option, i.e., RSA (set your own capabilities)
, so we can type 8
then press Enter.
Capabilities
You should now be prompted with the following:
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
Your selection?
Here we're being asked which actions we want the primary key to be able to perform, i.e., Sign, Certify, and/or Encrypt.
We're going to be using separate subkeys for the Sign and Encrypt actions, so we're going to disable those actions by toggling them off.
To toggle off the sign capability we need to type s
then press Enter.
You should now see output similar to the following:
Possible actions for this RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection?
To toggle off the encrypt capability we need to type e
then press Enter.
You should now see output similar to the following:
Possible actions for this RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection?
It's worth mentioning there are some cases when you may be required to use the primary key for signing instead of a subkey that's been certified by the primary key, e.g., if you need to prove ownership of the primary key with an entity that doesn't recognize subkeys. If this is a concern for you, then you can toggle the sign capability to be allowed.
Once you’re satisfied with the allowed actions for your primary key you can type q
then press Enter.
Keysize
You should now be prompted with the following:
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072)
Here we're being asked to choose the keysize which can be between 1024
and 4096
bits long. A longer keysize is preferred since it's more secure which is why we'll be using the maximum value of 4096
.
A smaller keysize can be chosen when the software you intend to use the key with doesn't support the larger keysize values.
We can now type the maximum keysize of 4096
then press Enter.
Expiration
You should now be prompted with the following:
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)
Here we're being asked to choose the expiration date for the key. By setting an expiration date users that are using the key will be notified that the key has expired, so it should no longer be trusted.
You can set the key to never expire, but if you loose access to the private key and all of the copies of the revocation certificate which will be going over how to create later, then the key will still be thought to be valid even though you no longer have access to it.
You can always move the expiration date to a later date as long as you have the private key, so if you're still using the key by the time the expiration date draws near you can update the key and distribute the updated public key.
We're going to set the expiration date to be 3 years from now, so we can type 3y
then press the Enter.
You should see the following confirmation prompt:
Key expires at Fri 23 Jul 2027 01:21:07 PM UTC
Is this correct?
If the expiration date looks correct, then type y
and press Enter.
User ID
You should now be prompted with the following:
GnuPG needs to construct a user ID to identify your key.
Real name:
The user ID consists of a name and an email used to identify the person that the key belongs to as well as a comment used to add any additional information you want to share about the key.
For the name you can put in your legal name, a pseudonym, the name of an organization the key belongs to, etc.
The name and email address you associate with the key will be available for anyone to view if they have access to the public key, so it's recommended to use a pseudonym and an email address you don't mind sharing publicly.
We're going to set the name to be your-name
which you should replace with the name you want to associate with the key.
After typing your-name
, we can press Enter.
You should now be prompted with the following:
GnuPG needs to construct a user ID to identify your key.
Real name: your-name
Email address:
We're going to set the email address to be your-email@example.com
which you should replace with the email you want to associate with the key.
After typing your-email@example.com
, we can press Enter.
You should now be prompted with the following:
GnuPG needs to construct a user ID to identify your key.
Real name: your-name
Email address: your-email@example.com
Comment:
We're going to leave the comment empty, so we can press Enter.
You should now be prompted with the following confirmation:
GnuPG needs to construct a user ID to identify your key.
Real name: your-name
Email address: your-email@example.com
Comment:
You selected this USER-ID:
"your-name <your-email@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?
If everything looks correct, then you can type o
, then press Enter.
It's possible to associate more than one user ID with a key which you can add later if you need to.
Passphrase
You should now be prompted to enter a passphrase for the key which you should have previously generated.
You can type or copy and paste the passphrase into the passphrase field then press the Ok button.
Key Generation
While entering a strong passphrase, you should see a prompt appear that looks similar to the following:
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.
Here we're being prompted to help the random number generator generate enough entropy for the key.
It's very important to have a lot of entropy available during this process to prevent the possibility of the keys from being able to be easily predicted. Therefore, it's recommended to move the mouse, type on the keyboard, etc. to increase the entropy.
If you're using Tails, then you may have noticed how quickly the key was generated which is due to how Tails generates random numbers which you can read about in the Tails Random numbers article.
Once the key generation is complete, you should see output similar to the following:
gpg: directory '/home/amnesia/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/amnesia/.gnupg/openpgp-revocs.d/0512CEFB5478FEB9032FFB6C46B680BB17A6BD07.rev'
public and secret key created and signed.
pub rsa4096/0x46B680BB17A6BD07 2024-07-23 [C] [expires: 2027-07-23]
Key fingerprint = 0512 CEFB 5478 FEB9 032F FB6C 46B6 80BB 17A6 BD07
uid your-name <your-email@example.com>
The second line of the output mentions the creation of a revocation certificate located in the following location /home/amnesia/.gnupg/openpgp-revocs.d/0512CEFB5478FEB9032FFB6C46B680BB17A6BD07.rev
.
We can output the content of the file by running the following command:
cat /home/amnesia/.gnupg/openpgp-revocs.d/0512CEFB5478FEB9032FFB6C46B680BB17A6BD07.rev
The output should look something like the following and note the PGP PUBLIC KEY BLOCK
section has been replaced with ...
:
This is a revocation certificate for the OpenPGP key:
pub rsa4096/0x46B680BB17A6BD07 2024-07-23 [] [expires: 2027-07-23]
Key fingerprint = 0512 CEFB 5478 FEB9 032F FB6C 46B6 80BB 17A6 BD07
uid your-name <your-email@example.com>
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
...
-----END PGP PUBLIC KEY BLOCK-----
By default gpg
creates a revocation certificate when you create a new primary key which is fine, but the revocation certificate isn't encrypted which means if anyone gets access to this file then they'll be able to revoke your key.
One option is to keep the default revocation certificate and properly backup and secure the file by encrypting it using gpg
and applying other security measures which we discuss in more detail below.
The other option is to generate our own revocation certificate which we demonstrate below and delete this file by running the following command:
rm -rf /home/amnesia/.gnupg/openpgp-revocs.d/0512CEFB5478FEB9032FFB6C46B680BB17A6BD07.rev
Adding Subkeys
We have successfully created an OpenPGP key with one 4096-bit RSA primary key which can be used to certify other keys.
This means we're now ready to add subkeys which will be used for signing, encryption, and authentication.
Editing the Primary Key
To add subkeys we can use the --edit-key
command which allows us to edit an existing key prefaced by the --expert
option which gives us the ability to configure more characteristics about the key.
To edit the primary key we just created we're going to run the following command:
gpg --expert --edit-key your-email@example.com
Be sure to replace your-email@example.com
with the email address you set with your key.
You should now be prompted with the following:
Secret key is available.
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2027-07-23
sec rsa4096/0x46B680BB17A6BD07
created: 2024-07-23 expires: 2027-07-23 usage: C
trust: ultimate validity: ultimate
[ultimate] (1). your-name <your-email@example.com>
Adding a Subkey
We're now going to use the addkey
command which allows us to add a subkey to the primary key.
Run the following command to add a subkey:
addkey
If you set a passphrase for your primary key, then you may be prompted to enter the passphrase before being able to add the subkey.
You should now be prompted with the following:
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?
We're going to be using the eighth option, i.e., RSA (set your own capabilities)
, so we can type 8
then press Enter.
You should now be prompted with the following:
Possible actions for this RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection?
To toggle off the encrypt capability we need to type e
then press Enter.
You should now see output similar to the following:
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?
Once you’re satisfied with the allowed actions for your signing subkey you can type q
then press Enter.
You'll now be prompted to set the remaining characteristics for the signing subkey which is done in a similar way to the primary key we previously set.
You should now be prompted with the following:
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072)
Here we're being asked to choose the keysize which we'll set to 4096
.
Again a smaller keysize can be chosen when the software you intend to use the key with doesn't support the larger keysize values.
We can now type the maximum keysize of 4096
then press Enter.
You should now be prompted to set the expiration date:
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)
We're going to set the expiration date to be 1 year from now, so we can type 1y
then press the Enter.
You should see the following confirmation prompt:
Key expires at Wed 23 Jul 2025 05:42:07 PM UTC
Is this correct? (y/N)
If the expiration date looks correct, then type y
and press Enter.
You should now see the following confirmation prompt for the subkey creation:
Really create? (y/N)
If the subkey looks correct, then type y
and press Enter.
You may now be prompted to enter the passphrase for the primary key to complete the addition of the subkey.
You should now be prompted to help generate enough entropy for the subkey just like we did for the primary key:
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.
Once enough entropy has been created, you should see output similar to the following:
sec rsa4096/0x46B680BB17A6BD07
created: 2024-07-23 expires: 2027-07-23 usage: C
trust: ultimate validity: ultimate
ssb rsa4096/0x4288AC227E259D0F
created: 2024-07-23 expires: 2025-07-23 usage: S
[ultimate] (1). your-name <your-email@example.com>
You can now repeat this process for adding the encryption and authentication keys.
The only difference will be you'll need to toggle off the sign capability for the encryption subkey by entering s
when prompted. For the authentication subkey you'll need to toggle off the sign and encrypt capabilities when prompted by entering s
and e
, respectively, then you'll need to toggle on the authentication capability by entering a
.
Once all the subkeys are added you should see output similar to the following:
sec rsa4096/0x46B680BB17A6BD07
created: 2024-07-23 expires: 2027-07-23 usage: C
trust: ultimate validity: ultimate
ssb rsa4096/0x4288AC227E259D0F
created: 2024-07-23 expires: 2025-07-23 usage: S
ssb rsa4096/0xC5AB9F2897890EFF
created: 2024-07-23 expires: 2025-07-23 usage: E
ssb rsa4096/0xE13FEA1C7ABD419E
created: 2024-07-23 expires: 2025-07-23 usage: A
[ultimate] (1). your-name <your-email@example.com>
We can now save the key to the keyring by typing save
and pressing Enter.
Adding Additional User IDs
While you're editing the primary key you can also add more user IDs, by running the following command:
adduid
You will then be prompted to enter the name, email address, and comment just like we did for the primary key.
After adding the additional user ID, you'll be prompted to enter the primary key passphrase to complete the operation.
You can then save the updates to the key by typing save
and pressing Enter.
Adding a Photo
While editing the primary key you can also add a photo using the following command:
addphoto
You should now be prompted to enter the filename for the photo you want to add:
Pick an image to use for your photo ID. The image must be a JPEG file.
Remember that the image is stored within your public key. If you use a
very large picture, your key will become very large as well!
Keeping the image close to 240x288 is a good size to use.
Enter JPEG filename for photo ID:
To add the photo you can input the filename of the photo if it's in the same location where you ran the command from or you can specify a path to the photo.
As mentioned in the prompt above make sure the image is a JPEG file and the dimensions of the image are 240x288.
Also as previously mentioned you should remove any metadata from the image before adding it to the key.
If the image is too large you’ll see the following warning:
This JPEG is really large (6572 bytes) !
Are you sure you want to use it? (y/N)
Don’t add an image that is too large instead exit the editing of the key by pressing Ctrl+c. Then compress the image some more, remove the metadata again, and try again.
If the image meets the proper criteria, then the image will be displayed in a separate window which you can use to inspect the image before adding it. After inspecting the image, you can close the window displaying it.
You’ll then be shown the following confirmation prompt:
Is this photo correct (y/N/q)?
If everything looks correct, then you can add the photo by typing y
and pressing Enter.
After adding the photo, you'll be prompted to enter the primary key passphrase to complete the operation.
You should now see output similar to the following:
sec rsa4096/0x46B680BB17A6BD07
created: 2024-07-23 expires: 2027-07-23 usage: C
trust: ultimate validity: ultimate
ssb rsa4096/0x4288AC227E259D0F
created: 2024-07-23 expires: 2025-07-23 usage: S
ssb rsa4096/0xC5AB9F2897890EFF
created: 2024-07-23 expires: 2025-07-23 usage: E
ssb rsa4096/0xE13FEA1C7ABD419E
created: 2024-07-23 expires: 2025-07-23 usage: A
[ultimate] (1). your-name <your-email@example.com>
[ unknown] (2) [jpeg image of size 5143]
You can then save the updates to the key by typing save
and pressing Enter.
Creating Backups
To ensure we don't lose access to our keys, we're going to discuss how we can create and secure backups of our keys.
After creating the backups, we'll be transferring them and storing them on at least one USB which should ideally remain offline. You can also encrypt the USB to provide another layer of security.
Exporting the Secret Key
To backup our secret key we can export it to a file by using the following command:
gpg -a --export-secret-key your-email@example.com > secret_key
Here, we're using the -a
option which creates ASCII armored output. This means the secret key will be outputted as Base64 encoded data along with a header and footer. Without the -a
option gpg
will output binary data which cannot be directly displayed as text, so by using the -a
option keys can be more easily shared in text oriented mediums like email.
After running the command, you'll be prompted to enter the passphrase for the primary key to complete the exporting of the secret key.
The secret key has now be exported to the file secret_key
, so if you view the contents of the file you'll be able to see the secret key as Base64 encoded data.
The secret_key
file is not encrypted, so if anyone gets access to this file then they'll be able to perform any action with your primary key, e.g., certifying, signing, encrypting, and authenticating.
Therefore, it's vital to protect this file which can be done by encrypting the file using a strong password/passphrase, moving the file to ideally an encrypted USB that should remain offline, store the USB in a fireproof box, give the file a less descriptive name, and make the file a hidden file.
We'll discuss how to encrypt and decrypt the file using gpg
below.
Generating a Revocation Certificate
We're also going to create a revocation certificate which allows us to revoke the primary key. A revocation certificate can be used to notify other users that the primary key has been compromised in some way, e.g., it was stolen, lost, etc.
You can always create a revocation certificate as long as you have access to the secret key, but it's a good idea to create one ahead of time in case the private key is stolen or lost. This way you can still notify other users that the key has been compromised and should no longer be trusted.
To create a revocation certificate we can run the following command:
gpg -a --gen-revoke your-email@example.com > revocation_cert
Here, we're again using the -a
option which creates ASCII armored output which we described above.
After running the command, you'll be prompted to confirm the creation of the revocation certificate for the primary key:
sec rsa4096/0x46B680BB17A6BD07 2024-07-23 your-name <your-email@example.com>
Create a revocation certificate for this key? (y/N)
To confirm the creation of the revocation certificate we need to type y
then press Enter.
You'll now be prompted to select a reason for the revocation:
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?
We're going to select 1
which specifies that the key has been compromised, so need to type 1
then press Enter.
You'll then be prompted to enter an optional description for the revocation:
Enter an optional description; end it with an empty line:
>
We're going to leave the optional description empty, so we're going to press Enter.
You'll then be prompted to confirm the details for the revocation:
Reason for revocation: Key has been compromised
(No description given)
Is this okay? (y/N)
If everything looks correct, then type y
and press Enter.
After confirming the details for the revocation, you may be prompted to enter the passphrase for the primary key to complete the creation of the revocation certificate.
You should now see the following output:
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!
The revocation certificate has now been created and is located in the file revocation_cert
, so if you view the contents of the file you'll be able to see the revocation certificate as Base64 encoded data.
The revocation_cert
file is not encrypted, so if anyone gets access to this file then they'll be able to revoke your key which means you'll no longer be able to use the key, and you'll lose all of your Web of Trust signatures.
Therefore, it's vital to protect this file which can be done by encrypting the file using a strong password/passphrase, moving the file to ideally an encrypted USB that should remain offline, store the USB in a fireproof box, give the file a less descriptive name, and make the file a hidden file.
It's also a good idea to move the file to a different USB, then the one that has the private key stored on it.
Again, we'll discuss how to encrypt and decrypt the file using gpg
below.
Exporting the Public Key
To backup our public key we can export it to a file by using the following command:
gpg -a --export your-email@example.com > public_key
Here, we're again using the -a
option which creates ASCII armored output which we described above.
The public key has now been exported to the file public_key
, so if you view the contents of the file you'll be able to see the public key as Base64 encoded data.
The public_key
file is meant to be shared with others, so there's no need to encrypt the file or secure it to the same level as the secret key or the revocation certificate. We just need to make sure we always have a copy so we can easily share our public key with others. Therefore, it's a good idea to back it up by moving it to the USB as well.
Physical Copies
Along with digital copies stored on USBs, we can also write down the keys on paper. While it's possible that process can be tedious and error prone, so it may be worth looking into printing the keys out and using a solution like Paperkey - an OpenPGP key archiver which is a command line tool used to export keys on paper.
If you're writing the keys down you can look into using a Shieldfolio as well as acid-free paper which can be used to write the keys down on or to print the keys onto.
Be aware that if you use a solution like Paperkey you may need to expose your secret key to a less secure system than Tails. Also, if you decide to print your secret key and/or revocation certificate be aware that your system and the printer may store data about those items. Therefore, it's worth looking into how to properly secure your printer.
Changing Subkeys Passphrase
Before improving the security of the primary secret key by separating the primary secret key from the subkeys we added, we're going to first change the primary key passphrase. This passphrase will be used to access just the subkeys which will improve the security of the primary secret key even more. The idea here is to use a strong and unique passphrase for the subkeys that's different from the one protecting the primary secret key. The subkeys will be exposed to less secure systems, so if the passphrase is compromised the one protecting the primary secret key will remain safe. Be sure to have already backed up the primary secret key which will be using the previous primary key passphrase.
Again, to come up with a strong passphrase for each subkey you can, e.g., open up KeePassXC which should be available if you're using Tails, navigate to the password generator, then generate a strong password or passphrase. Be sure to use the password quality check to make sure it's secure.
Again, it's also recommended to write down the passphrases and/or include them in a secure password manager like KeePassXC in case you forget them. Just make sure you secure all written copies of the passphrases as well as any password manager you decide to save the passphrases in.
To change the passphrase we're going to run the following command to edit the key:
gpg --expert --edit-key your-email@example.com
Then we're going to run the following command to change the passphrase:
passwd
A window will then be displayed asking for the primary key passphrase which you can type or copy and paste into the passphrase field then press the confirmation button.
Then you will be asked to enter a new passphrase which you can type or copy and paste into the passphrase field then press the confirmation button.
After the confirmation prompt, you may be asked to enter the passphrase for the first subkey. If you’re asked to enter this passphrase, then just enter the new passphrase you just created.
We can now save the changes by typing save
and pressing Enter.
Removing the Primary Secret Key
After changing the primary key passphrase, we’re now ready to separate the primary secret key from the subkeys we added. The idea here is to keep the primary secret key as secure as possible by removing it from the keyring, keeping it offline, and away from any system that is less secure.
The subkeys can then be added to a device which exposes them to a less secure environment, but the primary secret key will remain safely stored offline. Ideally, the subkeys are added to a hardware security key like a YubiKey to lessen the likelihood of a key getting compromised.
We're going to start by first listing the keys that are available in our keyring by using the following command:
gpg -k
Here, we're using the -k
option which allows us to list the keys in the keyring.
You should see a list of all of the keys in your keyring including the primary key and subkeys you created which should look something like this:
pub rsa4096/0x46B680BB17A6BD07 2024-07-23 [C] [expires: 2027-07-23]
Key fingerprint = 0512 CEFB 5478 FEB9 032F FB6C 46B6 80BB 17A6 BD07
uid [ultimate] your-name <your-email@example.com>
uid [ultimate] [jpeg image of size 5143]
sub rsa4096/0x4288AC227E259D0F 2024-07-23 [S] [expires: 2025-07-23]
sub rsa4096/0xC5AB9F2897890EFF 2024-07-23 [E] [expires: 2025-07-23]
sub rsa4096/0xE13FEA1C7ABD419E 2024-07-23 [A] [expires: 2025-07-23]
We can then list the secret keys that are available in our keyring by using the following command:
gpg -K
Here, we're using the -K
option which allows us to list the secret keys in the keyring.
You should see a list of all of the secret keys in your keyring including the primary key and subkeys you created which should look something like this:
sec rsa4096/0x46B680BB17A6BD07 2024-07-23 [C] [expires: 2027-07-23]
Key fingerprint = 0512 CEFB 5478 FEB9 032F FB6C 46B6 80BB 17A6 BD07
uid [ultimate] your-name <your-email@example.com>
uid [ultimate] [jpeg image of size 5143]
ssb rsa4096/0x4288AC227E259D0F 2024-07-23 [S] [expires: 2025-07-23]
ssb rsa4096/0xC5AB9F2897890EFF 2024-07-23 [E] [expires: 2025-07-23]
ssb rsa4096/0xE13FEA1C7ABD419E 2024-07-23 [A] [expires: 2025-07-23]
To separate the primary secret key from the keyring we're going to export the secret subkeys to a file by running the following command:
gpg -a --export-secret-subkeys your-email@example.com > secret_subkeys
Here, we're again using the -a
option which creates ASCII armored output which we described above.
After running the command, you'll be prompted to enter the passphrase for the primary key to complete the exporting of the secret subkeys.
The secret subkeys have now been exported to the file secret_subkeys
, so if you view the contents of the file you'll be able to see the secret subkeys as Base64 encoded data.
The secret_subkeys
file is not encrypted, so if anyone gets access to this file then they'll be able to perform any action with your subkeys, e.g., signing, encrypting, and authenticating.
Therefore, it's vital to protect this file which can be done by encrypting the file using a strong password/passphrase, moving the file to ideally an encrypted USB that should remain offline, store the USB in a fireproof box, give the file a less descriptive name, and make the file a hidden file.
We'll discuss how to encrypt and decrypt the file using gpg
below.
After exporting the secret subkeys, we can now delete the primary secret key which we previously exported and the secret subkeys from the key in the keyring by running the following command:
gpg --delete-secret-keys your-email@example.com
You should now see a confirmation prompt:
sec rsa4096/0x46B680BB17A6BD07 2024-07-23 your-name <your-email@example.com>
Delete this key from the keyring? (y/N)
If everything looks correct, then type y
and press Enter.
You should now see a second confirmation prompt:
This is a secret key! - really delete? (y/N)
Again, if everything looks correct, then type y
and press Enter to delete the secret keys.
A window may then be displayed for each secret key asking you again if you want to delete the keys which you should confirm.
If we run the command to list the keys that are available in our keyring again:
gpg -k
You should see a list of all of the keys in your keyring including the primary key and subkeys you created which should look something like this:
pub rsa4096/0x46B680BB17A6BD07 2024-07-23 [C] [expires: 2027-07-23]
Key fingerprint = 0512 CEFB 5478 FEB9 032F FB6C 46B6 80BB 17A6 BD07
uid [ultimate] your-name <your-email@example.com>
uid [ultimate] [jpeg image of size 5143]
sub rsa4096/0x4288AC227E259D0F 2024-07-23 [S] [expires: 2025-07-23]
sub rsa4096/0xC5AB9F2897890EFF 2024-07-23 [E] [expires: 2025-07-23]
sub rsa4096/0xE13FEA1C7ABD419E 2024-07-23 [A] [expires: 2025-07-23]
If we run the command to list the secret keys that are available in our keyring:
gpg -K
You should get an empty list.
We can now import just the secret subkeys that we previosuly exported by running the following command:
gpg --import secret_subkeys
After running the command, you'll be prompted to enter the passphrase for the primary key to complete the importing of the secret subkeys.
You should see output that looks similar to the following:
gpg: key 0x46B680BB17A6BD07: "your-name <your-email@example.com>" not changed
gpg: To migrate 'secring.gpg', with each smartcard, run: gpg --card-status
gpg: key 0x46B680BB17A6BD07: secret key imported
gpg: Total number processed: 1
gpg: unchanged: 1
gpg: secret keys read: 1
gpg: secret keys imported: 1
If we run the command to list the keys that are available in our keyring again:
gpg -k
You should see a list of all of the keys in your keyring including the primary key and subkeys you created which should look something like this:
pub rsa4096/0x46B680BB17A6BD07 2024-07-23 [C] [expires: 2027-07-23]
Key fingerprint = 0512 CEFB 5478 FEB9 032F FB6C 46B6 80BB 17A6 BD07
uid [ultimate] your-name <your-email@example.com>
uid [ultimate] [jpeg image of size 5143]
sub rsa4096/0x4288AC227E259D0F 2024-07-23 [S] [expires: 2025-07-23]
sub rsa4096/0xC5AB9F2897890EFF 2024-07-23 [E] [expires: 2025-07-23]
sub rsa4096/0xE13FEA1C7ABD419E 2024-07-23 [A] [expires: 2025-07-23]
If we run the command to list the secret keys that are available in our keyring:
gpg -K
You should see a list off all of the secret keys in your keyring including the subkeys you created which should look something like this:
sec# rsa4096/0x46B680BB17A6BD07 2024-07-23 [C] [expires: 2027-07-23]
Key fingerprint = 0512 CEFB 5478 FEB9 032F FB6C 46B6 80BB 17A6 BD07
uid [ultimate] your-name <your-email@example.com>
uid [ultimate] [jpeg image of size 5143]
ssb rsa4096/0x4288AC227E259D0F 2024-07-23 [S] [expires: 2025-07-23]
ssb rsa4096/0xC5AB9F2897890EFF 2024-07-23 [E] [expires: 2025-07-23]
ssb rsa4096/0xE13FEA1C7ABD419E 2024-07-23 [A] [expires: 2025-07-23]
The #
after sec
is used to indicate that the primary secret key is not in our keyring.
Importing Subkeys
If you're not planning on moving the secret subkeys to a hardware security key like a YubiKey, then you can take the exported secret subkeys, i.e., the file secret_subkeys
as well as the exported file containing the public key, i.e., the file public_key
, and import them to whatever device you want to be able to use the keys from.
Be sure to encrypt the secret_subkeys
file using a strong password/passphrase before importing the file to the other device as this can protect the subkeys while they are being moved to the device. We'll be using gpg
to encrypt the secret_subkeys
file which will give the file the following name secret_subkeys.gpg
which should be the file you use when importing the secret subkeys to the device.
Also, be sure to delete the secret_subkeys.gpg
and secret_subkeys
files from the device after successfully importing the subkeys to the keyring.
To import the public key when you're on the other device run the following command in the same directory where the public_key
file is located:
gpg --import public_key
To import the secret subkeys when you're on the other device run the following command after decrypting the secret_subkeys.gpg
file in the same directory where the secret_subkeys
file is located:
gpg --import secret_subkeys
Encrypting Backups
We're now going to go over how to encrypt the backup files using gpg
. We're going to be backing up the secret_key
, revocation_cert
, and the secret_subkeys
files.
The encryption process is the same for each file, so we'll just demonstrate it with the secret_key
file. Be sure to encrypt each one of the files though.
Again, to come up with a strong passphrase for each file you can, e.g., open up KeePassXC which should be available if you're using Tails, navigate to the password generator, then generate a strong password or passphrase. Be sure to use the password quality check to make sure it's secure.
Again, it's also recommended to write down the passphrases and/or include them in a secure password manager like KeePassXC in case you forget them. Just make sure you secure all written copies of the passphrases as well as any password manager you decide to save the passphrases in.
To encrypt the file we can run the following command:
gpg -c secret_key
You should now be prompted to enter a passphrase for the file which you should have previously generated.
You can type or copy and paste the passphrase into the passphrase field then press the confirmation button.
Once the encryption is complete you should now have a file named secret_key.gpg
. The gpg
file extension isn't required, but it's recommended because it lets the user know which tool they need to use to decrypt the file.
After testing that you can successfully decrypt the file, you should delete the unencrypted file, i.e., secret_subkey
by running the following command:
rm -rf secret_subkey
Decrypting Backups
The decryption process is the same for each file, so we'll just demonstrate it with the secret_key.gpg
file. Be sure to test the decryption for each file before deleting the unencrypted files.
To decrypt the file we can run the following command:
gpg secret_key.gpg
You should now be prompted to enter the passphrase for the file.
You can type or copy and paste the passphrase into the passphrase field then press the confirmation button.
Once the decryption is complete you should now have a file named secret_key
along with the secret_key.gpg
file.