simfish:

GNU Privacy Guard(GPG)

This workflow installs, configures and sets up shell commands for working with GNU Privacy Guard(gpg), which is open source and free implementation of the Open PGP standard-RFC4880.

cover image

Introduction

The focus of this workflow is setting up the GNU/Guix gnupg package. The additional package pinentry implements UI for securely prompting and reading pass-phrases.

Installation

The Guix manifest for the default packages is listed here. Other dependencies, such as Emacs integration are installed on demand.

(specifications->manifest '( "gnupg" "pinentry" "rng-tools" ))

To load this workflow run,

litdoc gpg

Shell Integration

One useful application of gpg is to save sensitive information that needs to be passed on to applications, as encrypted shell environment files. And to decrypt and source the files on the fly at runtime. The following is a shell script for accomplishing that in a Bash shell,

bin/gpg_decrypt.sh

#! /usr/bin/env bash
#////////////////////////////////////////////////////
# main
#////////////////////////////////////////////////////
[ $# -eq 1 ] || {
    echo "ERROR: missing FILE argument"
    echo "usage: litdoc gpg -- FILE"
    exit 1
}

file="${1}"
[ -r "${file}" ] || {
    echo "[ERROR]: unable to read file: ${file}"
    exit 1
}


source <$(gpg --decrypt "${file}")

The entry point for the script is the main script below,

#! /usr/bin/env bash

source "${LITDOC_DIR}/libs/sh/log.sh"

[ $# -ge 1 ] || {
    echo "usage:"
    echo "litdoc gpg configure"
    echo "litdoc gpg decrypt FILE"
}

case ${1} in
    configure)
        shift
        exec "${LITDOC_SITEDIR}/bin/gpg_configure.sh" $@
        ;;
    decrypt)
       shift
        exec "${LITDOC_SITEDIR}/bin/gpg_decrypt.sh" $@
        ;;
    ,*)
        log_fail "[gpg]: bad argument: <${@}>"
        ;;
esac

To run it use,

litdoc gpg encrypt FILE # where FILE is file to be encrypted
litdoc gpg decypt  FILE # where FILE is encrypted

Emacs Integration

Configuration for gpg can be found under ~/.gnupg/gpg,

~/.gnupg/gpg.conf
~/.gnupg/gpg-agent.conf

gpg.conf file defaults are often fine, at least for my personal application. However, the gpg-agent.conf file contains the pin input prompt UI. In particular this config, epg-pinentry-mode.

For a smooth Emacs integration, set the option to loopback, which enables Emacs to prompt for pass-phrase using the mini-buffer instead of an external program.

# tell pinentry to allow features to divert the passphrase
# entry to a running Emacs instance
#allow-emacs-pinentry
pinentry-program /usr/bin/pinentry-gnome3

# allow clients to use the loopback pinentry features
allow-loopback-pinentry

For the changes to take effect run,

litdoc site gpg configure

This will execute a shell script shown below,

#!/usr/bin/env bash
source "${LITDOC_DIR}/libs/sh/lit-log.sh"

[ $# -ge 1 ] || {
    log_error "bad argument: $@"
    echo "usage: litdoc gpg configure"
    exit 1
}

gpg --version
gpgconf --reload gpg-agent
gpgconf --kill gpg-agent

Once a key is generated loading the built-in package epa is sufficient to encrypt and decrypt files with gpg extension. This also applies to encrypted elisp files with file extension *.el.gpg or header info:epa-file-encrypt-to header

# -*- epa-file-encrypt-to: ("user@example.com") -*-

Emacs command for creating and reading encrypted files is available too,

(defun gpg::new-encrypted-file(  )
  "Opens a new encrypted file"
  (interactive)
  (let ((buffer (generate-new-buffer "untitled")))
    (set-buffer-major-mode buffer)
    (with-current-buffer buffer
      (goto-char (point-max))
      (insert "# -*- epa-file-encrypt-to: (\"aronggile@gmail.com\") -*-"))
    (display-buffer buffer '(display-buffer-pop-up-frame . nil))))

When working within Emacs, the EasyPG Assistant(epg) package provides an elisp interface to gpg. Among other features, the interface implements automatic encryption and decryption of files with *.gpg extension.

(use-package epg
  :config
  (setq epa-file-encrypt-to '("aronggile@gmail.com"))
  (setq epg-pinentry-mode 'loopback))

Application Notes

Generating GPG Key: run gpg with the full-gen-key option and select a cryptographic algorithm and curve type. The default is, elliptic-curve cryptography(option 9) and curve 25519(option 1). gpg will also prompt for expiration date for the key, where the default is two years.

  gpg --expert --full-gen-key

Backing up GPG Key: once a key is generated it should be backed up prior to use,

gpg --armor --export-secret-keys user@example.com > user.pk.sec
  • user@example.com is either the user's email address as specified during key generation. Alternatively, it can be the users full name.
  • user.pk.sec is file name the private key will be written on.

It is also a good idea to keep key revocation certificate,

gpg --output revoke-cert.asc --gen-revoke user.revoke.sec

Importing GPG Key from a Backup: to import a key that has was priorly saved, for example to user.pk.sec, run:

gpg --import   user.pk.sec
gpg --edit-key user@example.com

This will start an interactive session, where gpg asks for trust, trust-level, and confirmation to have a successful import.

gpg
> trust  # invoke trust subcommand
> 5      # response to trust level: [ultimate]
> y      # confirmation: [yes]

View and Edit GPG Key: to edit or change an existing key first list the available public keys using,

#
gpg --list-keys

Optionally, use --with-fingerprints option to view the cryptographically hashed version of the public key, which is useful when configuring git commit sign-off for example.

gpg-list-keys --with-fingerprints

Enter key editing mode. When prompted for user-id provide the email associated with the key

gpg --edit-key user@email

An interactive session will start. Type in help to list available commands. To edit expiration date for example, type expires and then follow the prompt.

Deleting a Key: to delete unused key from a local machine use,

gpg --delete-secret-and-public-keys user@example.com

References