Use GPG to sign, verify, encrypt and decrypt files, emails, and commits

Last update: 2022-11-15

What is GPG?

"GnuPG is a complete and free implementation of the OpenPGP standard as defined by RFC4880 (also known as PGP). GnuPG allows you to encrypt and sign your data and communications; it features a versatile key management system, along with access modules for all kinds of public key directories. GnuPG, also known as GPG, is a command line tool with features for easy integration with other applications [...]"

GPG websiteopen in new window

GPG (GnuPG, open source) is different from PGP (proprietary). It primarily uses private/public keys to handle all encryption/decryption/sign/verify actions (you can also use symmetric, but isn't so fun).

Generating your GPG key

gpg --full-gen-key

# For older versions (including Windows and MacOS) you can use --gen-key if the parameter above fails
  1. Select the algorithm (use the default RSA and RSA);
  2. Specify the length (longer = better, currently you will find 4096-bit);
  3. Most of the times you don't need to select a validity period (better if you set a shorter period in case of leaks, but inconvenient sometimes);
  4. Type your full name and email when prompted;
  5. You may add a comment (usually shown close to your name/email);
  6. You will be asked for a password, use a strong one;

Time to list the GPG keys generated and saved at your profile:

gpg --list-secret-keys --keyid-format LONG <EMAIL USED TO GENERATE THE KEY>

# The output will look like this (this example shows two keys):
# gpg: checking the trustdb
# gpg: marginals needed: 3  completes needed: 1  trust model: pgp
# gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
# gpg: next trustdb check due at 2024-11-15
# /home/user/.gnupg/pubring.kbx
# ------------------------------
# sec   rsa3072/CXXXXXXXXC540 2022-01-01 [SC] [expires: 2024-01-01]
# uid                 [ultimate] Your name <>
# ssb   rsa3072/F3DC33A661677229 2022-01-01 [E] [expires: 2024-01-01]
# sec   rsa4096/84YYYYYYYYYYE 2022-01-01 [SC]
#       78C4E82E42C7AA5535B1233320ED984YYYYYYYYYYE
# uid                 [ultimate] Your name <>
# ssb   rsa4096/A7CCCCCCCCCC5214 2022-01-01 [E]

The ID, refered at the next commands, is the string after the / (E.g. CXXXXXXXXC540)

Exporting the GPG public key

Likely you will have to sent your PUBLIC key to someone, or store it at some system for the purposes listed later. To export as text, use the export parameter:

gpg --armor --export <ID>

# The output looks like this (always copy the key including the BEGIN and END lines):
# mQINBGN0XVIBEACgiLew1ciXwpKyLZqVMGJ/c70y7RyyrloQswm9rPdrJTIprDpk
# [a bunch of characters here]
# =R8RB

Remember: The Public key can be shared with any other person, the Private key should NEVER be kept secret.

You can also export it to a .gpg file, useful to skip the copy/pasting step:

gpg --armor --output <FILENAME>.gpg --export <ID>

Using GPG to sign up commits

You may sign just a few commits, using the -S flag:

git commit -S -m "Your regular commit message"

Or all commits, using the global config:

git config --global commit.gpgsign true

# Now all following commits will include the signature

If you find problems with the signature, try using gpg2 instead. Set for all repositories using git config --global gpg.program gpg2

Using GPG at Gitlab

Gitlab will show the verify sign along with commits, check their details at Gitlab documentationopen in new window

You can find users GPG public key using the url<username>.gpg.

Using GPG at Github

Github will show the verify sign along with commits, check their details at Github documentationopen in new window

Importing other users public keys to your profile

When encrypting or verifying the signature of a file you should ask their PUBLIC key, then import at your profile:

# Add the key received key to a file, or use the generated `.gpg` file
gpg --import recipient-pubkey.gpg

Using GPG to encrypt/decrypt files

The encryption works using recipient public key. Only the recipient can decrypt it using their private key. Note that you can only encrypt ONE file at a time, you may generate a text file or any other format, including .tar.gz.

Make sure to import the recipient public key before running the command

gpg --output encrypted-file.txt.gpg --encrypt --recipient file.txt

To decrypt, your peer must simply execute:

gpg --output file.txt --decrypt encrypted-file.txt.gpg

The command above will use the private key in order to decrypt the file.

Using GPG to sign/verify files

To generate a signed file is basically the same process of encryption, but use the --sign command. The sign will use your private key to sign (you can think as "encrypt") the file.

gpg --sign somefile.txt

It will generate a file with .gpg extension, containing the file and your signature.

To verify the integrity use the --verify. This command will use your public key to check the file.

gpg --verify somefile.txt.sig

You can also see the contents of the file using --decrypt:

gpg --output file.txt --decrypt signed-file.txt.gpg

Remember that this decrypt is executed using the public key of the sender, so the file contents are not hidden from anyone who has your public key (likely anyone, its public right?!).

Sign up or encrypt emails using GPG

You can use GPG also to sign or encrypt your emails. Thunderbird its the perfect tool to handle it, check Thunderbird documentationopen in new window on how to configure the client.

Note that most webmails (including Gmail) do not provide a client that can handle GPG. Your private key should never leave the safe place (your laptop). You can use Thunderbird to send/receive end-to-end encrypted emails via IMAP/SMTP/POP for supported providers.

Set default GPG key on Debian/Ubuntu

If you have multiple keys you can set your default key creating/updating the file ~/.gnupg/gpg.conf:

# First list all keys
gpg --list-signatures

# Create file using vim/nano/anyother editor
# ~/.gnupg/gpg.conf
# and include the contents
# default-key YOURIDHERE

If you don't set the default one, the first generated is usually the default.