Privacy Tools Guide

Downloading software from the internet always carries some risk. A man-in-the-middle attacker, a compromised mirror server, or a malicious package maintainer could substitute a backdoored binary for the real thing. PGP signature verification gives you a cryptographic guarantee that the file you downloaded was signed by the expected key — and that it hasn’t been altered in transit.

This guide walks through the full verification workflow using GnuPG on Linux, macOS, and Windows.

What PGP Signature Verification Actually Checks

When a developer releases software, they typically:

  1. Build the binary or archive
  2. Generate a hash of that file (SHA-256, SHA-512, etc.)
  3. Sign that hash with their private key
  4. Publish the .sig or .asc signature file alongside the download

When you verify the signature, GPG checks two things: that the signature was produced by the claimed key, and that the file matches what was signed. If either fails, the verification fails.

What it does not check is whether the signing key itself belongs to who you think it does. That requires importing and trusting the correct key first.

Installing GnuPG

Linux

# Debian/Ubuntu
sudo apt install gnupg

# Fedora/RHEL
sudo dnf install gnupg2

# Arch
sudo pacman -S gnupg

macOS

brew install gnupg

Windows

Download Gpg4win from https://gpg4win.org/ — it includes Kleopatra, a GUI frontend, and the gpg command-line tool.

Step 1: Obtain the Developer’s Public Key

You need the correct public key before you can verify anything. Sources in order of trustworthiness:

From a project’s official website (most common):

# Example: Tor Project key
curl https://dist.torproject.org/torbrowser/openpgp/signed-keyring.gpg | gpg --import

From a keyserver (use fingerprint, never just name/email):

gpg --keyserver keys.openpgp.org --recv-keys 0x4E2C6E8793298290

From a file posted on the project site:

gpg --import developer-key.asc

After importing, verify the fingerprint matches what the project publishes:

gpg --fingerprint 0x4E2C6E8793298290

The fingerprint must be verified out-of-band — check the project’s official site, their GitHub profile, or a signed announcement. Never trust a keyserver fingerprint alone.

Step 2: Download the Software and Signature File

You need both the file you want to verify and its signature. The signature file typically has the same name with .sig or .asc appended:

wget https://example-project.org/downloads/app-2.0.tar.gz
wget https://example-project.org/downloads/app-2.0.tar.gz.sig

Some projects publish a checksums file that is itself signed:

wget https://example-project.org/downloads/SHA256SUMS
wget https://example-project.org/downloads/SHA256SUMS.gpg

Step 3: Verify the Signature

Direct signature on the file

gpg --verify app-2.0.tar.gz.sig app-2.0.tar.gz

A successful verification looks like this:

gpg: Signature made Fri 14 Mar 2026 12:04:19 UTC
gpg:                using RSA key 4E2C6E8793298290
gpg: Good signature from "Alice Developer <alice@example-project.org>" [unknown]
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: A490 D0F4 D311 A412 3456  789A 4E2C 6E87 9329 8290

The “Good signature” line is what matters. The warning about trust is expected unless you’ve explicitly set a trust level for that key.

Signed checksums file

# First verify the checksums file itself
gpg --verify SHA256SUMS.gpg SHA256SUMS

# Then check the file hash against the verified checksums
sha256sum --check --ignore-missing SHA256SUMS

Both commands must succeed. The second check confirms the downloaded binary matches the hash that was signed.

Reading the Output Correctly

Good signature — the file was signed by the key and hasn’t been altered:

gpg: Good signature from "Alice Developer <alice@example-project.org>"

BAD signature — the file does not match what was signed. Stop immediately, discard the file, and report it to the project:

gpg: BAD signature from "Alice Developer <alice@example-project.org>"

No public key — you haven’t imported the signing key yet:

gpg: Can't check signature: No public key

Key expired — the key has an expiry date that has passed. Check whether the project has published a new key:

gpg: Note: This key has expired!

Setting Key Trust Level

The “key not certified” warning appears because GPG doesn’t automatically trust imported keys. If you’ve verified the fingerprint through multiple channels and are confident the key is legitimate, you can set a trust level:

gpg --edit-key 4E2C6E8793298290

Inside the interactive prompt:

gpg> trust
Your decision? 4
(4 = I trust this key fully)
gpg> quit

Future verifications against this key will no longer show the trust warning.

Automating Verification in Scripts

For package management scripts or CI pipelines, automate signature verification with a non-interactive check:

#!/bin/bash
set -euo pipefail

FILE="app-2.0.tar.gz"
SIG="app-2.0.tar.gz.sig"
EXPECTED_KEY="4E2C6E8793298290"

# Import key if not present
gpg --list-keys "$EXPECTED_KEY" >/dev/null 2>&1 || \
  gpg --keyserver keys.openpgp.org --recv-keys "$EXPECTED_KEY"

# Verify
if gpg --verify "$SIG" "$FILE" 2>&1 | grep -q "Good signature"; then
  echo "Verification passed: $FILE"
else
  echo "VERIFICATION FAILED: $FILE — aborting"
  exit 1
fi

Common Projects and Their Verification Methods

Project Key source Signature format
Tor Browser dist.torproject.org .asc direct
Tails OS tails.boum.org OpenPGP signed checksums
VeraCrypt veracrypt.fr .sig direct
GnuPG itself gnupg.org .sig direct
Debian ISOs debian.org/CD/verify SHA512SUMS.sign

What Verification Cannot Protect Against

Signature verification confirms authenticity — it does not guarantee the software is safe. A legitimate key can sign malware if the developer’s system is compromised, if the project has been acquired, or if the developer intentionally includes malicious code. Verification establishes origin; it cannot establish intent.

For high-stakes software, cross-reference release announcements, check reproducible build attestations where available, and monitor the project’s security disclosure history.

Built by theluckystrike — More at zovo.one