Sign files and verify OpenPGP signatures with GnuPG
To sign a file, run gpg --armor --detach-sign file. This makes a separate file.asc signature that you publish next to the file. To check a signature, run gpg --verify file.asc file. Then make sure the fingerprint GnuPG prints belongs to the person you expect.
What a signature proves
A signature is made with a secret key over a hash of the data. When it checks out, you know two things: the data has not changed by a single bit since it was signed, and it was signed by the secret key that matches a certain public key. It does not tell you who owns that key. You learn that by checking the fingerprint, which is the step most people skip.
Three kinds of signature
| Command | Result | Use it for |
|---|---|---|
--detach-sign (-b) | A separate signature file: file.sig (binary), or file.asc with --armor | Software releases, documents, anything where the original file must stay untouched. The recommended choice. |
--sign (-s) | One file, file.gpg, holding the data and the signature together | Sending a signed file that the recipient opens with gpg --decrypt. Often combined with --encrypt. |
--clear-sign (--clearsign) | Readable text wrapped in -----BEGIN PGP SIGNED MESSAGE----- lines | Legacy uses only, such as short notices pasted into forums. Has pitfalls; see below. |
Make a detached signature
gpg --armor --detach-sign myapp-1.0.tar.gz
GnuPG asks for your passphrase and writes myapp-1.0.tar.gz.asc. It starts with -----BEGIN PGP SIGNATURE-----. Publish both files. If you have more than one secret key, choose which one signs with --local-user (-u):
gpg --local-user alice@example.org --armor --detach-sign myapp-1.0.tar.gz
Leave out --armor to get the smaller binary myapp-1.0.tar.gz.sig. Both formats verify the same way.
Verify a detached signature
Always give both file names: the signature first, then the data.
gpg --verify myapp-1.0.tar.gz.asc myapp-1.0.tar.gz
If you have the signer’s public key and have checked it, the result looks like this:
gpg: Signature made Wed 04 Nov 2026 02:01:53 AM EST
gpg: using EDDSA key 194E1A7919EA1A3228125B7DEAAC1E97B05EF7A4
gpg: issuer "alice@example.org"
gpg: Good signature from "Alice Example <alice@example.org>" [ultimate]
If even one byte of the file has changed:
gpg: BAD signature from "Alice Example <alice@example.org>" [ultimate]
and the exit code is 1 instead of 0. If you do not have the signer’s key at all:
gpg: Can't check signature: No public key
In that case get the key, preferably from the signer’s own website or by email address (gpg --locate-keys), and check its fingerprint before you trust the result.
Do not rely on a single file name. gpg --verify file.asc on its own makes GnuPG guess the data file by removing the suffix. The manual says this habit is “strongly discouraged”. Name the data file explicitly.
Understand the trust warning
For a key you have imported but not certified, GnuPG 2.5 shows a good signature like this:
gpg: Good signature from "Werner Koch (dist signing 2020)" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
6DAA6E64A76D2840571B4902528897B826403ADA
GnuPG 2.4 prints the last line as Primary key fingerprint: 6DAA 6E64 A76D 2840 571B 4902 5288 97B8 2640 3ADA. The signature itself is valid. The warning only means you have not yet told GnuPG that this key really belongs to the named person. Compare the fingerprint with a fingerprint from a source you trust: the project’s HTTPS website, a printed card, or the person themselves. If it matches, you can record that with a local certification, and the warning goes away:
gpg --quick-lsign-key 6DAA6E64A76D2840571B4902528897B826403ADA
(Type the fingerprint without spaces.) The bracketed word shows the key’s validity: [unknown] means not checked, [full] means certified by you or by someone you trust, and [ultimate] means one of your own keys. For the background, see Key signatures.
Check a fingerprint before you import
To see what is inside a key file without adding it to your keyring, use --show-keys:
gpg --show-keys alice-public.asc
pub ed25519 2026-11-04 [SC] [expires: 2029-11-03]
61E9031CF73B25CFB41E05738B8486FD22E7DEC3
uid Alice Example <alice@example.org>
sub cv25519 2026-11-04 [E]
A4D97423D2602F9A0B060387011466D44C6CD16E
Compare the full 40-character fingerprint, not just the last 8 or 16 characters. Short key IDs can be faked (HKP protocol).
Clear-signed text, and why to avoid it
gpg --clear-sign notes.txt
This writes notes.txt.asc:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Meet at 10
-----BEGIN PGP SIGNATURE-----
iKQEARYKAEwWIQQZThp5GeoaMigSW33qrB6XsF73pAUCaurYYRsUgAAAAAAEAA5t
...
-----END PGP SIGNATURE-----
It looks convenient, but the GnuPG manual and a December 2025 GnuPG blog post both advise against it. Only the part between the marker lines is covered by the signature. Lines starting with a dash are escaped. And text shown in a terminal can be disguised with escape codes. If you must check a clear-signed message, have GnuPG write out exactly what was signed, and read that:
gpg --verify --output signed.txt notes.txt.asc
For new work, use a detached signature. For email, use PGP/MIME in a mail program (Email encryption).
Signatures in scripts
A script should not just look for the words “Good signature”. Two safer methods:
gpgvchecks a signature only against the keys in a keyring you give it, and returns success only for a good signature from one of them:gpg --dearmor --output release-keys.gpg release-keys.asc gpgv --keyring ./release-keys.gpg myapp-1.0.tar.gz.asc myapp-1.0.tar.gz--assert-signer(GnuPG 2.4 and 2.5) makesgpgexit with 0 only if a valid signature was made by the fingerprint you name:gpg --assert-signer 6DAA6E64A76D2840571B4902528897B826403ADA \ --verify myapp-1.0.tar.gz.asc myapp-1.0.tar.gz
With --batch, verification stops at the first bad signature. Add --proc-all-sigs if you need a status for every signature. Verify downloads uses both methods on real downloads.
Common mistakes
- Signing with the wrong key. Check with
gpg --list-secret-keys, and use-uto choose the key. - Re-saving a file after signing. Changes to line endings or character encoding break the signature. Sign the final file and copy it in binary mode.
- Getting the key from the same place as the file. If an attacker controls the download server, they can replace both. Get the fingerprint from somewhere else.
- Misreading an expired key. A signature made while the key was valid still shows as “Good signature … [expired]”, followed by “Note: This key has expired!”. The file has not been changed since it was signed, but check the project’s website for a newer key.
Sources
- Operational GPG Commands (--sign, --clear-sign, --detach-sign, --verify, --show-keys, --fingerprint), The GNU Privacy Guard manual
- Configuration options (--assert-signer, --proc-all-sigs), The GNU Privacy Guard manual
- OpenPGP Key Management (--quick-lsign-key), The GNU Privacy Guard manual
- Cleartext Signatures Considered Harmful, GnuPG blog (December 26, 2025)
- Integrity Check (example verification output), GnuPG
- Signature Key (GnuPG release signing keys), GnuPG