GnuPG
About GnuPG
GnuPG is a tool for secure communication.
According to gnupg.org:
GnuPG is a complete and free implementation of the OpenPGP standard as defined by RFC4880 (also known as PGP). GnuPG allows you to encrypt and sign your data and communications; it features a versatile key management system, along with access modules for all kinds of public key directories. GnuPG, also known as GPG, is a command line tool with features for easy integration with other applications. A wealth of frontend applications and libraries are available. GnuPG also provides support for S/MIME and Secure Shell (ssh).
Installation
GnuPG is available in most Linux distributions' package repositories:
- Debian:
apt-get install -y gnupg - Red Hat:
dnf install -y gnupg2 - SUSE:
zypper in -y gpg2
For Windows, you can install either the command-line tool or the full Gpg4win suite. Download it from the official site.
Quick Start
Tutorial - Preparation
We'll go through a brief tutorial below, using a Linux system. Let's prepare our system for that by running these commands:
Generating Keys
GnuPG uses public-key cryptography so that users may communicate securely. In a public-key system, each user has a pair of keys consisting of a private key and a public key. A user's private key is kept secret; it need never be revealed. The public key may be given to anyone with whom the user wants to communicate.
Let's get started with our own key first:
# Generate a key
gpg --generate-key
# Export the public key to share it later
gpg --export --no-armor --output mykey.gpg clifford.weinmann@azul.africa
That's it. Now we're ready to use the key to encrypt data.
Encrypting Files
To encrypt & decrypt an existing file, follow these steps:
# Encrypt an existing file
gpg --encrypt --output hosts.gpg /etc/hosts
# Inspect the files
ls -l /etc/hosts hosts.gpg
file /etc/hosts hosts.gpg
# Decrypt the file again, and save it to a new name
gpg --quiet --decrypt --output hosts hosts.gpg
diff /etc/hosts hosts
Note that most gpg command line options have shorter forms too, for example the above commands can be rewritten as:
# Encrypt an existing file
gpg -e -o hosts.gpg /etc/hosts
# Decrypt the file again, and save it to a new name
gpg -q -d -o hosts hosts.gpg
We'll stick to the longer form here for better readability.
Generating & Encrypting Passwords
This document was triggered by a need to share passwords securely.
Of course GnuPG can generate random strings to use as passwords, with:
Where 1 is a quality level, and 18 is the number of random bytes to generate (before Base64 encoding).
For some quick alternate ways to generate random strings to use as passwords, see Generate Passwords.
Now let's use GnuPG you can encrypt such a password and save it to a file:
Decrypt the file with:
A convenient way to manage such password files in an organized way is with th pass utility.
Tip: If you're pasting passwords into the command line, at least in bash, start the command with a space to prevent it from being added to the shell history.
Share Files With Others
How do we share encrypted data with others? Let's demonstrate this using 2 separate local user accounts. First, we'll create a new account for this purpose:
In a new terminal window, let's create a key for the new user:
$ sudo -i -u azuldemo
azuldemo$ gpg --quick-generate-key azuldemo@azul.africa
azuldemo$ cd /tmp/gpgdemo
azuldemo$ gpg --export --no-armor --output azuldemo.gpg azuldemo@azul.africa
azuldemo$ gpg --list-key --with-wkd-hash azuldemo@azul.africa
pub ed25519 2025-02-01 [SC] [expires: 2028-02-01]
3C9859929C83B53A9FB4CD52503503E3C82E9A5E
uid [ultimate] azuldemo@azul.africa
35j5icoafbu65ej4y5iz9fgjxojx5nmu@azul.africa
sub cv25519 2025-02-01 [E]
azuldemo$ echo -e 'expire\n0\ny\nsave\n' | gpg --command-fd 0 --edit-key azuldemo@azul.africa
Back in our own terminal, let's import the new user's key & sign it:
$ gpg --show-key --with-wkd-hash azuldemo.gpg
pub ed25519/503503E3C82E9A5E 2025-02-01 [SC] [expires: 2028-02-01]
Key fingerprint = 3C98 5992 9C83 B53A 9FB4 CD52 5035 03E3 C82E 9A5E
Keygrip = 0E6A6B153ECC60288CF9E58F6212684A2AAA8D75
uid azuldemo@azul.africa
35j5icoafbu65ej4y5iz9fgjxojx5nmu@azul.africa
sub cv25519/6D2DE5AB2F55DF1D 2025-02-01 [E]
Keygrip = 7870915BA0681AE0A5DDA49A615C49B35EF47596
$ gpg --import azuldemo.gpg
$ echo -e 'sign\ny\nsave\n' | gpg --command-fd 0 --local-user clifford.weinmann@azul.africa --edit-key azuldemo@azul.africa
Now we can encrypt some data to send to them:
$ gpg --quiet --decrypt my-password.gpg | gpg --encrypt --armor --recipient azuldemo@azul.africa > shared-password.asc
$ gpg --quiet --decrypt my-password.gpg | gpg --encrypt --armor --local-user clifford.weinmann@azul.africa --sign --recipient azuldemo@azul.africa > signed-password.asc
Back in our test user's terminal:
# Decrypt the password
azuldemo$ gpg --decrypt signed-password.asc
azuldemo$ gpg --quiet --decrypt shared-password.asc
# Import the sender's key so we can reply
azuldemo$ gpg --import mykey.gpg
# Sign the key with ours to indicate that we trust it - note "sign" and "save" subcommands below
azuldemo$ echo 'Got it!' | gpg --encrypt --armor --recipient clifford.weinmann@azul.africa > reply.asc
# Get rid of the trust prompt
azuldemo$ gpg --edit-key clifford.weinmann@azul.africa
pub ed25519/456757387702E12F
created: 2025-02-04 expires: 2028-02-04 usage: SC
trust: unknown validity: unknown
sub cv25519/FFFA8A60501A3000
created: 2025-02-04 expires: 2028-02-04 usage: E
[ unknown] (1). Quintin <quintin@example.com>
gpg> sign
pub ed25519/456757387702E12F
created: 2025-02-04 expires: 2028-02-04 usage: SC
trust: unknown validity: unknown
Primary key fingerprint: EFDB 050E 225A 587B 6AB8 96EF 4567 5738 7702 E12F
Quintin <quintin@example.com>
This key is due to expire on 2028-02-04.
Are you sure that you want to sign this key with your
key "azuldemo@azul.africa" (4DC72CE825EF2CF5)
Really sign? (y/N) y
gpg> save
# Create a reply message
azuldemo$ echo 'No trust prompt ;-)' | gpg --encrypt --armor --recipient clifford.weinmann@azul.africa
Tutorial - Cleanup
Clean up after demo (from our own terminal):
Sharing Your Public Key
Using GnuPG to encrypt our own files is great.
As demonstrated above, it is equally handy for sharing encrypted documents with others. In the example above, the both users were on the same machine, so we could just copy a file. In practice we need to find a better way to get our public keys to people who want to send us encrypted messages / files.
There are numerous ways to share your exported public key, including:
- Manually sending the key to someone via email / instant message / file share / web server etc. This works, but is a manual process.
- Publish it on a (public) key server. This eliminates the manual effort, but trust can be an issue - how does anyone know it's really your key?
- Share it via DNS records (
cert,pka,dane). This solves the above problems, but is complicated to set up. - Web Key Directory (WKD) publishes your public key on your own website, and is our preferred approach.
To use WKD, the owner of the key must first export their key, with:
gpg --export --no-armor --output azuldemo.gpg azuldemo@azul.africa
gpg --list-key --with-wkd-hash azuldemo@azul.africa
Send both the output file (azuldemo.gpg in the above example) and the output from the gpg --list-key --with-wkd-hash <key> command to your trusty local web administrator.
The administrator will then publish it on the website, using the WKD hash (the 32 character identifier before your domain name - 35j5icoafbu65ej4y5iz9fgjxojx5nmu in our earlier example) as file name. For azul.africa, this means:
- Publish it at
https://openpgpkey.azul.africa/.well-known/openpgpkey/azul.africa/hu/<hash> - Copy to
mu1.azul.ninja:/usr/share/nginx/openpgpkey/.well-known/openpgpkey/azul.africa/hu/<hash>
A third party that wants to send you a file can then import it automatically, with:
Once this is done, they can encrypt a file / message with you as --recipient.
This will prompt them with a message saying "It is NOT certain that the key belongs to the person named in the user ID". To avoid this prompt, they can ask you to verify your key signature (just like we all do with those SSH host keys 😁), and then sign it with their own key:
$ gpg --edit-key stan.lovisa@azul.africa
gpg (GnuPG) 2.4.4; 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.
pub rsa3072/73C483F3F7C91885
created: 2025-01-31 expires: 2027-01-31 usage: SC
trust: marginal validity: unknown
sub rsa3072/543F4A9B8A98ACD2
created: 2025-01-31 expires: 2027-01-31 usage: E
[ unknown] (1). Stan Lovisa <stan.lovisa@azul.africa>
gpg> sign
gpg: using "A9EA7F3D" as default secret key for signing
pub rsa3072/73C483F3F7C91885
created: 2025-01-31 expires: 2027-01-31 usage: SC
trust: marginal validity: unknown
Primary key fingerprint: B82D C217 0404 2277 71A4 2132 73C4 83F3 F7C9 1885
Stan Lovisa <stan.lovisa@azul.africa>
This key is due to expire on 2027-01-31.
Are you sure that you want to sign this key with your
key "Clifford Weinmann <clifford@weinmann.africa>" (9FD07C97758B1A18)
Really sign? (y/N) y
gpg> save
Further Reading
For a more thorough introduction to GPG, check out the GNU Privacy Handbook. The online English version is available here.