A Practical Guide to GnuPG

Publish Date:  Last Update:
Tags:guide security
1503 words, 8 minute(s) to read.

pix/posts/guide-to-gpg/encryption-chadism.webp

Using GnuPG can be hard, we’ve been there before. You generate your keys and then somehow you loose them, and then you realize you should get to learn how to correctly use GnuPG, but reality hits and there are no complete tutorials. So you go around the interent and try different articles and sources with no luck. Although I don’t promise a complete and comprehensive guide to GnuPG, in this article I would go over setting up GnuPG keys, subkeys, using GnuPG for SSH, transferring keys to other computers and using online services like Github and Codeberg.

Generating GnuPG Master-keys

GnuPG uses asymmetric encryption, which means that you would use 2 keys. Private keys for decrypting data. Public keys for encrypting data. By default, the implementation of GnuPG generates 2 pairs of keys, the master-key and a signed sub-key. It also generates your primary user identity.

The types of keys GnuPG can generate are:

By default, running gpg --gen-key creates pub, sec, and sub, ssb. The latter pair is for encryption.

Generate your new secret keys either with the quick command gpg --gen-key, or, if you would like to specify the bit-size (recommended 4096), with the command gpg --full-generate-key.

1
2
3
4
5
6
7
[~] $ gpg --list-secret-keys
/home/ayham/.local/share/gnupg/pubring.kbx
------------------------------------------
sec   rsa4096 2022-09-27 [SC] [expires: 2023-03-26]
      8C38DD3A3030F8AEB8A9A2BC783F6DE277DA7BFF
uid           [ultimate] ayham <me@ayham.xyz>
ssb   rsa4096 2022-09-27 [E] [expires: 2023-03-26]

After creating your initial keys, you should have one master key (the first one) that is signing and certification only ‘[SC]’, and one encryption key ‘[E]’.

Generating Sub-keys

Sub-keys are separate pair of keys generated by GnuPG, with the slight difference being that those keys are signed by your master key. Since the Web-of-trust is built upon the master key, you must keep your master key secret, and as I will show later, not on actively operating computers. Sub-keys allow you to sign and encrypt with your master’s key identity without the actual master key.

Sign-only keys can be used to sign Git commits. To generate a signing key:

 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
30
31
32
33
34
35
[~] $ gpg --edit-key me@ayham.xyz
gpg (GnuPG) 2.2.39; Copyright (C) 2022 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.

sec  rsa4096/783F6DE277DA7BFF
     created: 2022-09-27  expires: 2023-03-26  usage: SC
     trust: ultimate      validity: ultimate
ssb  rsa4096/186B390DB1EB9503
     created: 2022-09-27  expires: 2023-03-26  usage: E
[ultimate] (1). ayham <me@ayham.xyz>

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)
  (14) Existing key from card
Your selection? 4
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) 6m
Key expires at Fri 31 Mar 2023 03:23:40 PM +03
Is this correct? (y/N) y
Really create? (y/N) y
...
gpg> save

Choose an expiry date which is far enough to not be a hassle. You can always change the key expiry date, with the ‘expire’ command. If you have multiple devices (or installs) on which you would like to use your GnuPG keys, you can create as many keys as you need and then distribute them appropriately. However, this only works for sign keys and NOT encryption keys. GnuPG will just use the latest encryption key. This configuration of subkeys would allow you to selectively revoke compromised keys, with no need to revoke your master key.

Using GnuPG for SSH

You can generate an authorization key for SSH:

1
[~] $ gpg --quick-add-key <your key id> rsa4096 auth 6m

To setup GnuPG to act as an SSH agent:

1
2
[~] $ echo "enable-ssh-support" >> ~/.local/share/gnupg/gpg-agent.conf
[~] $ echo "use-standard-socket" >> ~/.local/share/gnupg/gpg-agent.conf

Your location of the configuration file may vary.

Add to your pre-desktop files (e.x. .bash_profile, .zprofile):

1
2
3
4
5
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
gpgconf --launch gpg-agent
gpg-connect-agent /bye
gpg-connect-agent updatestartuptty /bye >/dev/null
export GnuPG_TTY=$(tty)

Tell the GnuPG agent about your key. First find your auth. public key:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[~] $ gpg --with-keygrip --list-secret-keys
/home/ayham/.local/share/gnupg/pubring.kbx
------------------------------------------
sec   rsa4096 2022-09-27 [SC] [expires: 2023-03-26]
      8C38DD3A3030F8AEB8A9A2BC783F6DE277DA7BFF
      Keygrip = 48D61587035B00590DA8B96BA587161668E0C4AA
uid           [ultimate] ayham <me@ayham.xyz>
ssb   rsa4096 2022-09-27 [E] [expires: 2023-03-26]
      Keygrip = 1D1A365C136EC6C78523C26CF766B041810E03AD
ssb   rsa4096 2022-09-27 [A] [expires: 2023-03-26]
      Keygrip = 41FE9D7D43999B0A0344E4F4900E1E1A3E142065
ssb   rsa4096 2022-09-29 [S] [expires: 2023-03-28]
      Keygrip = 1134F1DEDA38D009B43BD61356F6B25A8F4E6EE9

Append the keygrip to sshcontrol:

echo {41FE9D7D43999B0A0344E4F4900E1E1A3E142065} >> ~/.local/share/gnupg/sshcontrol

Re-login or end any SSH agents, then run ssh-add -l to check if the agent does detect the key.

Transferring Your Keys

Back-up your keys:

1
2
3
4
[~] $ gpg --armor --export > public-keys.asc
[~] $ gpg --armor --export-secret-keys > private-keys.asc
[~] $ gpg --export-ownertrust > ownertrust.asc
[~] $ gpg --armor --gen-revoke me@ayham.xyz > revocation.asc

Keep all those files safe somewhere external. Move the public key files to the destination installion you would like to have your keys.

You will need to get your subkey’s public key id which you would want to use on the destination installation:

1
2
3
4
5
6
7
8
9
[~] $ gpg --list-secret-keys --keyid-format short
/home/ayham/.local/share/gnupg/pubring.kbx
------------------------------------------
sec   rsa4096/77DA7BFF 2022-09-27 [SC] [expires: 2023-03-26]
      8C38DD3A3030F8AEB8A9A2BC783F6DE277DA7BFF
uid         [ultimate] ayham <me@ayham.xyz>
ssb   rsa4096/B1EB9503 2022-09-27 [E] [expires: 2023-03-26]
ssb   rsa4096/9625CB0E 2022-09-27 [A] [expires: 2023-03-26]
ssb   rsa4096/CB24AEBF 2022-09-29 [S] [expires: 2023-03-28]

Export your subkey private key:

1
[~] $ gpg --armor --export-secret-keys 9625CB0E > your-key-name.asc

Now to import your exported files, run these on the destination system:

1
2
3
4
[~] $ gpg --import your-public-keys.asc
[~] $ gpg --import your-private-keys.asc
[~] $ # don't forget to import your ownertrust.asc to all systems
[~] $ gpg --import-ownertrust your-ownertrust.asc

Do not to forget to shred -U your *.asc files.

If you chose GnuPG as your SSH agent, and if you run ssh-add -l on the destination system and it does not show a user id, you would have to update the sshcontrol file with the new keygrip (use same method as above). You would also need to update server SSH public key, by adding a new one. I didn’t find a simpler solution to this.

Using Codeberg & Github

You can use your newly generated subkey for signing code commits. And by generating a subkey for every system you would like to sign your code on, you can ensure that in case you loose the private key for the subkey, it is just a matter of revocation and updating of your master public key to reflect that. A disadvantage of this method is that you do need to update the master key for any important modifications, like adding or deleting subkeys.

To start using your keys, export your public key and paste the extracted data on Codeberg and Github. I hope I can safely assume that if you followed along this article, you would be able to do that by yourself.

Export your SSH public key like so:

1
[~] $ gpg --export-ssh-key <your key id>

Add the output to Codeberg and Github.

Check if your SSH authentication works (I use dropbear client, it works smoothly with GnuPG):

1
2
[~] $ dbclient git@codeberg.org
[~] $ dbclient git@github.com

Don’t forget to configure git to always sign your commits:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[~] $ nvim .config/git/config
[user]
	email = <your email>
	name = <your name>
	signingKey = <your subkey id>!
[commit]
	gpgsign = true
[init]
	defaultBranch = master
[core]
	sshCommand = dbclient

The exclamation mark is not a typo!

Side note: I recommend generating your master key on a different installation than your main install, and then importing your needed subkeys to your main install. Either that or delete your ~/.local/share/gnupg/ after you have backed up your keys to another storage, then reimport them again without the master private key. This is so you do not store your master private key on an active machine connected to the internet.

Further Reading