Signing and Encrypting with GPG

March 29, 2019

Have you ever wanted to cryptographically verify that you were the one to sign a document

Installing gpg

brew install gnupg

Creating a Key

gpg --full-generate-key

Select RSA and RSA (default) and choose 4096. If you ever want to use this key to sign GitHub commits you need to use this configuration. Enter your information. Add whatever you want for the comment; I chose to leave mine blank.

Viewing the Key

gpg --list-keys --keyid-format LONG
# /Users/landon/.gnupg/pubring.kbx
# --------------------------------
# pub   rsa4096/6827462004B422D2 2019-03-29 [SC]
#       E9B1D409A94B77AB2BF2F4D86827462004B422D2
# uid                 [ultimate] Landon Turner <MY_EMAIL>
# sub   rsa4096/4948C17DB8DCC4C9 2019-03-29 [E]

This command shows which keys are in your pubring.kbx. LONG is specified here so we can see the id of the key. It is located after pub rsa4096/. Mine is 6827462004B422D2.

Signing a Message

I found The GNU Privacy Handbook on signatures very helpful for understanding what was going on.

There are a few ways to generate a signature for a message. If you pass in a file, it outputs a file containing the signature into the same directory. If you use stdin, it outputs to stdout. I will show several different commands for producing signatures.

The clear signed message wraps the original message along with the signature.

echo 'I solemnly swear that I am up to no good.' | gpg --clear-sign
# -----BEGIN PGP SIGNED MESSAGE-----
# Hash: SHA256
# 
# I solemnly swear that I am up to no good.
# -----BEGIN PGP SIGNATURE-----
# 
# iQIzBAEBCAAdFiEE6bHUCalLd6sr8vTYaCdGIAS0ItIFAlydkqEACgkQaCdGIAS0
# ItL2cg//de17P3+SxJVeJeoeqTWgZA7DlXiRZ09/DM4NhaY9RSIKao/IKeKUZMyU
# ty7JDP8dSir6kJlqJHY/IL50RAPXSoURY0Zg9svGfbUrNZOzhDT1IdZypxsL1xch
# luYDan8+fGiXQrOM5FnC9Kadhh4FKNxHXzPXyBNmFuBlB76dX9YELMhJAoiF89Wm
# WMCJ7S0he6kJnlle1RDPFGEUUrueRS5I31M3XNZjbdRvlwesf0oydUCYgNJjH9c0
# kJIKi3HEEDz4pfd7nw3xrAFD9LTlzdgxORCbeb2L6ThlWQudU8r1qUFcaGMWsXk+
# GAlL5mqFQ2oAGOe8irhtkpz1WuTzaHeOdxMxEZvCf1TCwMqceBM8HQoHvsMmJqyL
# 2L95gzzH3i5r9ZXhMOtngBjsrz7P/hhiiA0I2smvd5farY0KyQ0HxzMnoFuAjI/u
# CidR/qsxxUmFChbrznBeuZRsMHqVBkJuPWBuTZSjccI6UDI97B5b/LBPcPj11aTM
# rgOqlkT1VPiKaGUimgQwcMmtZM3EIpBDhhgiwED3gEjtl28pYF4kaQANClKU3Xg2
# Oj1VDyU9K3R+gpx6rQcAS3HIIYAVPG/q+S3JTz64rEs9H3K3Yo95hL8yTHSHnLXR
# xXyzRS4i4tye8rT+UMIBe2IVwmwcj5ISzvmBRqoxka4hN+Upc6Y=
# =/H0q
# -----END PGP SIGNATURE-----

In the next command, the -a --armor flag creates the nice ASCII version of the signature. Without -a it outputs binary into the terminal. I will use this flag throughout the rest of the post, as it works all gpg commands.

echo 'I solemnly swear that I am up to no good.' | gpg --sign --armor
# -----BEGIN PGP MESSAGE-----
# 
# owEBdwKI/ZANAwAIAWgnRiAEtCLSAcswYgBcnZK+SSBzb2xlbW5seSBzd2VhciB0
# aGF0IEkgYW0gdXAgdG8gbm8gZ29vZC4KiQIzBAABCAAdFiEE6bHUCalLd6sr8vTY
# aCdGIAS0ItIFAlydkr4ACgkQaCdGIAS0ItI6qw//Y5IwPOL0XrKlD/zM/nbt0C7k
# 2mJuY/PVH7nFM4wr/HpJwPHJX44rSXynOKwkBkMasuE3PFnFf9EB40iRTmtIKUMw
# dVj7yXiqn0KVlBc4s0D7jTaml4cGJpb+xR/1yqjp5OMqEsWgtPgItONYbSfKkWHV
# kdf6Ib/8jYYNxjoPLS+nJTdaGt84/lHnanslAK6/91d0JK34LZF53EDXH+zE89uA
# Z9rnVwX+T791Gi5XtEd1FEo+m8uGyW311ktklF/+hIVl7DpCWmGnPBDr1Vu6z1I3
# SNwcqAPXHz4/1Rhp4gvSn0ckUNe82xwZgz9pdrFFQo0YuCLXx6f2rqH0RptwrS47
# laa9vm2Gou/Yz7352qfnVIwgyYGF7gA2bOLOR7wY+FS2KezpZzB9vEwhfdOU7ecA
# j3Bk5oG2Bnn3+wmOMarQ4+rsJVFS3kQNUB9IsMCIdLbUwIFFU8gHE5SA5erOyoKd
# Ok4375Kh7DjBe2wPiBohvQLK0eaUU2ZYuQmWC2k6u1e6O4gT7rocePGqqOqEpaEO
# u6bDwWra2YUI5wlWifsnOeaQrPKnfCJiJEiMGioqt9OfKs+dVKFuPYtQpHjnrrJ2
# qnjuOO3UMWdK21EDoTKgXc2TuhH7Xp752Oya3K0g6PVlP4tI8xLdj8WMqEy7VjAW
# mewOVOMewnDW+ZA+yZQ=
# =sbgw
# -----END PGP MESSAGE-----

Run the same command, but output to a file. We can verify and reconstruct our message with this file.

echo 'I solemnly swear that I am up to no good.' | gpg -sa --output message.sig

When using the -s --sign flag, the message is also embedded in the signature. You can verify the signature and recover the message with the following commands.

gpg --decrypt message.sig
# I solemnly swear that I am up to no good.
# gpg: Signature made Thu Mar 28 22:55:34 2019 CDT
# gpg:                using RSA key E9B1D409A94B77AB2BF2F4D86827462004B422D2
# gpg: Good signature from "Landon Turner <MY_EMAIL>" [ultimate]

The signature does not have to be embedded in the signature, however. Using the flag --detach-sign you can create just the signature.

echo 'I solemnly swear that I am up to no good.' | gpg --detach-sign -a
# -----BEGIN PGP SIGNATURE-----
# 
# iQIzBAABCAAdFiEE6bHUCalLd6sr8vTYaCdGIAS0ItIFAlydmNEACgkQaCdGIAS0
# ItJStA//UbJUmFoK0z9ubGEibtZUbRKArxnbyDQ+ky8APo4nIEbq6K3sKRR5I1GS
# 3ofgGnGC9nF+JbZ00CFSsOi2CI1iLlxXjd1uYrqhLTbCwNnYzCykMcbt0ZP6K6rY
# pLAPSLfCGHikS0eth1UfBLZoWNAmVXCFb2LxkNRcbjQFRCp5yamBeye9N5yDbJ7v
# eBstgq79rnHUyBAhYjsFX9++Jb7je4T1juTjXD+JcPu0qOR3wznGNbI9b84yF44/
# nd7NZpL5+NJqyTc9ZvfP5cQ9nUTHyuvgwkHJZVHAgJIb3HEjcgbhtsaO7zHvCRBr
# l0MhXOSyvSfFwmsEyh7j9S5HqZ4WYpNN8IFhR7KgreTGoTPOvXySOrsNY0kF4L1w
# DdmbL6z8ygXa52FZSV61THNnB3aIu3H03YHJ5has2BihGsKL1OkZYZww1FewyOb+
# wsWsh3CM8UAuInW6ETM6Rhhdmsyi51bAXv6I5C8NqvvjBTO8vjt0qdPS4oazazsG
# 50h84B49+X1jK2KWg+oYsS9uXBS8GGrJmO//JeCYZArCxQJwbjel5FPyCKdVwDOs
# Eb32TMXCGsm3kxsuzf9BilC7B5MPjw9rh6d1EN0bi4y65WTIzBWOB17S/9/6Z3sz
# 7fVzfuFFlZgDEAh5cpZ4ZXfnRqM7uQybrgfgBwCda+mKsM73HAs=
# =P5rp
# -----END PGP SIGNATURE-----
echo 'I solemnly swear that I am up to no good.' > message.txt
gpg --detach-sign -a --output message.sig message.txt
gpg --verify message.sig message.txt
# gpg: Signature made Thu Mar 28 23:05:57 2019 CDT
# gpg:                using RSA key E9B1D409A94B77AB2BF2F4D86827462004B422D2
# gpg: Good signature from "Landon Turner <MY_EMAIL>" [ultimate]

Encrypting a Message

There are two basic types of encryption, symmetric and public key. With symmetric encryption, you take a key and encrypt a message. Whoever has that key can encrypt it. While you can use gpg to encrypt (see the flag -c --symmetric), this post is about using the keys generated earlier.

A key pair is made up of a private and public key. The public key is used to encrypt the message that only the private key can decrypt. As the names suggest, the public key is safe to hand out to the world, but the private key should never be given out. When you give out your public key, you enable anyone to encrypt messages only you can decrypt.

Generating a Public Key

gpg --export -a MY_EMAIL

Importing a Public Key

If you are trying to encrypt a file for someone else, you need their public key. To import it, use the following command gpg --import public_key.gpg. The key will be listed in your keychain when you run the command gpg --list-keys. When you run this command you will be shown their email address. This is used to specify who you are encrypting for.

Encrypting Using a Public Key

I found The GNU Privacy Handbook on encryption very helpful for understanding what was going on. You can include multiple recipients, and if you include your own, you will be able to decrypt it as well.

echo 'I solemnly swear that I am up to no good.' > message.txt
gpg --encrypt --output msg.gpg --recipient OTHER_EMAIL --recipient MY_EMAIL

Decrypting the Message

gpg --decrypt msg.gpg
# gpg: encrypted with 4096-bit RSA key, ID 4948C17DB8DCC4C9, created 2019-03-29
#       "Landon Turner <MY_EMAIL>"
# gpg: encrypted with 4096-bit RSA key, ID F3B7D450F6DB041A, created 2019-03-26
#       "Landon Turner <OTHER_EMAIL>"
# I solemnly swear that I am up to no good.

Using a Keyserver

There are websites that are gpg key repositories. You can upload your public key safely because there is no risk in exposing your public key. The wiki on key servers has a good list of key servers to use. I used the MIT keyserver.

One thing that struck me as strange is I did not have to verify with the keyserver that I was the one who owns this email. I would think an added security step would be email verification so that I couldn't go making the email tim@apple.com and tricking people into thinking I was Tim.

Note. The following commands were not working on my mac but were working on a remote centos instance. I will come back later and link the stack overflow that has my answer.

UPDATE: I was able to get the ubuntu keyserver keyserver.ubuntu.com to work. Thanks ubuntu gods.

Registering Your Keys

gpg --send-keys --keyserver keyserver.ubuntu.com 6827462004B422D2
# gpg: sending key 6827462004B422D2 to hkp://keyserver.ubuntu.com

Pulling Keys From Server

The following command will register my key in your keychain. You can use this to tweet encrypted messages at me if you wanted, or verify the signature of this post.

gpg --recv-keys --keyserver keyserver.ubuntu.com 6827462004B422D2
# gpg: requesting key 04B422D2 from hkp server keyserver.ubuntu.com
# gpg: key 04B422D2: public key "Landon Turner <MY_EMAIL>" imported
# gpg: Total number processed: 1
# gpg:               imported: 1  (RSA: 1)

Using With GitHub

You can upload your key to GitHub, register your key ID with git, then sign your commits using the -S flag. You can be certain the commit for this post was signed.

note: the following signature is built from the markdown file located in the github repo without the signature included.

-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEE6bHUCalLd6sr8vTYaCdGIAS0ItIFAlyeXtIACgkQaCdGIAS0
ItKthBAAkW9VPbXfT7885vmL1SbZa8CT5KymAzoDHwDzQF4FzEZfxj9gNseQzsKJ
y2mkFUtqN/DFneaAma9tgCA3+38fXTgXIoh8YYoTvVo2sszAuXuaARd0pPrHz2dd
R6GjmU7c2a/FFfN08s5QJDNf636ld/fteJlvqhK5dvsc8LFo5aQFskz2ZZ4IF+x6
6zDl00wN9UQwIC49iuDC76Gi6FxFxuJ0x9Xm1hl6OkhSmMwbSv2Anz/6waoiV185
GhRfr30vNk1qsu02tD8sOONwQACCpeE95UjEkp/bL3dIHOB8lEEyHgoLmVaxe2GO
ZMitRkKRPcmWXlluNW1ydIxwcuWXSqzpd5PrIQf1+EFE7+y+IYXM5SlXmw2RrQ0t
kadcXlOJ6OmqKYcHRnieL6mbSYKBRkVyLz6t6mUi5/cXJ9g/vJWa28nL/xc4nEI/
qn7GJTPd+U9NRQEMfz48eTxIYlB947Oli06AwM1ehN4E9kCNfQJSL7/nCGVKK/Nq
s9v0BIq1Zol6bMAGRMRlnAPGVBW9EWxuMDEGsJrXDhOSdRmnrv9EnngKluNR9h+q
/wD8N+s2Mp5pVEDreJGP+qMgVoLCfwxnFzQ+9o9mgz6dnc7b35S+XZGF2pZqqMB0
+C+ocTgh0GxXBQDdc8uQOU8u5WXH5OjjpGz86WSO4l7J74z5VrU=
=WrZd
-----END PGP SIGNATURE-----