PGP overview

This page give a quick intro to PGP signing with just enough practical examples to enable you to do what you want to do, be that checking the signature of a download, or to generate a key and sign files so others can check the signature to verify that they actually came from you.

Note: all of the examples here use the Hax0rbana Signet signing key as the public key that will be doing the signing and used for verification. If you are verifying anything other than Signet, the fingerprint will not be 741EF6C759139E2DC30CF6BCF48EAC5191E53074, but rather some other equally long string of hexidecimal characters. Similarly, substitue the filename of the thing you're verifying and their corresponding .sig files.

Quick reference

For those who keep coming back to this page because they remember the general process but not the the exact commands to run, this section is for you.

# Obtain key from keyserver
gpg --recv-key 741EF6C759139E2DC30CF6BCF48EAC5191E53074

# Check signature
gpg --verify signet-0.9.18.tar.xz.sig signet-0.9.18.tar.xz

# Generate your own signing key
gpg --full-generate-key

# Sign a file
gpg --detach-sig --local-user 741EF6C759139E2DC30CF6BCF48EAC5191E53074 < signet-0.9.18.tar.xz > signet-0.9.18.tar.xz.sig

Checking signatures

Checking the signature of a file verifies that the person who controls the signing key has signed it. Generally speaking, that means that they've either created it or attested that it is legitimate in some way.

These instructions are specifically about detached PGP signatures, which is likely what people are talking about when they just say to "check the signature" of a download. The overall process is as follows:

  1. Download the file you want to verify
  2. Download the matching signature file (often ends in .sig)
  3. Download the public key of the person who signed (if you don't already have it)
  4. Use a tool like GPG to verify the signature

Downloading the file and signature will be specific to whatever you are downloading. As an example, if you wanted to check the signature for Signet, you would get the file and the signature from the downloads page.

There's a separate section for Obtaining public keys that you will need to read to get the key before you can verify the signatures. If you've already verified a signature from this person before, you will not need to obtain their public key again unless it expires (in which case you'll need to get their new public key).

The example below will verify the signature of signet-0.9.18.tar.xz

gpg --verify signet-0.9.18.tar.xz.sig signet-0.9.18.tar.xz

The important things to look for in the output of that command are:

This verifies that the signature is legitimate, and says what key is was signed with. That long hex number should always match the key fingerprint that is listed on the download page. In this example, that would be here.

If you have not marked the public key as trusted, gpg will show you a warning similar to the one below.

gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 741E F6C7 5913 9E2D C30C  F6BC F48E AC51 91E5 3074

This indicates that while it's cryptographically proven that the signature was valid, it's not sure that this key ID actually belongs to the name/email address that it claims to belong to. For more information on the risks of a key's name/email not being accurate, see the Obtaining public keys section.

To mark this key as trusted, you can use the command below. This will set the trust of the key so gpg knows that you've verified that the fingerprint matches the claimed owner. After running this, you should be able to verify the signature without getting any warnings.

echo "741EF6C759139E2DC30CF6BCF48EAC5191E53074:6:" | gpg --import-ownertrust

To see the trust level, you can use:

gpg --list-key 741EF6C759139E2DC30CF6BCF48EAC5191E53074

The line that begins with "uid" will say "[ unknown]" if you have not marked it as being trusted, and "[ultimate]" if you have marked it as being trusted.

While making the key as trusted is optional, it is recommended, as it's a bad idea to get in the habit of ignoring warning messages from gpg. Once day it may be a different, important warning, and you may not notice if you are accustomed to there being a warning for every verification.

For full documentation, see the gpg documentation.

Obtaining public keys

Obtaining the correct public key one of the most security critical steps in signature verification. It generally only needed to be done once (unless the key expires, in which case you'll have to do it again) and you need to make sure that the key fingerprint belongs to the actual authors that you intend to trust.

If the signer uploaded their keys to public key servers, gpg can often download it from there using the key fingerprint.

gpg --recv-key 741EF6C759139E2DC30CF6BCF48EAC5191E53074

If it is not on public key servers, you will have to manually downloading the key. Key fingerprints are typically listed on download pages, which use HTTPS. For typical use cases, the HTTPS connection is sufficient to verify that the web page is legitimate and you can trust this key. The fingerprint, and the key itself, are also frequently included in the git repos that contain the source code of programs you are verifying. For the ultimate verification, you would meet with the person face to face and have them tell you their PGP key's fingerprint.

The commands below can be used to check the signet key's fingerprint and then import the key.

gpg --show-key signet.pub
gpg --import signet.pub

The reason verifying the fingerprint and not just the name and email address of a PGP key is so important is because anyone can generate a key saying that are anyone they want to claim to be. If you want to see this for yourself, see the Generating keys section. You can claim you are anyone, but you will have a different key and thus a different fingerprint.

Generating keys

The Gnu Privacy Guard (gpg) tool can walk you through the process of creating a PGP key. It will ask you a number of questions, if you're not sure what to answer, selecting the default is likely going to be fine.

gpg --full-generate-key

The details of why to choose one algorithm over another of what is an acceptable key length is beyond the scope of this document. To make a key that will be secure and widely compatible, we suggest 4096-bit RSA keys. We also suggest using the comment field blank, as it frequently leads to confusion in the future. If your key expires, it will mean everyone has to go re-download your pulic key to verify any signatures, so you will likely want this to be some number of years, if you have any expiration date at all.

After you generate your PGP key, you will likely want to back it up. Keep in mind that exporting your key will result in an unencrypted backup. So you will likely want to encrypt the backup in some way. This could be by using Full Disk Encryption, putting it in your password manager such as KeePassXC, using OpenSSL to encrypt it, or even putting it in an encrypted zip file. The examples below shows writing it out to disk without encryption, encrypting with OpenSSL, and printing it out so you can copy and paste it into your password manager.

# To export your key, you will need to fingerprint to tell gpg which key you want to export
# This example uses the Hax0rbana Signet signing key

# Export to an unencrypted file
gpg --armor --export-secret-keys 741EF6C759139E2DC30CF6BCF48EAC5191E53074 > signet.priv.asc
# To import that key:
cat signet.priv.asc | gpg --import

# Export to an OpenSSL encrypted file (will prompt for a password)
gpg --armor --export-secret-keys 741EF6C759139E2DC30CF6BCF48EAC5191E53074 | \
	openssl aes-256-cbc -salt -pbkdf2 -out signet.priv.asc.enc
# To decrypt (will prompt for the password) and import:
cat signet.priv.asc.enc | openssl aes-256-cbc -d -pbkdf2 | gpg --import

# Print exported key on the screen so it can be put in a password manager
gpg --armor --export-secret-keys 741EF6C759139E2DC30CF6BCF48EAC5191E53074

You will also want to export your public key so you can publish it for everyone who wants to verify your PGP signatures. Below is an example that does this for the Hax0rbana Signet key.

gpg -a --export 741EF6C759139E2DC30CF6BCF48EAC5191E53074 > signet.pub

Signing

This assumes you have generated a key on the machine where you want to do the signing, or you've imported a key to that machine. If this is not the case, see the Generating keys section.

The --detach-sig argument is what tells gpg that you want to do a detached signature. In the example, the key that should do the signing is also being specified to make sure the correct key is used for signing (without the --local-user argument it would use whatever is set as the default signing key). The file to sign comes in on standard in, and the signature comes out on standard out. For full documentation, see the gpg documentation.

gpg --detach-sig --local-user 741EF6C759139E2DC30CF6BCF48EAC5191E53074 < signet-0.9.18.tar.xz > signet-0.9.18.tar.xz.sig