This GPG guide covers how to digitally sign data in various ways, explains the purpose of digital signatures, and shows how to verify them.
If you don't know much about GPG, it's worth starting with the first part of our GPG Guide which explains a lot of the background information which is required in order to understand what's going on.
When a sender uses a public key to encrypt data for a recipient, how is the recipient supposed to know if the sender is actually who they say they are?
The public key is available for anybody to use, so there needs to be a means for that sender to unequivocally prove that the data came from them.
GPG provides a way to do the above in combination with generating a signature (like a fingerprint) of the data which proves the data has not been tampered with.
The gist of the steps involved for digitally signing (and optionally encrypting) are:
- (1) The sender also has their own public/private key pair and have previously made their public key available to the recipient.
- (2) The sender's side will generate a hash (aka digest) of the original data.
- (3) That hash is then encrypted using the sender's private key and appended to the original data.
- (4) Then (optionally, as you'll see later) the whole lot can be encrypted using the recipient's public key.
- (5) At the recipient side (if the step above was carried out), the encrypted digitally signed data is decrypted using the recipient's private key.
- (6) The digital signature is decrypted using the sender's public key to reveal a hash/digest of the original data (this is the supplied hash or digest).
- (7) A recalculation of the hash/digest of the original data (without the appended signature) is carried out at the recipient side, if that matches the supplied hash, then the only person that could have sent the data is the real owner of the public key used to sign. Note that the matching hash proves both the integrity of the data and the identity of the owner, thus proving the data is authentic.
A digital signature also provides what is called non-repudiation, i.e. the signer can't claim they didn't sign the data whilst also claiming that their private key remains private.
Though this sort of digital signature is not required every time a sender sends data, in some cases it is vital that the recipient can prove the identity and authenticity of the sent data, in which case a digital signature must be used.
If a document, software, or some other data is available for public consumption then there is no need to encrypt it.
In such a case however, there may still be good reason for people to want to prove that the data is authentic (Originates from the specified creator/owner and has not been tampered with). This is where digital signatures can come in handy.
Using a digital signature alone (without encryption) only involves steps 1, 2, 3, 6, and 7.
There are two types of digital signature that gpg can apply. A normal signature, where the raw binary data of the signature is included with the original data. And a clear sign signature where the signature is added as readable text (a base64 ascii-armor signature). Commands to use both of these signature types are described below.
To use gpg for a clear text digital signature use the --clearsign option.
For example, to sign file.txt using this method you would use:
gpg --clearsign file.txt
The screenshot below shows this command in action, and a dump of the result (the original file.txt only contains a single line of text saying "This file is not meant to be encrypted, just signed!", file.txt.asc includes that along with the digital signature). Note that by default the name of the signed file has an appended .asc, you can control the name using the -o (or --output) option, eg:
gpg --output filename --clearsign file.txt
On the receiving side, the recipient can verify the signature (provided they have the sender's public key on their keyring).
gpg --verify file.txt.asc
To sign data normally, use the -s (or --sign) option. Using the same file.txt that we used above, we can sign like so:
gpg --sign file.txt
This will produce the file file.txt.gpg, the contents of which will contain our (readable) data along with what looks like unreadable garbage (this is the raw signature). Someone with the sender's public key can verify this in the exact same way as a clear sign signature by using the --verify option:
gpg --verify file.txt.gpg
When the sender also encrypts the data for the recipient to decrypt (i.e. all of the steps 1-7 above are carried out), the sender simply needs to combine the commands we used for asymmetric encryption with the -s (or --sign) option. The command below signs and encrypts for recipient Tutonics :
gpg -o file.enc -s -e -r Tutonics file.txt
In order to verify without decrypting, the recipient can run:
gpg --verify file.enc
Note that they'll need the senders public key on their keyring! To both decrypt and verify, the -d or --decrypt option will do both (i.e. it will automatically try to verify the signature if there is one present).
gpg -o original_file.txt -d file.enc
If the recipient does not have the sender's public key on their keyring for verification, the decryption will still work as usual, but following message will be displayed:
gpg: Can't check signature: public key not found
Also note that their public key may not be trusted, in which case you'll get a message like:
gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner.
If you know the owner (and really trust them) and have already verified their public key's fingerprint with them, then you may wish to adjust the "trust" setting for their key. Do so by using the --edit-key option, then from the gpg cli, run:
Set the trust level to 5: "I trust ultimately" (if that is actually the case!). Now the warning won't happen again when using their public key.
If you wish to leave the original file as-is and create a separate binary signature file, you can use the --detach-sign option. For example, using file.txt run:
gpg --detach-sign file.txt
This will produce the file file.txt.sig, which is made available to others along with the original data (file.txt in this case). To verify the authenticity of file.txt, you would run the following command (which assumes file.txt is in the current directory along with file.txt.sig):
gpg --verify file.txt.sig
or, if you've change the name of the file.txt to filename in the meantime or have it in another directory, you can specify the location of the original data file this way:
gpg --verify file.txt.sig /path/to/filename
Note that in each of the examples above, we could have signed using another private key (that's already on our private keyring) by using the --local-user option.
In the next GPG guide, we'll cover using gpg for symmetric encryption using various different algorithms.
Thanks to everyone who worked on GNU Privacy Guard (the GNU Projects implementation of the OpenPGP standard)