GnuPG
13 Feb 2016 • Leave Comments- First run
- Examine Key
- Create key
- Export key
- Importing keys
- Sending keys to servers
- Key Management
- Sign / encrypt
- expire
- gpg-agent
- Refs
In the previous post SSH, I talked about secure connection (i.e. remote login) on the Internet. Now you will see how GnuPG (an implementation of OpenPGP) is used to encrypt/decrypt messages (i.e. email, documents). To use gpg, read official guide.
First run
If you never run gpg, then try --list-keys
or --fingerprint
(include fingerprint of key).
jim@tux ~ $ gpg --list-keys --list-options show-usage
jim@tux ~ $ gpg --list-secret-keys --list-options show-usage
gpg: directory `/home/jim/.gnupg' created
gpg: new configuration file `/home/jim/.gnupg/gpg.conf' created
gpg: WARNING: options in `/home/jim/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring `/home/jim/.gnupg/pubring.gpg' created
gpg: /home/jim/.gnupg/trustdb.gpg: trustdb created
This will try to list available GPG keys on system. The first time it's run, gpg will create some directories and files essential to the correct operation and implementation of GnuPG.
Examine Key
user@tux ~ $ gpg -vv [--with-fingerprint] [--with-colons] < /path/to/key
user@tux ~ $ gpg -vv --list-packets /path/to/key
Create key
The very first step of using GnuPG is creating a key pair.
Here is what I will do:
- Choose default key method: (1) RSA and RSA (default).
- Keysize - the longest - 4096 bits.
- Key valid for one year
- Provide name and email address to identify the key.
- Provide a passphrase to protect the private key. The public key don't need protection.
- Get the key ID: the last 64 bits fingerprint.
gpg --list-keys
again to check results.
jim@tux ~ $ gpg --full-generate-key (ask for key parameters)
# or
jim@tux ~ $ gpg --gen-key (use default key parameter)
jim@tux ~ $ gpg --keyid-format 0xlong --list-keys
jim@tux ~ $ gpg --with-colons --list-keys
--full-gen-key
is interactive asking for key parameters like exipration date etc.- GnuPG will take several minutes to generate the key pair. You'd better moving the mouse, browsing the web, or having streaming audio in the background will help speed up the process.
- New version of GnuPG creates revocation certificate automaticall unpon key creation in ~/.gnupg/openpgp-revocs.d.
- Existing key user ID (comment included) can not be modified after creation. But you can add or delete user ID instead. We can optionally set one of the user IDs as the primary ID (top in the ID list).
- You can change passphrase anytime afterwards with passwd sub-command.
Revocation
Newer GnuPG version will issue revocation certificate upon key creation. However, it's always a good idea to create a new revocation certificate as long as you still access to the private key, providing a strong revocation description.
Create a revocation certificate. Doing this allow you to revoke the key in case something nasty happens (lose the key; superseded; compromised etc.).
jim@tux ~ $ gpg --output 12345678-revocation.asc --gen-revoke 12345678
If you don't give --output 12345678-revocation.asc
, the revocation certificate will be printed on screen.
Please move it to a medium which you can hide away; if Mallory gets access to this certificate he can use it to make your key unusable. It is smart to print this certificate and store it away, just in case your media become unreadable. But have some caution: The print system of your machine might store the data and make it available to others!
Later on, suppose you want to revoke the key,
jim@tux ~ $ gpg --import 12345678-revocation.asc
jim@tux ~ $ gpg --keyserver pgp.mit.edu --send-keys 12345678
- Issuing this command imports the revocation into your keyring, revoking your key locally.
-
This sends the revoked key to key server to let your friends know.
If it succeeds, you'll get the message:
gpg: success sending to `pgp.mit.edu' (status=200)
If you check your key's verbose index page on pgp.mit.edu, you'll see KEY REVOKED on the first line of the details.
Export key
Now it's time to distribute the public key.
# export public key
jim@tux ~ $ gpg --armor --export --output public.pgp email@gmx.com
# export private key
jim@tux ~ $ gpg --armor --export-secret-keys --export-options backup --output key-backup.pgp email.gmx.com
- By default, the public key will be exported to STDOUT.
--output name.pub
exports to file. It's recommended to distribute this file with the fingerprint attached. --armor
tells gpg to generate ASCII text output instead of default binary.-
We export private key (public key included) for backup or moving keys around.
A reasonable way to achieve a long term backup of OpenPGP (GnuPG, PGP, etc) keys is to print them out on paper. Paper and ink have amazingly long retention qualities - far longer than the magnetic or optical means that are generally used to back up computer data.
Importing keys
Once you get a copy of the exported public key of your friend, add it to your public keyring.
Pay attention to verify fingerprint to avoid receiving a forged public key.
jim@tux ~ $ gpg --import friend.pub
jim@tux ~ $ gpg --edit-key friend-key, (enter sub-command)
list - list the key information.
fpr - print fingerprint of imported key (same as `gpg --fingerprint`).
sign - sign your friend's public key by your private key.
check - check the signature.
After importing the public key, now you can encrypt message to friend or to certify key's owner's signature.
We can also import a secret key:
jim@tux ~ $ gpg --import key-backup.pgp
Sending keys to servers
--export
and --import
distribute keys between friends directly. There are many public key servers where you can --recv-keys
, --send-keys
, and --search-keys
. Since version 2.1 of GnuPG, dirmngr takes care of accessing the OpenPGP keyservers.
All these public key servers will exchange keys periodically. Most of the time, you only need to focus on one of them. You can specify keyserver in ~/.gnupg/dirmngr.conf or on command line by --keyserver
.
jim@tux ~ $ gpg --recv-key key-id
jim@tux ~ $ gpg --send-key key-id
We can
Key Management
- Key
- Your own key pair - public/private key.
- Friends'/organizations' public keys. Imported from key file or received from key servers.
- Utility
- Public key is distributed over the Internet, i.e. sent to key servers or handed over to friends manually.
- People encrypt messages before sending to you.
- People certify your signature.
- Keep private key confidentially.
- Use it to decrypt message received.
-
Sign documents before publication.
A special case is to sign public keys from friends/key servers to validate them.
- Public key is distributed over the Internet, i.e. sent to key servers or handed over to friends manually.
- Validity
- Before using a key, make sure the key is owned by whom you would communicate with. Our own key pair is valid by default. But how about friends' public keys? How to validate them?
- Upon receiving a public key, fingerprint is included which should be compared with what the owner claims (i.e. handed over to you). If it's a organization's public certificate, usually fingerprint is pasted on their official page along with public key certificate download link.
- After confirmation the public key fingerprint, you sign the public key with your private key. To manually sign a key directly is to validate/certify a key.
-
If a public key is not sign directly before usage, a gpg warning comes out like this:
gpg: WARNING: This key is not certified with a trusted signature!
gpg detects that the key you are using has not been validated. You can check whether a key is valid by the output of
gpg --list-keys
. If there is an[unknown]
in front of the user's ID, the key is NOT valid in that you cannot determine if it's owned by the one claiming to own it.
-
Web of trust
validity and trust are different thing. If you trust somebody, you acutally accept the keys he signed as valid. But what if you have got 100 public keys at hand? Sign manually one by one? OMG! GnuPG addresses this problem with a mechanism popularly known as the web of trust. In the web of trust model, responsibility for validating public keys can be delegated to people you trust.
For example, you get public keys: k1, k2, k3, … You manually / directly signed k1 with your private key and validate it. Meanwhile, k1 signed k2 and k3 directly as well. From the viewpoint of k1, k2 and k3 are valid keys. If you trust k1 fully (level 4, discussed below), then you trust k1's signing action on k2 and k3. You view k2 and k3 as valid as well though you do not sign them directly.
What the hell does trust mean? trust means the confidence on someone's capacities at signing/validating/certifying keys.
- Trust is subjective judgement on others' capacity. You trust on somebody according to whether he verifies public fingerprint carefully, whether he is a master of GnuPG and PKI. The purpose of trust is to relieve you from signing/validating keys one by one manually.
- Validity is the status of a key from viewpoint of you (your gpg on system).
- So trust serves validity. The trust relationship forms a web. gpg determines a key's validity by this web of trust.
- Trust has levels. You can trust Bob fully while Alice partially.
Using trust to validate keys
How trust works? Recall gpg sub-command sign validates public keys. There is trust sub-command to assign trust level to a key's owner.
- Trust has levels: unknown, none, marginal, ful, ultimate. Level 0 (unkown) means you don't know the key's owner's capacity at validating keys, while 5 means trust ultimately. Never trust other's key ultimately! ultimate is designated for your own key only. Details on trust levels, refer to reference 1.
- Formerly, a key was considered valid only if you signed it personally. A more flexible algorithm can now be used: a key K is considered valid if it meets two conditions:
- it is signed by enough valid keys, meaning:
- you have signed it personally,
- it has been signed by one fully trusted key, or
- it has been signed by three marginally trusted keys; and
- the path of signed keys leading from K back to your own key is five steps or shorter.
- prerequisite: the parent key should be fully valid.
Apart from the web of trust, there is also a tree of signing on which only the first layer nodes of tree is signed by you directly! We cannot determine the validity of a node (key) on lower layers without the help of web of trust.
- it is signed by enough valid keys, meaning:
Validity Level
The prequisite in the algorithm: the parent key (signing key) shuld be fully valid. Actually, validity also has levels - similar to trust.
You can sign a key directly and check the result. In front of the user ID, you will find [full], means this key is fully valid. For example, you fully trust a marginal valid key k1 on the signing tree and k1 signs another key k2. k2 should NOT be regarded fully valid.
Sign / encrypt
sign
jim@tux ~ $ gpg --output message.sig --sign message.txt
or
jim@tux ~ $ gpg --clearsign message.txt
or
jim@tux ~ $ gpg --detach-sig message.txt
- It uses your private key to sign.
-
The first output is binary format with original file compressed.
This is NOT a preferred way to sign documents.
-
The 2nd output will append signature to the end of original file without compression. This what we usually used to sign email.
But receiver has to recover orginal document from the signature file.
-
The 3rd will create a separate binary signature file without touching the original document. You can send the original file along with the signature file.
This is useful when the original document is large files.
verify
Unpon get a signed message, we can just check the signature by –verify or verify the signature and extract the original message concurrently by –decrypt. To verify a detach signature, both the oirginal document and signature file must be present.
jim@tux ~ $ gpg --verify message.sig
jim@tux ~ $ gpg --verify message.sig message
jim@tux ~ $ gpg --output message --decrypt messag.sig
encrypt
$ gpg --encrypt --recipient recipient@example.com message.txt
- Should specify who is the receiver by
--recipient
.
sign and encrypt
$ gpg --sign --encrypt --recipient recipient@example.com message.txt
- Output is binary format.
- Cannot use
--clearsign
with--encrypt
simutaneously. - There is no need for
--detach-sig
in this case.
When receving a secret.gpg file, you
$ gpg --output original.txt --decrypt secret.gpg
expire
Though keys can be set to never expire, you are recommended to set an expiration date since you can always extend the expiration date even after it has expired. This "expiration" is actually more of a safety valve or "dead-man switch" that will automatically trigger at some point. If you have access to the secret key material, you can untrigger it. The point is to setup something to disable your key in case you lose access to it (and have no revocation certificate).
gpg --edit-key uid
gpg> expire
...
gpg> key 1
gpg> expire
...
gpg> save
- The first expire without selected key sets new exipiration date for primary key.
- The second expire with selected sub-key sets new expiration date for key 1.
Ohters can notice the expiration of your public key from key servers. For private keys, only you know it unless you give them to some bad guy.
gpg-agent
Like the SSH Agent, GPG agent cache the private key passphrase. A user don't need to input passphrase each time using the key.
Sometimes working with certain applications requires the use of a GPG key very frequently, which means that a passphrase must be frequently entered. In the past many applications supported a passphrase caching mechanism. This would make life easier for users because passphrases were automatically entered. However, this disallowed sharing this cache across programs (how secure would that be?) and forced applications to reinvent the wheel over and over again.
In order for apg-agent to works in Shell, we must correctly set GPG_TTY
as below.
# ~/.bashrc
export GPG_TTY=$(tty)
pinentry
GnuPG includes gpg-agent. Pinentry (app-crypt/pinentry) is a helper application that gpg-agent uses to request the passphrase in a graphical window. It comes in three flavors: it can popup a window using the GTK+, QT, or curses libraries (depending on the USE flags set in /etc/portage/make.conf).
If app-crypt/pinentry was installed with more than one popup window type, it is possible to choose between the windows with the eselect pinentry command:
laptop ~ # eselect pinentry list
Available pinentry binary implementations:
[1] pinentry-gtk-2 *
[2] pinentry-curses
laptop ~ # eselect pinentry set 1
configuring gpg-agent
# ~/.gnupg/gpg-agent.conf
# called when prompt for passphrase the first time
pinentry-program /usr/bin/pinentry-gtk-2
# timeout 30 minutes
default-cache-ttl 1800
Now configure GnuPG to use an agent when appropriate. Edit ~/.gnupg/gpg.conf and add the following line:
# ~/.gnupg/gpg.conf
#
# DEPRECATED!
use-agent
Since GPG2, use-agent
is deprecated as GPG2 always require agent.
launch agent
To launch agent manually:
$ eval $(gpg-agent --sh --daemon --enable-ssh-support --write-env-file ${HOME}/.cache/gpg-agent-info)
If the arguments are already provided in configuration file, they can be omitted. Attention, command line arguments will override those in configuration file.
The command should be wrapped by eval, otherwise environment variables would not be exported.
Automation
Refer to lastest ~/.bashrc for updates
To launch GPG agent automatically on boot, add the command to startup scripts specially for servers (NO X/GUI). By default, Xfce4 starts the agent automatically on startup. Check by ps -ef | grep -i gpg-agent
.
But if you launch an agent manually on consosle and then switch to start Xfce4, it will launch another agent for you. So check to launch agent in startup scripts like .bashrc and .bash_profile.
-
(opt) Disable Xfce4 automation
$ xfconf-query -c xfce4-session -p /startup/gpg-agent/enabled -n -t bool -s false $ xfconf-query -c xfce4-session -p /startup/ssh-agent/enabled -n -t bool -s false
-
Edit .bashrc:
# Associate with existing gpg-agent if [ -f "${HOME}/.cache/gpg-agent-info" ]; then . "${HOME}/.cache/gpg-agent-info" export GPG_AGENT_INFO export SSH_AUTH_SOCK export SSH_AGENT_PID fi # Start the gpg-agent if not already running if ! pgrep -x -u "${USER}" gpg-agent >/dev/null 2>&1; then eval `/usr/bin/gpg-agent --sh --daemon --enable-ssh-support --write-env-file "${HOME}/.cache/gpg-agent-info"` fi # Refresh gpg-agent tty in case user switches into an X session gpg-connect-agent updatestartuptty /bye >/dev/null
With this script, the previous ssh-find-agent is deprecated.
[optional] SSH mode
The OpenSSH Agent protocol is always enabled (check ${XDG_RUNTIME_DIR}/gnupg/S.gpg-agent.ssh
), but gpg-agent will only set the SSH_AUTH_SOCK
variable if flag --enable-ssh-support
is given.
This mode does not require SSH_AGENT_PID
.
GPG_AGENT_INFO
deprecated since GnuPG v2.1
Like SSH agent, GPG agent exports an environmental variable GPG_AGENT_INFO
and file ~/.cache/gpg-agent-info.