Using autofs for GPG keys on a USB stick

The problem

GPG potentially provides a great deal of security, both for
encryption and signing. However, like all crypto programs the security
provided is only as secure as the keys used. Therefore, keeping
private keys safe is important.

Like a lot of Free Software developers, I do much of my development
and email work on my laptop. Quite a bit of this work need GPG
(e.g. for signing packages before uploading them into the Debian
archive), so I need to have access to my key(s) on my laptop. Laptops
present a significant security risk here: rather than living in a
reasonably secure location at home or in the office, they travel
around and get used in all sorts of locations. This means they're much
more likely to be lost or stolen, along with whatever data is on
them. Losing your GPG private key is bad!

To mitigate against this, many people choose not to store their
private keys directly on their laptops; the most common way to do this
is using a USB stick: small, cheap removable storage that should be
easy to keep secure (it will fit in a pocket!). So long as an attacker
does not get the USB stick, the key is secure.

However, even that is not ideal. USB sticks are still quite easy to
lose. An even better solution would be to make sure that an attacker
needs both the laptop and the USB stick to be able to
gain access to the GPG private key. There are quite a few ways to do
this (see other options below). Here is my
solution.

My solution

I use a combination of the following software to store my GPG
key on a USB stick so that I can safely use GPG on my laptop:

I'm using the versions of both as they're found in Debian Etch
(4.0r2) - I run "stable" as the base operating system on my laptop. I
would expect all of the following to work with newer versions, but I
can't strictly guarantee that.

I use autofs already on my laptop for automatically mounting
various network and other filesystems like removable media. There are
other similar options available if you use Gnome or KDE, but I don't
by preference. As I've already chosen to use autofs, it's an easy
matter to add extra uses for it.

USB stick setup

When I started using a USB stick for my private key, I just had a
32MB stick (the cheapest I could find). At that point, there was not
much space free on the stick. As USB sticks get larger and larger in
capacity, that's no longer the case. It's a shame to waste the space
on one by just using it for private keys, so now I
partition my current 1GB stick and split up the space. I have one
partition simply formatted with FAT32, and a (much smaller) second
encrypted partition where I store my private key data. I've found this
quite handy - I have space that I can use for carrying around data I
need to share, without having to expose my key data.

There are a couple of non-obvious things here. By setting up a
Windows-friendly partition ID on the first partition,
this stops Windows from helpfully suggesting "this USB stick doesn't
appear to contain anything. Should I format it?" Then using a
non-Windows partition ID on the other partition stops Windows from
messing with it. Linux won't care what the partition ID is later.

The first partition on the USB stick is uninteresting at this
point; it's just a bog-standard, boring FAT32 for data sharing with
anything that can read/write FAT32.

Setting up an encrypted filesystem

The next step is to create an encrypted filesystem within that
second partition. I'm quite specific about how I do this; maybe I'm
being overly (or even underly- !) paranoid, but my goal (as stated
above) is to make the private data on the USB stick useless without
the laptop. To do that, I create an AES-encrypted filesystem in the
second partition on the stick. There are (again!) some non-obvious
steps to this:

"Scrub" the partition first - fill it with random data so that the
encrypted data added later will not be discernible.

# dd if=/dev/urandom of=/dev/sdb2

I deliberately create a random key for that
encrypted filesystem and store that key on the laptop. I don't
even know the key - it's a lump of data from /dev/random
that I store in the file /etc/loop.key, mode 0600. I'm
using a simple, single-key encryption scheme for the key here for
the sake of simplicity in my documentation. See the loop-aes
docs for a good run-through on how to set up much better
encryption schemes using GPG and multiple random keys.

# dd if=/dev/random > /etc/loop.key bs=1 count=60

A problem with many (all?) filesystems is that they have known,
recognisable data stored at various points. This is (of course)
needed - it's how filesystem code recognises its own on-disk data
structures. But for our uses, it's less good - known plaintext is
a bad thing to have in your encrypted data, as it
makes the encryption easier to break. Therefore, another design
choice I make here is to start the filesystem at a random offset
inside the partition. The known plain text is still going to be in
the filesystem headers, but the random offset adds orders of
magnitude to the cost of finding it. In all of the examples here,
I've chosen the arbitrary offset of
65326520. Make sure you change this if you're
trying to replicate this later. And no, that's not the offset I
use on my system... :-)

After you install them, loop-aes comes with a modified loopback
block device driver and loop-aes-utils also adds more featureful
versions of the losetup, mount and umount
programs that interact with it. These are all you need to make an
encrypted loopback device and then use it. For example:

You now have an encrypted block device that contains a filesystem
that holds your GPG private key. Without knowing both the
randomly-chosen key data and the offset that we supplied above, that
filesystem is useless to anybody. That's the point; storing those 2
secret bits of information on the laptop is the important next
step.

At this point, you can try the following to verify that the
filesystem mounts fine for you:

It's worth doing this by hand for a sanity check; you'll be tearing
your hair out later otherwise when autofs doesn't work for you!

If you're wondering why I use vfat/FAT32 as the filesystem in the
encrypted area, it's quite simple. I wanted a small, low-overhead
filesystem that supports long file names. It's not such an issue now,
but when I started using a small USB key ext2 and most of the other
Linux filesystems had a lot of overhead on small media.

Autofs setup

Autofs is quite easy to configure, for at least simple
setups. /etc/auto.master defines the list of mount points
that it knows about; the autofs init script will start one copy of
autofs for each of them. Mine looks like:

The format here is simple: when a user asks for a file under
/auto, autofs will look up the right thing to do in the "map"
file /etc/auto.misc etc. If the map file is non-executable,
then it should contain a simple list of mappings (lookup key, mount
options and device). If the map file is executable, then the map file
will be executed, with the lookup key passed in as an argument. The
map script is then responsible for printing the options and device on
stdout; the calling autofs process will then use that information and
call mount appropriately. If that sounds complicated, it's not
too bad. But it's very flexible. See
the autofs documentation for much more detail if you're
interested.

The map that matters here is /etc/auto.pen. I've written a
simple shell script that will attempt to detect if the USB stick is
connected, by looking for a /dev/sdX device with the right size. More
intelligent heuristics are clearly possible, but this works well
enough for me. If the USB stick is not detected, it returns a device
of "missing". If the USB stick is found, my script will return a
device of /dev/sdX1 or /dev/sdX2 depending on the key asked for. In
each case, the script will also print a selection of options. Most of
those will be obvious, but -fstype=pen is special.

Normally when working with autofs, you'd specify a normal
filesystem type using -fstype (such as ext3, vfat). It passes
that option on to the mount program underneath using -t
fstype. However, there is a clever feature here. Mount is
designed to be extensible - if you tell it to work with a filesystem
type it does not recognise, it will look for a helper program to run
instead, called /sbin/mount.fstype. This is the final step in
the autofs configuration - I have a special mount script (in
/etc/mount.pen for sanity, but sym-linked into /sbin/mount.pen) that
knows just how to call mount to make the encrypted filesystem
work.

GnuPG setup

GnuPG does not know anything about the details of the USB stick at
all. I have simply moved my private keyring
($HOME/.gnupg/secring.pgp) to the filesystem on the USB stick
and replaced it with a symbolic link:

Once I've finished with the GPG key, autofs will time out and
unmount the USB stick. I explicitly mount that filesystem read-only,
so even if I unplug the USB stick early it can't cause any problems on
the filesystem. I also tweak the timeout in the autofs init.d script
to make things work slightly faster - the default is 30 seconds, but I
prefer 5.

Other options

Other people have come up with similar ideas to make their private
data secure on their laptop/USB stick combination. As I have more time
I'll link to more of them here.

My good friend Daniel Silverstone has written libgfshare,
a secret-sharing library, which is how he solves at least some of this
problem.

Matthew Johnson has another way of
working: encrypting the entire hard disk and then using a USB
stick to hold the needed passphrase.

Revision history

v1 (2008-02-05)

Initial release

v2 (2008-02-05)

Added mention of libgfshare and cryptkey,
clarified why I use vfat in the encrypted filesystem