Having full control over encrypted messages is sometimes just nice and crucial in other situations and/or places in the world. GPG, the Gnu Privacy Guard, is a commonly used tool to encrypt, decrypt, and sign secrets.
After reading this article, you will know how to use GPG. Let’s go!
Asymmetric Cryptography: A conceptual overview
Symmetric cryptography is easy to understand. You have two functions, encrypt and decrypt. Both use a key to generate the output:
encrypt(clear text, key) = cipher text decrypt(cipher text, key) = clear text
The issue with this concept is that you need to exchange the key in a secure way.
Asymmetric cryptography on the other hand makes use of a public/private key pair:
encrypt(clear text, receiver public key) = cipher text decrypt(cipher text, receiver private key) = clear text
An attacker cannot derive the private key from the public key. This means you can share the public key with everybody. The security of the system does not rely on the public key. Only the private key needs to stay secret.
If you want to understand how asymmetric cryptography can be used for signing documents, I recommend reading this article:
You need to install the command line application GPG, also called GnuPG. Don’t confuse it with Pretty Good Privacy (PGP in short). The first release of PGP was in 1991, GPG had its debut in 1999. This means there are over 20 years of security expertise in GPG.
Please note that the leading
$ only indicates that you should enter the
following command into the console. You should not enter $ in the beginning.
All leading/trailing spaces are ignored; they do not matter.
$ sudo apt-get install gpg
$ brew install gnupg
Generate GPG keys
$ gpg --full-generate-key
A couple of questions follow. They all suggest reasonable defaults. If you don’t know what to take, just go with the default.
In the end, you should see a message like this:
pub rsa4096 2021-05-16 [SC] 20E4E524CA0B5402260F01EB62EE7851D92F3ECE uid John Smith <[[email protected]](mailto:[email protected])> sub rsa4096 2021-05-16 [E]
You can verify that it worked by listing your keys:
$ gpg --list-keys gpg: checking the trustdb gpg: marginals needed: 3 completes needed: 1 trust model: pgp gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u /home/johnsmith/.gnupg/pubring.kbx ----------------------------- pub rsa4096 2021-05-16 [SC] 20E4E524CA0B5402260F01EB62EE7851D92F3ECE uid [ultimate] John Smith <[[email protected]](mailto:[email protected])> sub rsa4096 2021-05-16 [E]
The 20E4E524CA0B5402260F01EB62EE7851D92F3ECE is the ID of the keypair. To make the following simpler, we store it in a variable:
$ export GPGKEY=20E4E524CA0B5402260F01EB62EE7851D92F3ECE $ echo $GPGKEY 20E4E524CA0B5402260F01EB62EE7851D92F3ECE
Create a Backup!
Losing your private key is a shame. Now you need to share it in a secure manner with all your contacts again. To prevent it, create a backup.
The Bitcoin community has figured out a way to create a 12-word combination that generates the seed for generating the key pairs (BIP44). This is pretty amazing as you can now write down those 12 (up to 24) words and recreate the key files! GPG is working on this feature (T169). Until this is done, you need to store the private key in a secure way. Maybe two USB sticks that you deposit in secure locations.
$ gpg -ao my-private.key --export-secret-keys $GPGKEY
The file my-private.key looks like this:
-----BEGIN PGP PRIVATE KEY BLOCK----- olGdwDBQAAzBeETABsuGf/ALnExpZDlNpG9kJ4oCfJg+QEDVpMjytNOGGyj/A5h0 ... ... -----END PGP PRIVATE KEY BLOCK-----
Share the Public Key
You can share your public key in two ways. ASCII-armored or via key server.
Share public key via copy-paste
You can directly share an ASCII version of the binary data:
$ gpg --export -a $GPGKEY
This will print a long section starting with
-----BEGIN PGP PUBLIC KEY BLOCK----- ... ... -----END PGP PUBLIC KEY BLOCK-----
You can also pipe that block directly into a file:
$ gpg --export -a $GPGKEY > public_key.asc
This pure text can easily be shared in a web form, e.g. Github uses this.
Share public key via key server
$ gpg --send-keys --keyserver keyserver.ubuntu.com $GPGKEY
Others can then search for a public key via
Please note that the keyserver does not validate that the user who generated the GPG key ever had access to [email protected] !
Encrypt a file
$ gpg --output doc.gpg \ --encrypt \ --recipient [email protected] \ plain-text.pdf
Now you can share doc.gpg and only the holder of the key behind [email protected] will be able to decrypt the message.
Decrypt a file
$ gpg --output decrypted.pdf \ --encrypt \ --recipient [email protected] \ message.txt
⚠️ The decrypted file can still be malware. Don’t execute fishy stuff.
Sign a file
By signing a file, you essentially encrypt it with your private key. This way, everybody can decrypt it with your public key. And everybody knows that only you can possibly have encrypted it.
$ gpg --output signed-message.sig --sign message.txt
This produces a binary file called signed-message.sig . This is a binary file that is not readable without using your public key to decrypt and verify it:
$ gpg --output destination.path.txt --decrypt doc.sig gpg: Signature made So 16 Mai 2021 17:26:56 CEST gpg: using RSA key D1E632346B642680EF360D696901E782EF663EC4 gpg: Good signature from "Martin Thoma (Generated on 2021-01-15 for private use) <[[email protected]](mailto:[email protected])>" [ultimate]
If you have a text file, you can “clearsign” it. That means the message is readable in plain text and the signature is in the same file:
$ gpg --clearsing my-special-message.txt
It produces the following:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 Dear reader, This is a simple example message. Best, Martin -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEE0eYyNGtkJoDvNg1paQHngu9mPsQFAmChOooACgkQaQHngu9m PsQ6GBAAqRgP7dsD8isQk2U+K+6Ocl4T5G+DavgmxtKcjzaJQyuTY7gfjDTzLg0m 6VUzGzSZeq3A7XyJHEN4tn8LCi9Yapw/rwajNdEoeI3Vuag9/hMYo01mOuJMkbq8 5wCcb9qwoHg+4WHCDo0oSBmXsbZl8wVkIWPvjC7EnqduNkMOEnARGqdgzKeqL+XM iKhP78rK+j1enrWDdnmMmNWz1xZcBEvtF0R8RZhwtKs4JxJFDC51y1HXBJwej8iY oYvcT5Hov6oP4CwTgkAeMUJdQpePUPSFi8YMc2cTruaanP5hgYud9ZrJ2jURU17i KXTmgOwX20BHiqQGY4PnnZKX9cjrIfKlMKcXd/owqkXx/iXOs3CkiXyg3yV4xpxf 72s9r32PE4dCZllomKarEGyNTqLmTJsfDpfxZLVeUE05e5El2HcUrn44eD4EL1+/ 0wxUrkxUeNYNnbT51A65NLYHZ44GDBhOhXGqJd8/k2DcMgAtL1ifrMSL4XxSa2nP fAdykEh/Dph/QXlybuJpdq/Up6qacGulY3AjqwzdrwQl++0oh4uvFqCHHKTccWWN ClUDCfVhmlaEFDf88MLcoRZ57uQbCXYNnkOpMx3FGqTlawZz/lbaisFV3UfNHgr8 jpCE1lYIpqkwrpvKJ8VE8XeGcTz8oHqJa0ZJxvDAdDK9mp19MhU= =7cya -----END PGP SIGNATURE-----
To verify the message.txt.asc, you sadly need two steps:
$ gpg --detach-sign -o sig.gpg message.txt.asc $ gpg --verify sig.gpg message.txt.asc gpg: Signature made Mo 17 Mai 2021 23:25:16 CEST gpg: using RSA key D1E632346B642680EF360D696901E782EF663EC4 gpg: Good signature from "Martin Thoma (Generated on 2021-01-15 for private use) <[[email protected]](mailto:[email protected])>" [ultimate]
Dealing with Breaches: Revocation Certificates
Any system will break eventually. The question is only when it will break and how you deal with it.
When (and only then ⚠️) your private key becomes public, you want to tell the world that this private key should no longer be used. This is what you use a revocation certificate for.
$ gpg --output revocation.crt --gen-revoke [email protected]
The file looks like this:
-----BEGIN PGP PUBLIC KEY BLOCK----- Comment: This is a revocation certificate iQJQBCABCgA6FiEEve8XTzI4e8gcXLrLSL/usUTi8owFAmCi45kcHQNKdXN0IGZv ciBleGFtcGxlIGJsb2cgcG9zdAAKCRBIv+6xROLyjGr+D/9+kHdBGjOP6pjN9I1I OffsUEIewwU5EHkIA0fK4ujlk/POqt5soKpEHKEduVZXRKE7M76VwdRl8jRu+0+7 8ODxcVV5HNeN49kjWsN6K2CL9iweKHo49CBQ7MaA5dhRAhv/t5LxMax2j2tI5WHV j8ieS3qJCkY+QjzrXqeueHxTFZeRLX/HTdDbymhH3RpF8LSY3EIsEG2VLAbnUke2 IzP/zhxDqnaEZW4GGsHmYGWur+TcyV6Vh7NZ2rVtaPY9U11906xfVbuVZy4adAG5 SE2pqrXbJPPFnObK1WnwIiOZSnVeu3oEnfrK8kCAesxqmDnutRohlga6aKdOvKPE s1iJGwKJsjeF89TlUwEWVbDPFdBHPq7Yo4YA7YXHpls2hOBrBifgK0oxyl1um+fl m4z6qtkkMq3CB7qQUOftsvA/u+y1amepKCuOZTdQVOsZNAPSaDtz1onbaJWlowXi XRQWKMoGQ3RNp2m9raS1VRpdV8Y5f+NIqGJi85l8NT/KQSpQIxcO69VpHtFj0NVj iTwZT50WHbVN8lw2W1mImg3AZvM+pLlpE8mr+XFrjqRHnYCpMh44/inzPKFaOjgM L7DGq8P57SFs9Kg9TjHz6lx4VF/8GmZUx/cw0yoQbeu7QOWW7jY9gi0wLq2ZbI5I /2y8FtUVS4Pr9SLW8gqeMzMEBA== =i/uQ -----END PGP PUBLIC KEY BLOCK-----
It can be imported like this:
$ gpg --import revocation.crt $ gpg --list-keys ... pub rsa4096 2021-05-17 [SC] [revoked: 2021-05-17] BDEF174F32387BC81C5CBACB48BFEEB144E2F28C uid [ revoked] John Smith <[j](mailto:[email protected])[email protected]>
And let the keyserver know:
$ gpg --keyserver keyserver.ubuntu.com --send-keys $GPGKEY
Please be aware that sending GPG-encrypted messages only hides the contents of the file. It does not hide meta-data such as the message size or the sender/receiver of the message.
You can obfuscate the size by appending padding text, e.g. something like a lorem-ipsum text. An attacker could still figure out a maximum message size.
You can obfuscate the receiver by putting the message out in public, e.g. on your personal website. Or using a public computer to generate a new Gmail account and exchanging GPG-encrypted messages via those. But then you need to make sure you’re actually talking to the right person … this problem is hard.
If you exchange messages, you might also want to be able to repudiate the messages: If any part of the conversation went public, you want to be able to deny that you’re the author. The solution here is simple: Share your private key. The problem is that you would need to do that regularly.
If you are interested in other security and privacy features you might want to have, I highly recommend reading “SoK: Secure Messaging” (IEEE Symposium on Security and Privacy, 2015) by Unger, Dechand, Bonneau, Fahl, Perl, Goldberg, and Smith.