Following the
short
introduction to eCryptfs and file-system encryption solutions;
this article describes how I
used eCryptfs to encrypt
my entire $HOME,
and dm-crypt to
protect swap space (without breaking
hibernation).
Topics:
eCryptfs basics
eCryptfs is a kernel-native stacked cryptographic file-system for
GNU/Linux, that is used on top of existing mounted file-systems. It is
a part of Linux since version 2.6.19 (the
ecryptfs module),
but to work with it you need the userspace
tools:
ecryptfs-utils,
which in turn require
keyutils
(tools for the kernel key management system). Once you install these
two packages you can
modprobe ecryptfs and continue with the
setup. If you are interested in implementation details I highly
recommend the
Linux Journal
article by Michael Halcrow, the architect and former developer of
eCryptfs. Today Michael works at
Microsoft
on
BitLocker -
their own disk encryption solution.
Encrypting a directory
I co-authored another article on eCryptfs, that guides you trough the
process of creating a secure and private directory
within your
$HOME. You can read it on
the
Arch
Linux wiki.
Encrypting $HOME
First you need to backup your current $HOME, what I did was:
$ su -
# mv /home/user /home/user.old
# mkdir -m 700 /home/user
# chown user:user /home/user
# usermod -d /home/user.old user
After your new $HOME becomes
/home/user.old re-login to the
system. Then prepare the rest of the eCryptfs directory structure:
$ su -
# mkdir -p /home/.ecryptfs/user/.Private
# chmod 755 /home/.ecryptfs
# chmod -R 700 /home/.ecryptfs/user
# chown -R user:user /home/.ecryptfs/user
# ln -s /home/.ecryptfs/user/.Private /home/user/.Private
# chmod 500 /home/user
Directory
/home/.ecryptfs is owned by root and it is a
central place for everything related to eCryptfs and user
accounts. Everything under
/home/.ecryptfs/user is owned by
you and the actual encrypted data will be stored
in
/home/.ecryptfs/user/.Private. That directory will be
mounted on top of
/home/user (for convenience I will use the
symlink
/home/user/.Private when
mounting). While
/home/user is not mounted we made sure that
nothing can be written there with that last
chmod
command. This will prevent cronjobs and other software from causing
problems.
Note: Previously this article explained a much simpler setup,
using
/home/user as both lower and upper directory. This new
approach is better and safer. Among other things it avoids problems
with cronjobs (as explained), and it is much easier to access your
encrypted data (i.e. for backup).
We can now mount eCryptfs over
/home/user - notice that while
mounted it will have the same permissions as the
lower
.Private directory:
# mount -t ecryptfs /home/user/.Private /home/user
Since this is the first time you are mounting this directory eCryptfs
will ask you some questions about how you want it set up. Summary of
my own options:
Key type: passphrase
Passphrase: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Cypher: twofish
Key byte: 32
Plaintext passtrough: yes
Filename encryption: yes
Add signature to cache: yes
Filename encryption is available from
Linux 2.6.29, and I
enabled passtrough because I needed it for auto-mounting later (it
allows un-encrypted files to be stored in the lower directory). When
asked you can also generate an additional key that will be used for
filename encryption, or you can use the same key you generated for
encrypting file contents. As for your passphrase, I don't need to tell
you that it should be strong, you can generate a batch of strong
pseudo-random passphrases with a command like:
# < /dev/urandom tr -cd \[:graph:\] | fold -w 32 | head -n 5
Remember it or print it on paper for safe keeping, this will be
your
mount passphrase which will be used to mount this
directory. Without it your data is
lost.
Note: The relation between a
passphrase
and
key(s) could be confusing, so I will explain it in more
detail; The passphrase is your mount passphrase which will be salted,
hashed and loaded into the kernel keyring. In eCryptfs terms, this
salted, hashed passphrase is your "
file encryption key, encryption
key", or
fekek (I will refer to it as just "
key" later in the
text). Also, in eCryptfs terms the key used to protect filenames is
known as "
filename encryption key",
or
fnek. Usually it is automatically generated from the same
passphrase, which is salted and hashed a little differently then it
was for generating the
fekek.
The directory is now mounted and your key is in the kernel keyring. We
now have to edit a few files to allow easier mounts in the
future. First inspect your
/etc/mtab file, it contains an
entry for encrypted
/home/user, which you need to replicate
in
/etc/fstab. An example entry in fstab might then look like
(
XYZ represents the key signature):
# Encrypted volumes
/home/user/.Private /home/user ecryptfs rw,user,noauto,exec,ecryptfs_sig=XYZ,ecryptfs_cipher=twofish,ecryptfs_key_bytes=32,ecryptfs_passthrough,ecryptfs_fnek_sig=XYZ,ecryptfs_unlink_sigs 0 0
When mounting your new $HOME as a user you will use
mount -i
so you don't invoke the mount helper again. Using
-i by
default mounts with
noexec, nosuid, nodev - this being your
$HOME you will probably want to have executable files, so I
added
exec to the above fstab line.
When you mounted, a
/root/.ecryptfs directory was
automatically created - that's where the signature cache was
stored. Let's create a few other files in there (later we will move
this configuration directory, and transfer the ownership to you):
# touch /root/.ecryptfs/auto-mount
# ecryptfs-wrap-passphrase /root/.ecryptfs/wrapped-passphrase
Passphrase to wrap: [enter mount passphrase]
Wrapping passphrase: [enter user password]
Let's explain the second command. We are using a passphrase for our
mount point and the key needs to be added to the kernel keyring every
time we want to mount
/home/user. Our later goal is to have
auto-mounting on login, so to make that easier and automatic we
encrypted our mount passphrase with our login password. The resulting
hash is stored in the
wrapped-passphrase file, which can be
unwraped by the eCryptfs
PAM module on login (more about this
below). This also has some security implications, which we will
discuss later on.
Our initial setup is done, let's un-mount the directory:
# umount /home/user
Auto mounting on login
To be able to auto-mount when you login to the system your eCryptfs
configuration directory must be readable, it can't be encrypted. We
will now move it to
/home/.ecryptfs/user:
# mv /root/.ecryptfs /home/.ecryptfs/user
# chown -R user:user /home/.ecryptfs/user/.ecryptfs
# ln -s /home/.ecryptfs/user/.ecryptfs /home/user/.ecryptfs
Now we have to write the actual auto-mounting code. For
me the
simplest solution was to employ shell initialization files. In my case
and ZSH those being
~/.zprofile and
~/.zshrc. In
case of BASH
~/.profile and
~/.bashrc can be
used. The way your shell reads init files is important,
the
profile file is read first and in case it's an
interactive shell the
rc file is read next. You could add the
auto-mount code to your existing profile or rc file and leave it
un-encrypted. But let's not expose any more information than it is
absolutely needed. I setup my
~/.zprofile to mount on login
and left
~/.zshrc encrypted. Let's see the example code:
# -*- shell-script -*-
#
if [ -r "${HOME}/.ecryptfs/auto-mount" ]; then
grep -qs "${HOME} ecryptfs" /proc/mounts
if [ $? -ne 0 ]; then
mount -i "${HOME}" ; cd "${HOME}"
fi
fi
In order for this code to be executed the file must be
readable. That's why we enabled passtrough before. Save it
as
/home/profile.sh for now.
Note: An alternative to mounting from your shell profile is to
use the
pam-mount
package. You should also know that eCryptfs PAM module has some
auto-mounting functionality, but most of it was written
with
Ubuntu in mind. To make use of it you would have to
setup everything exactly the way Ubuntu does. In fact, if you followed
this guide then you already did so. However it's not possible to
change default options and you would have to use AES and a 16 byte
key. How does it work? If the PAM module finds the
auto-mount
file it unwraps the passphrase and proceeds to
call
/sbin/mount.ecryptfs_private which can successfully
mount only if all above requirements are met. Same thing applies to
un-mounting when session is closed, provided the PAM stack is
configured correctly.
Now we need to configure
PAM to automatically unwrap the
passphrase on login (using the password the user entered to login to
the system). My current workstation is running
Arch Linux so
I modified
/etc/pam.d/system-auth - on other
distributions
/etc/pam.d/login or
common-auth
could be used (also consider the run-level and possibly login manager
you are using). The important part being to add the first setting
immediately
below the line referencing the
pam_unix.so
module in the
auth context and the second
immediately
above the line referencing the
pam_unix.so
module in the
password context. Let's see an example from
Arch Linux:
#%PAM-1.0
#...
auth required pam_unix.so try_first_pass nullok
auth required pam_ecryptfs.so unwrap
#...
password required pam_ecryptfs.so
password required pam_unix.so try_first_pass nullok sha512 shadow
#...
# eCryptfs optional in session context
#session optional pam_ecryptfs.so
Now that you prepared everything for automatic mounting you can once
again mount
/home/user to transfer your files back - and
encrypt them in the process. When you un-mounted the directory the key
was deleted from the kernel keyring so you will have to insert it once
more. This would also be a good place to mention that
keyctl
utility can be used for key management or for some simpler operations
you can use the
ecryptfs-manager:
$ ecryptfs-insert-wrapped-passphrase-into-keyring /home/user/.ecryptfs/wrapped-passphrase
Passphrase: [enter user password]
$ mount -i /home/user
Now move or copy your files from
/home/user.old
to
/home/user. If you have enough space you should definitely
copy so you have a backup. Files will be encrypted as they are placed
in their new home:
$ rsync -aP /home/user.old/ /home/user/
When it's done you should exit and login as root, un-mount the
encrypted directory and change your $HOME once more. Last step is to
setup the shell profile you prepared earlier:
# umount /home/user
# usermod -d /home/user user
# chmod 600 /home/profile.sh
# chown user:user /home/profile.sh
# mv /home/profile.sh /home/.ecryptfs/user/.Private/.profile
# ln -s /home/.ecryptfs/user/.Private/.profile /home/user/.profile
# exit
You can now login as a user to test if auto-mounting works. PAM will
unwrap your passphrase and insert the key into the kernel
keyring. Your auto-mount code from
~/.profile will be run
next. You are now using an encrypted $HOME directory.
It is a good idea to create another set of links (this time encrypted)
to your eCryptfs configuration directories, so that both your
encrypted and un-encrypted $HOME points to them:
$ ln -s /home/.ecryptfs/user/.ecryptfs /home/user/.ecryptfs
$ ln -s /home/.ecryptfs/user/.Private /home/user/.Private
Encrypting swap space
Various data is leaked to your swap space. If we are encrypting our
$HOME we have to encrypt swap too. Since eCryptfs is not ideal for
encrypting entire partitions we will use
dm-crypt for
this. Since nothing permanent is stored in swap you can
setup
dm-crypt to use a
random generated key every
boot and re-write the swap space. But in order for
suspend to
disk to work the hibernation image must not be changed/deleted. I
have read all kinds of miss-information about this, many claimed it's
impossible to use encrypted swap with hibernation. It's not
true. Important thing being to use a
static key for encryption
- so your swap stays unchanged on next boot and hibernation image
intact.
Note: My swap partition is
/dev/sda3 and I
use
uswsusp for
suspend/hibernate. Examples are written accordingly.
First we will setup an encrypted swap space, with dm-crypt
and
LUKS. Luks is
needed because of the static key, in Arch Linux package is
called
cryptsetup:
$ su -
Disable swap space
# swapoff /dev/sda3
Encrypt /dev/sda3 and set a passphrase (no connection to eCryptfs one)
# cryptsetup -h sha256 -c twofish-xts-essiv:sha256 -s 256 luksFormat /dev/sda3
Map /dev/sda3 to /dev/mapper/swap (using the passphrase)
# cryptsetup luksOpen /dev/sda3 swap
Make /dev/mapper/swap a swap device
# mkswap /dev/mapper/swap
Enable the encrypted swap
# swapon -p 1 /dev/mapper/swap
Swap is configured, now edit a few files to tell your system to use
this new swap. Everything that will be written to it will be encrypted
on the fly and actually written to your real swap partition. First
comment out your current swap entry in
/etc/fstab and create
a new one pointing to your new swap space:
#/dev/sda3 swap swap defaults 0 0
# Encrypted volumes
/dev/mapper/swap swap swap defaults 0 0
Uswsusp (or whatever method you are using - kernel, TuxOnIce) also
needs to know that the new
resume device
is
/dev/mapper/swap. Edit
/etc/suspend.conf and
replace your entry:
#resume device = /dev/sda3
resume device = /dev/mapper/swap
Note: You can also setup encryption with uswsusp it self. More
information can be found
in
/usr/share/doc/suspend/README.encryption. Basically you
generate a key file
/etc/suspend.key, enable encryption in
suspend.conf and point
"RSA key file" entry to the key you
generated. Your hibernate image would already be encrypted once when
written to
/dev/mapper/swap, but if you really want two
layers of encryption you could do it.
Now comes the really tricky part. In order to resume from hibernation
your (encrypted)swap must be mounted early on. How hibernation is
usually done is with a
resume hook in your initrd. You will
need another hook in there that will setup swap before resume hook is
run. I will explain my setup on Arch Linux, for
Debian I
found
one guide on how to do it there.
Arch Linux already has an
encrypt hook that is used to mount
the
root (and
only root) file-system in case it's
encrypted. All other encrypted partitions are mounted later on
from
/etc/crypttab - not of much use for hibernation, because
by then it would be too late. I modified the
hook
/lib/initcpio/hooks/encrypt and changed
cryptdev
to
"/dev/sda3" and
cryptname to
"swap". In
recent versions the syntax has changed and
cryptdevice is used
like so:
cryptdevice="/dev/sda3:swap
swap=/dev/mapper/swap". This also means that you can
append
"cryptdevice=/dev/sda3:swap" to the kernel in your
boot loader configuration and avoid editing the hook all
together.
The basic thing here is that a command like the following example must
be run on boot (it will ask for the passphrase and then unlock the
swap partition):
/bin/cryptsetup luksOpen /dev/sda3 swap
Add the
encrypt hook
to
/etc/mkinitcpio.conf before
the
uresume/resume and
filesystems hooks. You should
then re-create the initrd:
# mkinitcpio -p kernel26
All done. You can reboot and test it with a clean hibernation
cycle.
Note: If you have concerns about using a static key, consider
using a static key only when you hibernate, while using a random key
otherwise. It can be done and you will find examples of automation on
the web. If nothing else you can re-mount the swap by hand, using a
passphrase, before hibernating.
Encrypting other directories
Some other directories to consider for encryption are:
/tmp
and
/var/tmp. You could use dm-crypt or eCryptfs with random
keys for
/tmp since nothing permanent is stored there. But
because of this, you could also just setup
/tmp
as
tmpfs and have it in memory. The
/var/tmp directory
is trickier, it holds some data that should be preserved and it should
be mounted
very early in the boot process (before anything else
is written there). Doing it would be an interesting
exercise.
An example fstab entry for the
tmpfs:
# Pseudo
none /tmp tmpfs defaults,size=512M,mode=1777 0 0
Notes on security
If you decided to use auto-mounting eCryptfs setup explained here
employs a strong encryption passphrase for your files, but actually
protects it with your user login password (which in most cases doesn't
even have 10 characters). First think about making your login password
more complex, using eCryptfs or
not. The
Diceware
method provides strong passwords that are easy to remember. I also
recommend this document
on
password recovery
speeds.
Simple method for drastically improving the security of your eCryptfs
setup is to move your
wrapped-passphrase file to a removable
storage device, like a memory card. Symlink it to your eCryptfs
configuration directory, and in this scenario you get
two-factor
authentication, something you
know (your password) and
something only you
have (your wrapped-passphrase file):
$ ls -al ~/.ecryptfs/wrapped-passphrase
lrwxrwxrwx 1 user user 18 2009-03-14 21:45 /home/user/.ecryptfs/wrapped-passphrase -> /mnt/usb/.ecryptfs/key
Note: If you ever change your login password you can use
the
ecryptfs-rewrap-passphrase utility to update and
re-encrypt your wrapped-passphrase file.
Using this method requires your removable storage to be mounted before
you login. Modern distributions allow you to auto-mount
through
udev but there are also legacy solutions
like
autofs which still work good. Using it your media would
be mounted the moment PAM tries to read your wrapped-passphrase. Here
are some mount options to consider:
usb -fstype=vfat,utf8,shortname=mixed,noexec,umask=077,fmask=0177,dmask=0077,uid=1000,gid=1000 :/dev/sdc1
Consider using additional layers of encryption. You can encrypt
individual files (i.e. that hold passwords) or tarball-ed directories
with
GPG. If
needed, tools
like
Elettra
provide plausible deniability.
Last topic I will discuss are backups. Backup is mandatory, but if you
went through all this to secure your data you can't just dump it on a
file-server. The data must remain encrypted. One approach is to
encrypt the destination it self, the other to backup the source in
encrypted form (or both, yes). For removable drives both options are
feasible, but in case of a network file-system eCryptfs is still not
fully functional over NFS. My personal backup
solution,
rybackup,
has eCryptfs support and could give you some ideas.