PGP - Pretty Good Privacy

  • created by Phil Zimmermann in 1991
  • owned by Symantec
  • OpenPGP is a standard defined in RFC 4880
  • GPG/GnuPG (GNU Privacy Guard) implements OpenPGP

basic concepts

  • encryption - convert plaintext to ciphertext using a key
    • symmetric - use same key for encryption and decryption
    • asymmetric - use 2 keys - public and private
  • pgp encryption - nobody should read this except the recipient
    1. sender generates a random encryption key (session key)
    2. sender encrypts message contents with session key using a symmetric cipher
    3. sender encrypts session key using recipient’s public PGP key
    4. sender sends both encrypted message and encrypted session key to recipient
    5. recipient decrypts session key using their private PGP key
    6. recipient uses session key to decrypt message
  • pgp signature - verify integrity - use keys the opposite way as above:
    1. signer generates checksum of message
    2. signer encrypts the checksum using own private PGP key
    3. signer sends encrypted checksum along with message
    4. verifier generates their own checksum of message
    5. verifier decrypts provided checksum using signer’s public PGP key
    6. if checksums match, integrity is verified
  • combined usage - sign encrypted message with sender’s own PGP key
  • key identities
    • each PGP key must have one or more identities (name+email like Alice <[email protected]>) associated with it
    • if multiple identities are used, one of them would be marked as primary. e.g.
    • you can create new identities, revoke old ones and change which identity is primary
  • key validity
    • full – pretty sure this key belongs to Alice
    • marginal – somewhat sure this key belongs to Alice
    • unknown – no assurance that this key belongs to Alice
  • Web of Trust (WoT) vs Trust on First Usage (ToFU)
    • WOT - sign each others keys to ascertain that he is who he claims to be
    • TOFU - SSH-like, i.e. first time you connect to a system, record its key fingerprint (in .ssh/known_hosts). Check this from next time and fail if it doesn’t match

generate and protect master PGP key

  • a PGP key can have 4 capabilities - these are just functional limitations assigned at creation time:
    • [S] - use for signing
    • [E] - use for encryption
    • [A] - use for authentication
    • [C] - use for certifying other keys - master key
      • add or revoke other keys (subkeys) with S/E/A capabilities
      • add, change or revoke identities (uids) associated with the key
      • add or change the expiration date on itself or any subkey
      • sign other people’s keys for WoT purposes
  • a single key can have multiple capabilities
  • no technical difference between master key and subkeys

generate master key

$ gpg --quick-generate-key 'Alice Engineer <[email protected]>' rsa4096 cert

output will be something like:

pub   rsa4096 2017-12-06 [C] [expires: 2019-12-06]
uid                      Alice Engineer <[email protected]>

the 2nd line above is the full fingerprint of your new key.

  • key ids can be represented in 3 forms:
    • fingerprint - full 40-character key identifier (111122223333444455556666AAAABBBBCCCCDDDD)
    • long - last 16 characters of fingerprint (AAAABBBBCCCCDDDD)
    • short - last 8 characters of fingerprint - avoid using this (CCCCDDDD)
  • backup your master key on paper using paperkey:
    $ gpg --export-secret-key <FINGERPRINT> | paperkey -o /tmp/key-backup.txt

    you can convert this text file to a PDF using enscript --no-header -p - /tmp/key-backup.txt | ps2pdf - /tmp/key-backup.pdf and then print it out on paper. Keep it safe!

  • add more identities using:
    $ gpg --quick-add-uid <FINGERPRINT> 'Alice Engineer <[email protected]>'
    $ gpg --quick-set-primary-uid <FINGERPRINT> 'Alice Engineer <[email protected]>'  # reset your primary uid

generate PGP subkeys

  • generate 1 subkey each for encryption, signing and authentication
    $ gpg --quick-add-key <FINGERPRINT> rsa2048 encr
    $ gpg --quick-add-key <FINGERPRINT> rsa2048 sign
    $ gpg --quick-add-key <FINGERPRINT> rsa2048 auth

move master key offline

  • create an encrypted USB drive (you can use the same passphrase as your master key passphrase) and backup your ~/.gnupg to it
  • I used GNOME Disks (LUKS) for this, but you can also do it on the cmdline.

common gnupg operations

  • mounting master key offline storage
    $ export GNUPGHOME=/media/disk/name/gnupg-backup
    $ gpg --list-secret-keys

    You want to make sure that you see sec and not sec# in the output (the # means the key is not available and you’re still using your regular home directory location).

    • import any changes made using offline storage keys:
      $ gpg --export | gpg --homedir ~/.gnupg --import
      $ unset GNUPGHOME
  • extend key expiration date
    $ gpg --quick-set-expire <FINGERPRINT> 1y          # extend by 1 year
    $ gpg --quick-set-expire <FINGERPRINT> 2020-07-01  # extend till
  • export public key to stdout - share this with everyone and bug them to send you encrypted emails or pictures or what have you.
    $ gpg --export --armor <FINGERPRINT>
  • upload your public key to keyservers - just be aware that your key can’t be deleted once pushed
    $ gpg --send-key <FINGERPRINT>
  • import a public key
    • from file (get mine here):
      $ gpg --import <PUBLICKEYFILE>
    • from keyserver:
      $ gpg --search-keys <EMAIL>
      $ gpg --recv-keys <FINGERPRINT>

      for example, Linus Torvalds’ key:

      $ gpg --search-keys [email protected]
      gpg: data source:
      (1)	Linus Torvalds <[email protected]>
      	  2048 bit RSA key 6211AA3B00411886, created: 2014-07-21 (revoked)
      (2)	Linus Torvalds <[email protected]>
      	Linus Torvalds <[email protected]>
      	  2048 bit RSA key 79BE3E4300411886, created: 2011-09-20
  • refresh other people’s keys in your keyring:
    $ gpg --refresh
  • encrypt file with receiver’s public key:
    $ gpg --recipient <EMAIL|FINGERPRINT> --encrypt <FILENAME>
  • decrypt file with your private key:
    $ gpg --output <OUTPUTFILE> --decrypt <ENCRYPTEDFILENAME>
  • sign a file with your private key:
    $ gpg --output <OUTPUTFILE> --sign <FILENAME>  # binary
    $ gpg --output <OUTPUTFILE> --clearsign <FILENAME>  # plaintext
    $ gpg --output <OUTPUTFILE> --detach-sig <FILENAME>  # detached signature
  • verify a signature:
    $ gpg --verify doc.sig
    $ gpg --verify archlinux.iso.sig  # verify detached signature for archlinux.iso
  • encrypt and sign (in ASCII armor)
    $ gpg --encrypt --sign --armor -r <RECIPIENT> <FILENAME>  # will create <FILENAME>.asc
  • decrypt encrypted and signed file
    $ gpg <FILENAME>.asc
  • sign someone’s key (WOT):
    $ gpg --sign-key <RECP_EMAIL>

    send them this signed key:

    $ gpg --output ~/signed.key --export --armor <RECP_EMAIL>

    they can now import this into their gpg database:

    $ gpg --import ~/signed.key
  • export your auth key in OpenSSH public key format
    $ gpg --export-ssh-key <FINGERPRINT>


  • use OpenKeyChain on android
  • transfer your key as per the OpenKeyChain FAQ
    $ gpg --armor --gen-random 1 20   # generate random password to use for below
    $ gpg --armor --export-secret-keys <FINGERPRINT> | gpg --armor --symmetric --output mykey.sec.asc
  • copy above to your phone using USB and chose Import Key from File. Enter the random password using which it was encrypted.

pgp with ssh

  • make sure you have an auth subkey
  • add following to your ~/.bashrc
    export GPG_TTY=$(tty) # as per gpg-agent(1)
    unset SSH_AGENT_PID
    [[ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]] && export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
  • add following to ~/.gnupg/gpg-agent.conf
  • if using GNOME, stop the keyring daemon from starting up ssh-agent
    $ cp /etc/xdg/autostart/gnome-keyring-ssh.desktop ~/.config/autostart/ && echo 'Hidden=true' >> ~/.config/autostart/gnome-keyring-ssh.desktop
  • add your auth key’s keygrip to ~/.gnupg/sshcontrol
    $ gpg --list-keys --with-keygrip <FINGERPRINT>|grep -A1 '\[A\]'|tail -n1|awk -F= '{print $2}'|tr -d ' '>>~/.gnupg/sshcontrol
  • use ssh-copy-id as usual to copy this to any remote hosts

pgp with git

  • use git commit -S to sign your commits
  • copy your public key to GitHub/GitLab to get a little Verified icon next to your signed commits

password management with pass

  • store your GPG encrypted passwords in a git repository!
  • initialize with
    $ pass init <gpd-id or email>
  • also initialize git repo:
    $ pass git init
    $ pass git remote add origin <REMOTEURL>
    $ pass git config --bool --add pass.signcommits true  # sign commits
    $ pass git push -u --all
  • add multiline passwords (pass insert -m in the following form so passff/browserpass can work:
    login: <the_login>
    url: <the_url>
    <other_inputfield_name> : <inputfield_value>
  • push changes to git server:
    $ pass git push
  • generate n length password for
    $ pass generate n  # add -n before so no symbols are added
  • On Android, install Password Store via F-Droid. It depends on OpenKeyChain, so make sure to install that as well
    • follow this to transfer your keys to your phone