This is my attempt at a gpg guide.
Mainly intendet for my future self and enriched by many online resources
- GPG in General
- Symmetric vs Asymmetric
- Installation
- Managing Key Pairs
- Encrypting Files
- tar Archive Guide
- Signing Files
- GPG-Agent Cache
- Subkeys
- Handling Private Keys
- Backup
- Signing git Commits
- References and Sources
GPG aka GnuPG aka Gnu Privacy Guard
GNU: a recursive acronym meaning "**GNU's not Unix!**")
GPG (OpenPG) is the adaption of the encryption standard known as PGP (Pretty Good Privacy). It is mainly designed to use asymmetric public/private key cryptography but also has the option to symmetrically encrypt data.
Symmetric key cryptography uses the same key for both encryption and decryption. This means that both parties that want to communicate have to agree on the key beforehand. The main difficulty with symmetric key cryptography is the key exchange itself.
Asymmetric key encryption uses a private / public key pair. The public key is used to encrypt data for you and only the private key, which has to be kept secret, can decrypt the data.
Both schemes are used together for optimal performance. This means using asymmetric encryption to exchange a symmetric key that has been used encrypt data. This is faster because symmetric encryption is a lot faster than asymmetric encryption. This way both parties only need to know the public key of each other to exhange the symmetric key over an encrypted channel. The symmetrically encrypted data can then be sent over unsecured channels (assuming the passphrase is strong enough).
- Windows: gpg4win
- MacOS:
brew install gpg pinentry-mac
- Linux:
sudo apt-get install gnupg
On Windows most of the following functionality can be handled via the installed gpg4win GUI application called Kleopatra.
In this guide GnuPG version 2.3.4
was used.
gpg --version
gpg --full-gen-key
You will be prompted several things:
- Keypair kind (RSA & RSA or ECC are the 2 most likely options for you)
- Keysize (RSA), Elliptic Curve (ECC)
- Expiration Date for the key (this can be extended manually later on, so picking a key with an expiration is the safest option in case you lose the key)
- Name and email address
- Comment
- Passphrase: Choose a secure password to protect your key
-k = --list-keys
-K = --list-secret-keys
// List public keys only
gpg -k
// List all private keys available
gpg -K
//List all private keys with subkey fingerprints
gpg -K --with-subkey-fingerprints
gpg --fingerprint [KEYID] //without KEYID supplied it will list all fingerprints
gpg --delete-key KEYID
gpg --delete-secret-key KEYID
KEYID can be anything that identifies the key like the name of the owner, email, fingerprint etc.
-a = --armor (ASCII instead of Binary)
-o = --ouptut
// Public
gpg --export -a -o PUBLIC.asc KEYID
// Private
gpg --export-secret-keys -a -o PRIVATE.asc KEYID
Without --output specified gpg will print to stdout
Note: The secret key export includes a full export (because the public key and all secret parts are included in the private secret key)
// Public (your own or someone elses)
gpg --import PUBLIC.key
// Private
gpg --allow-secret-key-import --import PRIVATE.asc
You can and should publish your public for others to use it. You can either distribute it directly, add it to your website or use a public keyserver.
gpg --send --keyserver hkp://KEYSERVER KEYID
gpg --send-keys --keyserver hkp://KEYSERVER KEYID
gpg --keyserver hkp://KEYSERVER --search [email protected]
Where KEYSERVER is the address of the key server like: pgp.mit.edu
gpg --edit-key KEYID
A interactive gpg prompt will start, get all command by entering help
. Options include:
trust
: Change trust levelexpire
: Change expiration datepasswd
: Change passphraseadduid
/deluid
: Add remove user id
uid's are numbered, entering this number in the prompt will select/deselect the uid.
If the private key has been compromised or a UID has changed or simply if you forgot the passphrase the public key has no use anymore. It is recommended to generate a revocation certificate immediately after generating a key and keeping the revocation certificate somewhere safe.
gpg -o revoke.asc -a --gen-revoke KEYID
To revoke the key do:
gpg --import revoke.asc
You can now replace the existing public keys on keyservers with the revoked one to notify people of the change. Or simply replace the old public key a new one. You have to generate a new keypair for this.
gpg --sign-key [email protected]
In order to verify the key manually, you can compare the local fingerprint of the public key with a the fingerprint of the same key provided directly and securely by the recipient itself.
gpg --fingerprint [email protected]
-c = --symmetric (encrypt)
-o = --output (optional)
gpg -c [--cipher-algo AES256] [-o OUTPUT] INPUT
The default symmtric cipher in gpg 2.3 is AES-256 so passing the --cipher-algo
flag is unnecessary unless you want to use something else or be sure.
Alternatively you can also set --cipher-algo AES256
in your gpg.conf
file or in the command line so you don't have to specify it everytime. Or you could edit the cipher preferences on your key with set-pref
inside the edit menu.
Using AES-256 will use the CFB block cipher mode internally.
-e = --encrypt (asymmetric)
-r = --recipient
-u = --local-user (local key used to encrypt)(optional)
-o = --output (optional)
gpg -e -r KEYID [-u KEYID] [-o OUTPUT] INPUT
If you don't supply the -o
output file flag, gpg will create a new file with the same filename + .gpg
appended (.asc
if ascii armored output)
An additional feature of public key cryptography is the ability to encrypt for multiple recipients. Therefore in gpg you can specify multiple recipients by adding multiple -r KEYID
flags.
Encryption uses compression by default. To disable, use the option -z 0
. This will speed up the process if encrypting a large file which is already compressed.
gpg -e -z 0 -r KEYID file.tar.gz
Lists infos about the gpg file. Can be signed or encrypted data.
gpg --list-packets GPGFILE
This works for both symmetrically and asymmetrically encrypted files
-d = --decrypt
-o = --output (optional)
gpg -d -o OUTPUT INPUT
or
gpg INPUT (will decrypt and save to filename without .gpg or .asc ending)
Not having an output file specified will result in gpg printing to stdout.
Normally encrypted data and exports will be binary. If you intend to send the encrypted data over the internet (email etc.) to someone it has to be in ASCII form. Use the -a
flag which stands for --armor
to have an ASCII output.
Simply storing data on a NAS or never having to paste it somewhere doesn't require the --armor
flag.
Using ASCII armor will results in bigger files and longer encryption times:
We do not recommend using the --armour option for encrypting files that will be transferred to/from NAS systems. This option is mainly intended for sending binary data through email, not via transfer commands such as bbftp or ftp. The file size tends to be about 33% bigger than without this option, and encrypting the data takes about 10-15% longer.
Quote by NASA's guide for GPG file encryption
-c create
-x extract
-f filename
-z gzip compression
-j bzip compression
-v verbose
// Create .tar archive
tar -cf archive.tar FOLDER/ [optional more files]
// Extract .tar
tar -xf archive.tar [-C extractFolder]
// Create gzipped archives
tar -czf archive.tar.gz FOLDER/
// Extract gzipped
tar -xzf archive.tar.gz
//List Contents:
tar -tvf archive.tar
-s = --sign
-u = --local-user (local key used to sign)(optional)
// Sign file (binary output)
gpg [-u KEYID] -o OUTPUT -s INPUT
// Sign file (ASCII output)
gpg [-u KEYID] -o OUTPUT --clear-sign INPUT
Both options result in the file being wrapped inside the signature. This means that for non-trivial documents like simple text, the receiver needs to edit the files to extract the original file data without the signature. This can also be achieved by simply decrypting the signed file into a seperate output.
To circumvent this problem you can create a detached signature into a seperate file. This way the receiver can use the signed document as intendet and can verify the validity with the seperate signature file. This is highly recommended when signing binary data (e.g. archives)
-b = --detach-sign
// Binary output
gpg -o OUTPUT.sig -b INPUT
// ASCII output
gpg -a -o OUTPUT.asc -b INPUT
gpg -s -e -r KEYID [-u KEYID] [-a] INPUT
This will first sign the file and then encrypt it. When decrypting the signature is automatically checked (assuming the public key of the sender has been imported).
gpg --verify INPUT
INPUT can be any signed file or detached signature.
gpg --verify FILE.txt.asc FILE.txt
While playing around locally, encrypting and decrypting files you might have noticed that the password for keys gets cached locally for a short time. This of course has the advantage that you don't have to enter the key all the time. The cache gets cleared periodically or when restarting of course.
If you want to clear the cache manually:
gpg-connect-agent reloadagent /bye
Subkeys make key management easier since your primary key pair is very important and holds a lot of power. Therefore you should keep it very safe, but this safety would also come at a cost when you try to encrypt or sign data. This is where subkeys come in.
When you created your keypair, gpg automatically created an encryption subkey. To seperate encryption, signing and if you need to authentication into fully seperate subkeys you have to create a new key for each functionality. The certify functionality shall be kept only on the primary secret key as this enables the signing of new subkeys.
Now you keep only the subkeys on your machine, publish them instead of your primary key and use them instead of the primary key.
You will need access to the secret key only in the following scenarios:
- sign someone else's key or revoke an existing signature,
- add a new UID or mark an existing UID as primary,
- create a new subkey,
- revoke an existing UID or subkey,
- change the preferences (e.g., with setpref) on a UID,
- change the expiration date on your primary key or any of its subkey, or
- revoke or generate a revocation certificate for the complete key.
gpg --edit-key KEYID addkey
// Go through key creation guidde
gpg> save
// Export all subkeys
gpg -o secret-subkeys --export-secret-subkeys
// Alternatively you can specify a specific subkey with KEYID! (! is important)
//Delete secret primary key
gpg --delete-secret-key KEYID
//Import subkey
gpg --import secret-subkeys
gpg -K
should now show a sec#
instead of a sec
for your private key, indicating a missing secret key.
Remember to delete the file containing the subkeys afterwards.
Additionally you should also change the passphrase protecting your subkeys with:
gpg --edit-key KEYID passwd
This way if your subkey set gets compromised your primary key backup is still protected with the original passphrase.
Private keys should be kept secret and not be exported or shared.
Depending on your threat assessement and security needed you have several options options:
From Jens Erat's Stackexchange Answer
Your computer always could be hacked or infected by some malware downloading your keys and installing a key logger to fetch your password (and this is not a matter of which operating system you use, all of them include severe security holes nobody knows about at this time).
Keeping your primary (private) key offline is a good choice preventing these problems. It includes some hassles, but reduces risks as stated above.
Highest security would of course mean to use a separate, offline computer (hardware, no virtual machine!) to do all the key management using your primary key and only transferring OpenPGP data (foreign keys and signatures you issued) using some thumb drive.
Export backup from private secret key (including trustdb etc.)
gpg -o private_backup.gpg -a --export-secret-keys --export-options export-backup KEYID
The exported private key is encrypted by default with the passphrase you chose for it when you created the keypair.
gpg --import-options restore --import private_backup.gpg
As an alternative to the following procedure you could also use Paperkey.
I just wanted to have qr codes and the extra unnecessary data printed, doesn't bother me much.
Use linux or wsl for the following steps.
Install packages:
sudo apt-get install qrencode imagemagick
In order to safely store the created backup file of the secret private key, we can split the generated (ascii armored!) file into 1.5kB files
split -b 1500 -d backup.key part
Here we split backup.key into multiple files with a max of 1500 bytes, so that we can encode qrcodes with a error correction level of Q. They are numbered like: part00 part01...
Next run the following bash script to encode every part as a qr image
for file in part??
do
qrencode -l Q -r $file -o $file.png
rm $file
done
Now we'll create one image that contains all parts with their filelabel below. Ready for printing
montage -label '%f' *.png -geometry '1x1<' -tile 2x3 backup.png
Now your can print all the qrcodes on paper in the correct order! Don't print the passphrase for the secret key! instead write it on the paper by hand
First scan in, take pictures or whatever. Just get seperate correctly ordered images of the qr codes on your machine.
Label them part00.png...part??.png
Install zbar-tools:
sudo apt-get install zbar-tools
Run this script to read the qr codes with zbarimg and write them concatenated into a new file called restored_key.gpg
for file in part??.png
do
zbarimg --raw $file > part_${file//[^0-9]/}
done
cat part_* > restored_key.gpg
rm part_*
Alternatively you can write all them to file directly with zbarcam
:
zbarcam --raw > cam.input
You can scan multiple qrcodes in the correct order and the input will be together in cam.input
Now you can import the restored secret key like exaplained in Restore
Tell git about the key used to sign commits (copy fingerprint via gpg -K
):
git config --global user.signingkey FINGERPRINT
--global
can be ommited if the change should only affect the local git repo.
In order to push the commit, your public has to be registered to your account of your git host of choice.
Usually under Settings -> GPG Keys. Make sure that the associated email in the signing key is also registered in your account!
Sign all commits per default:
git config --global commit.gpgsign true
Alternatively you can manually sign a commit with the -S
flag when commiting:
git commit -S -m "MESSAGE"
- bfrg's gpg guide
- samuelexferri's gpg guide
- NASA's gpg encryption guide
- Debian's Subkey Guide
- Andy Gock's GPG Cheatsheet
- Secret Key Backup (Rubberstamp's Answer on Stackexchange)
- Paul Fawkesley - Protect Private Key
- Paul Fawkesley - Prepare Offline Machine
- Jens Erat on a good gnupg setup
- Jens Erat on how many gpg keys to make
- https://gist.github.com/GrantTrebbin/0c6aadc7ecebe3107d08
- Githubs guide to sign commits