Intro

GPG, which stands for GNU Privacy Guard, is an open source implementation of the Pretty Good Privacy (PGP) encryption standard. In this article, we’ll focus on asymmetric encryption, where we use a set of two keys, one public to encrypt, and one private that only itself can decrypt the encrypted content.

Creating a GPG key

Generate your key pair

 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
$ gpg --full-generate-key
...
gpg (GnuPG) 2.4.3; Copyright (C) 2023 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)
   (9) ECC (sign and encrypt) *default*
  (10) ECC (sign only)
  (14) Existing key from card
Your selection? 1

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) 0

Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.
Real name: John Doe
Email address: john.doe@somewhere.com
Comment: Personal encryption and signing GPG key

You selected this USER-ID:
    "John Doe (Personal encryption and signing GPG key) <john.doe@somewhere.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

# One optional password will be prompted for the encryption 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.

# One optional password will be prompted for the signing 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.

gpg: revocation certificate stored as '~/.gnupg/openpgp-revocs.d/C49BCFA8706203B8A03BF3A22EC378BC8416920D.rev'
public and secret key created and signed.

pub   rsa4096 2024-01-10 [SC]
      C49BCFA8706203B8A03BF3A22EC378BC8416920D
uid                      John Doe (Personal encryption and signing GPG key) <john.doe@somewhere.com>
sub   rsa4096 2024-01-10 [E]

Check for your key pair

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ gpg --list-signatures
...
~/.gnupg/pubring.kbx
-----------------------------
pub   rsa4096 2024-01-10 [SC]
      C49BCFA8706203B8A03BF3A22EC378BC8416920D
uid           [ultimate] John Doe (Personal encryption and signing GPG key) <john.doe@somewhere.com>
sig 3        2EC378BC8416920D 2024-01-10  [self-signature]
sub   rsa4096 2024-01-10 [E]
sig          2EC378BC8416920D 2024-01-10  [self-signature]

Export your key pair

1
2
3
4
5
# Public key
$ gpg --armor --export 2EC378BC8416920D > john_doe_public_gpg_key.asc

# Private key
$ gpg --armor --export-secret-keys 2EC378BC8416920D > john_doe_private_gpg_key.asc

Remove keys

Now that we have the key pair, let’s store it somewhere safe and let’s remove the keys to pretend we are importing someone else’s key to encrypt something for them.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ gpg --delete-keys 2EC378BC8416920D
...
pub  rsa4096/2EC378BC8416920D 2024-01-10 John Doe (Personal encryption and signing GPG key) <john.doe@somewhere.com>
Delete this key from the keyring? (y/N) y

$ gpg --delete-secret-keys 2EC378BC8416920D
...
sec  rsa4096/2EC378BC8416920D 2024-01-10 John Doe (Personal encryption and signing GPG key) <john.doe@somewhere.com>
Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y

Import public keys

Let’s say you want to send to John Doe something that only they can read. You would import their public key like this:

1
2
3
4
5
$ gpg --import john_doe_public_gpg_key.asc
...
gpg: key 2EC378BC8416920D: public key "John Doe (Personal encryption and signing GPG key) <john.doe@somewhere.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1

Encrypt

With the public key available, you can encrypt some content as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ echo "my secret message" > not_so_secret_message.txt
$ gpg --encrypt --recipient 2EC378BC8416920D --output secret_message.txt.asc not_so_secret_message.txt

# Check for the encrypted content
$ cat secret_message.txt.asc
...
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       β”‚ File: secret_message.txt.asc
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   β”‚ οΏ½^B^L^C^L>οΏ½
   2   β”‚ οΏ½οΏ½ΡΏ^A^P^@οΏ½οΏ½9=^SJοΏ½    ^XοΏ½-οΏ½οΏ½^Y^ZοΏ½οΏ½οΏ½sοΏ½οΏ½v[οΏ½xοΏ½^GοΏ½^OutI)rxοΏ½οΏ½οΏ½οΏ½οΏ½n��ψHZIοΏ½οΏ½οΏ½οΏ½οΏ½L^WοΏ½p eοΏ½οΏ½οΏ½Kyz^SοΏ½οΏ½&οΏ½οΏ½^Y?οΏ½οΏ½9οΏ½Χ¨PοΏ½οΏ½S��݈^mοΏ½isοΏ½<οΏ½BοΏ½οΏ½οΏ½q~^UοΏ½οΏ½οΏ½οΏ½w^NΨ¨οΏ½:^MοΏ½οΏ½οΏ½οΏ½c]οΏ½οΏ½[LοΏ½^?\οΏ½5οΏ½IοΏ½^ZοΏ½Q'οΏ½^VοΏ½οΏ½οΏ½οΏ½^WοΏ½^@+οΏ½NοΏ½0οΏ½XFοΏ½ήœί‹uοΏ½έ»5οΏ½,οΏ½X9@οΏ½οΏ½    οΏ½οΏ½οΏ½$οΏ½^KοΏ½rοΏ½   οΏ½οΏ½οΏ½NοΏ½&οΏ½οΏ½}οΏ½
       β”‚ οΏ½bοΏ½^WkΦΏ#bXQpοΏ½οΏ½οΏ½οΏ½οΏ½οΏ½^G^οΏ½οΏ½VNοΏ½^U}(^RoοΏ½m^KοΏ½οΏ½^Y^BοΏ½οΏ½rοΏ½Oy`οΏ½οΏ½^GοΏ½sοΏ½οΏ½οΏ½>οΏ½mοΏ½$^RοΏ½U%^^^ZοΏ½^]Ρ₯{οΏ½οΏ½οΏ½}οΏ½οΏ½OοΏ½οΏ½οΏ½t^QCIοΏ½-οΏ½οΏ½]tοΏ½οΏ½οΏ½οΏ½4vοΏ½DοΏ½οΏ½7οΏ½οΏ½οΏ½^FοΏ½}):YοΏ½-^Y_οΏ½οΏ½^@οΏ½ΫΏX^WοΏ½^USοΏ½^BοΏ½οΏ½^^^ZοΏ½YοΏ½οΏ½οΏ½NοΏ½οΏ½<οΏ½N!οΏ½3οΏ½^]οΏ½^RοΏ½_G^XetοΏ½οΏ½οΏ½οΏ½οΏ½οΏ½0^T^N^]^UH^E^?οΏ½hοΏ½yiBοΏ½
   3   β”‚ hοΏ½c$Ν€bοΏ½^BIЍ��^XοΏ½4οΏ½οΏ½^@οΏ½>gοΏ½VοΏ½οΏ½οΏ½οΏ½+=οΏ½*^]οΏ½οΏ½|οΏ½οΏ½WQοΏ½xοΏ½οΏ½^FlοΏ½οΏ½7οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½οΏ½qοΏ½^KQοΏ½?οΏ½#οΏ½οΏ½οΏ½οΏ½bf^PP οΏ½οΏ½dοΏ½οΏ½%οΏ½Ν€u^ZοΏ½1οΏ½N^BοΏ½hοΏ½we^YοΏ½^@,^A^^iAοΏ½$οΏ½οΏ½pοΏ½  T'οΏ½k9οΏ½aοΏ½$οΏ½οΏ½K^_οΏ½οΏ½\HοΏ½οΏ½[^UΤ“^A  ^B^PοΏ½οΏ½uΜ€ yοΏ½οΏ½^NοΏ½οΏ½οΏ½οΏ½οΏ½οΏ½4R5οΏ½οΏ½$\yοΏ½οΏ½οΏ½UοΏ½οΏ½pοΏ½οΏ½VοΏ½^VοΏ½οΏ½οΏ½bC}.οΏ½jοΏ½i`οΏ½οΏ½^BοΏ½οΏ½^PbοΏ½οΏ½^L^@οΏ½Δͺ
   4   β”‚ οΏ½2οΏ½5οΏ½οΏ½NοΏ½οΏ½OοΏ½;οΏ½[Η†i]^DfοΏ½^~οΏ½W^D6W^OοΏ½Ζ”QοΏ½οΏ½Υ­AlοΏ½^TοΏ½EοΏ½οΏ½Q^CοΏ½^]`οΏ½οΏ½οΏ½οΏ½~οΏ½^XοΏ½Τ½οΏ½οΏ½οΏ½^οΏ½ZqοΏ½^QοΏ½οΏ½KːBοΏ½
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Now, you can share the encrypted content with John Doe. Now imagine that they want to decrypt the message from a new computer and they would need to import their private key. They would do it like:

1
2
3
4
5
6
7
8
$ gpg --import john_doe_private_gpg_key.asc
...
gpg: key 2EC378BC8416920D: "John Doe (Personal encryption and signing GPG key) <john.doe@somewhere.com>" not changed
gpg: key 2EC378BC8416920D: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

Once the secret key is on the keychain, the decryption can be done as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ gpg --decrypt --output decrypted_message.txt secret_message.txt.asc

# See the original content
$ cat decrypted_message.txt
...
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       β”‚ File: decrypted_message.txt
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   β”‚ my secret message
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Using GPG as a security measure

Besides playing around with encrypted messages, GPG is used in another immensely useful feature in the routine of a software engineer or anyone using GitHub.

Let’s look at an example of its capabilities. In GitHub, you can store your public key and then use ~/.gitconfig to specify which private key should be used to sign the commit.

1
2
3
4
5
6
7
# ~/.gitconfig
[user]
    email = john.doe@somewhere.com
    name = John Doe
    signingkey = 0x2EC378BC8416920D
[commit]
    gpgsign = True

This local git configuration plus the Flag unsigned commits as unverified checked in the aforementioned feature would display a Verified badge in all of your signed commits while making commits you did not sign Unverified. Such a feature would e.g. prevent git-blame-someone-else from being used against you like it was with Linus Torvalds 🀦

An extra mile

GPG keys (and SSH keys too) can be stored on smart cards like a Yubikey. This adds an extra layer of security by preventing the use of a file that can be stolen by some malware on your computer.

Conclusion

  • You should set a password for your keys
    • This ensures that even if the file is stolen, people pretending to be you won’t be able to decrypt or sign anything on your behalf
  • You should have a right to privacy
  • Better safe than sorry

If you liked this article, import my public GPG key and send me some encrypted message <3