GnuPG Part 4 – Encrypt and Sign Files

GnuPG is typically used by other programs, such as email clients, that automatically use the keys contained in your keyring for encryption and signing. However it can also be used to manually encrypt, decrypt, sign, and verify files using gpg commands. While you may rarely need to do this in practice in the real world, it is a great exercise for understanding how public key encryption and signing works.

Create a Test File

We’ll need a file to work with for these examples, so we’ll simply create one named testfile.txt containing the text “This is a test.”

echo "This is a test." > testfile.txt

Encrypt the File

To encrypt a file, you must use the --encrypt option, the --recipient option to specify a recipient (i.e. the public key to encrypt with), and the --out option to specify an output file. The file to be encrypted must be at the end, which can make the full command feel a bit confusing at first.

gpg --out encryptedfile.asc --encrypt --recipient alice@example.com --armor testfile.txt

If you do not specify an output file with --out, the encrypted file will be automatically saved in the current working directory with .asc appended to the original file name if the --armor option was used, or .gpg if it was not.

If the recipient’s public key has not been signed, as explained in Part 3, you will get a warning prompt asking for confirmation.

Since we used the --armor option, we can view the contents of the encrypted file and see the ciphertext.

cat encryptedfile.asc
-----BEGIN PGP MESSAGE-----

hQGMA1XbZzXhupAbAQv/RswYvraPE4/JdZrTNQCQ9LNKTDqEGPqozI+jEvndSLJf
Jv6/yjjBUQIEMNV80iyYCGiogJAidelJb5+tqg/sClkxtLehBQl/9wlMIlkOa/h4
PKr6ykkBQxmG5b1wzplxcr3M84tnZ2EcgntgoXaufyKo7OBNrwrJieBqBx1SBKE7
Bg73jq+MMOWAKcWUoCVjbzt/BJawNj09SQnFIO23ybMiDw/fclJloH9AAFUTrVct
IVhBIGqp8CszzSusqXdju5sbvH2aJqU9EcRDVZ1kZi60/bMbkY74guWbuxS6b59E
My0DYN++X/Z0FiDKxW/vvZyawATBhXlpIWpo3IEG/4SfCs13x3GtcSBbvMyZAM9E
aqY7Lt6Cp7ytmH/E5sRl+njbS+5wc01g+3PBwBQ/dARTTHpzQ1aEZaIDhO3ZcjGD
p8Xpqfpe9jM9utf/kfiXeWYZtvTMlmsaROJo01hrrPieue2Rgu+PqlFz4i6aJZ+W
bMJBNoko9pRRjzx0paS60lgBQrdzleVbT1JaL+XrAs/Qx8S50kw3e9i/jCPBeBoF
cMN/uq0nIClFQfV5xLIJ+O/OxCyFLYtJbgMv0XQpALCdJkhQTNzRz6eAEQlW5u/Q
CCT4vbJMhE1V
=Yj49
-----END PGP MESSAGE-----

Decrypt the File

The recipient can decrypt the file with the --decrypt option (assuming they possess the corresponding private key).

gpg --out decryptedfile.txt --decrypt encryptedfile.asc

Unlike --encrypt, the decrypted output will simply be displayed if the --out or redirect options are not used to write it to a file.

Sign the File

Whereas encrypting a file provides confidentiality, signing a file provides integrity by allowing the recipient to verify that the file is truly from the purported sender; and was not modified in transit. In a way it is the functional opposite of encryption, since signing uses the sender’s private key and can be verified by anyone with the public key.

You can sign a file using the --sign or --clearsign options. The --clearsign option is similar to --armor in that it creates the signature in plain text rather than binary. I will use it in this example for the sake of clarity.

gpg --clearsign testfile.txt

If you do not specify an output file with --out, the signed file will be automatically saved in the current working directory with .asc appended to the original file name if the --clearsign option was used, or .gpg if the --sign option was used.

If you view the contents of the signed file, you will see the original content as well as the signature.

cat testfile.txt.asc 
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

This is a test.
-----BEGIN PGP SIGNATURE-----

iHUEAREIAB0WIQT+Ql29bFIAmkx/4jr2NmhDPqcKLQUCY5TIOwAKCRD2NmhDPqcK
LcXkAP0ddy6ezclw0OAKErdRKm5pNv37GWtsyNU3E387sm6hqgD/f8yonnMYKpRb
7FfBz7CcbLaINZxyWosm3GYHqUUmqVQ=
=oDZU
-----END PGP SIGNATURE-----

Verify the Signed File

The recipient can verify the signature on the file using the --verify option. The resulting output will tell you if the signature is good.

gpg --verify testfile.txt.asc
gpg: Signature made Mon 05 Dec 2022 11:13:35 AM MST
gpg:                using DSA key 197698E11D9E5B6787C4B55FE1A00903B0E16687
gpg: Good signature from "Bobby " [full]

Encrypt + Sign

Of course you can both encrypt and sign a file before sending it, and both functions can be done in the same command. This provides both confidentiality and integrity, and is the standard practice of most public key encryption systems.

To do this, use the --sign option after the --encrypt option.

gpg --encrypt --sign --recipient alice@example.com --armor testfile.txt

Note that when doing this, signing is performed as part of the encryption rather than as a separate function, so there is no option (or point) for using --clearsign. The signature will be encoded into the encrypted message. You can still use the --armor option.

The recipient can then use --decrypt on the file, and the signature will be verified as part of the decryption.

gpg --decrypt testfile.txt.gpg
gpg: encrypted with 3072-bit RSA key, ID B7A021383ADD3D0F, created 2022-12-01
      "Alice <alice@example.com>"
This is a test.
gpg: Signature made Sun 11 Dec 2022 03:27:45 PM MST
gpg:                using DSA key FE425DBD6C52009A4C7FE23AF63668433EA70A2D
gpg: Good signature from "Bobby <bobby@example.com>" [full]

<< GnuPG Part 3 – Import, Sign, and Trust Keys