Implementing Encrypted Home Directories
When used correctly, encrypted filesystems can be an effective way to protect sensitive data stored on a computer. Standard encryption packages, such as the GNU Privacy Guard (GPG), are good for encrypting e-mail. They are not as convenient, however, for encrypting files one wishes to read or modify many times throughout the files' lifetimes.
Unlike GPG, an encrypted filesystem is transparent to users. There is no hassle of manually decrypting a file before reading it or encrypting it again after modifying it. Potential user forgetfulness also is mitigated. After introducing some encrypted filesystems available for Linux, this article explains how to create an encrypted home directory that is automatically mounted at login time and unmounted at logout. Finally, this article introduces some concepts that demonstrate the dangers of improperly implemented encryption techniques.
Why would one want to encrypt the data stored on a computer? Isn't protecting sensitive data what filesystem permissions are for? Although useful, filesystem permissions quickly lose their effectiveness when an attacker has complete control of the storage medium the permissions are used to protect. For example, if someone steals my Linux laptop, an Apple iBook, its filesystems permissions are of little use against the thief who can simply boot from a diabolical CD-ROM. The same is true if I send my laptop to Apple for repairs. A dishonest employee conceivably could read my files. Correctly encrypting the files on a computer is a safe form of protection, because the process does not depend on the integrity of the operating system after the encryption takes place.
I have chosen to encrypt only the home directories on my iBook. Encrypting the entire filesystem, starting with root, was not acceptable in my case due to performance penalties and other factors. Information on implementing this technique can be found on the Internet—it requires using Linux's initial ramdisk capability. In my experiences with an x86-based system, the encryption technique I chose is around 50% slower than a non-encrypted XFS filesystem when writing to disk using buffered I/O. Encrypting only home directories obviously leaves many files, such as system logs, as plain text, but these were not significantly sensitive in my case. Encrypting only home directories was a sensible compromise for me.
Linux supports a few options for encrypting filesystems. Systems such as the Transparent Cryptographic File System provide an encrypted extension to NFS-served ext2 volumes. Other filesystems contain integrated cryptography in their design for local use. For my application, the best solution seemed to be the concept of loopback encrypted filesystems. As you will see, loopback encryption can be used to encrypt any filesystem type supported by Linux, including the proven ext2, XFS and ReiserFS.
Linux loopback filesystem support simply allows a user to mount an ordinary file as if it were a device, such as /dev/hda1. This traditionally is useful for doing things like mounting a CD-ROM filesystem image to populate and test before burning it to CD-R media or distributing bootable floppy disk images. Herbert Valerio Riedel's GNU/Linux Cryptographic API (CryptoAPI) and util-linux patches add support for mounting encrypted filesystem images to the loopback driver.
Before delving into the details of loopback encrypted filesystems, let's take a look at how to create and mount a vanilla loopback filesystem. First, create a file to contain the filesystem. This example creates a file large enough to host a 20MB filesystem:
dd if=/dev/zero of=plaintext.img bs=1M count=20
Second, associate the newly created file with a loopback device:
losetup /dev/loop0 plaintext.img
Next, create a filesystem within the file, using the newly associated loop device:
mkfs -t ext2 /dev/loop0
Finally, mount the filesystem and use it as if it were any other mounted volume:
mount /dev/loop0 mount point
Now, let us move on to the encrypted case. In order to use loopback encrypted filesystems, the kernel must support them. Most distributions do not include this functionality, so a custom-built kernel probably is necessary. A cryptographic API package similar to the one I use is being merged into the mainstream 2.5 kernel. However, for the stable 2.4 tree, the GNU/Linux CryptoAPI patches are necessary and available at www.kerneli.org. Once you apply the patch-int and loop-hvr patches, Cryptographic options should be available when you configure your kernel. The following options must be enabled:
cryptographic API support (CONFIG_CRYPTO)
generic loop cryptographic filter (CONFIG_CRYPTOLOOP)
cryptographic ciphers (CONFIG_CIPHERS)
You have to enable at least one cipher as well. Remember which cipher you choose. I chose AES, originally called Rijndael, and use AES in my examples.
Build and install the newly configured kernel. All of the kernel's encryption code may be compiled as modules. If you choose to build kernel modules, don't forget to insert them before you try to use their functionality. It also is necessary to patch util-linux, compile the tools and install them. The relevant util-linux patch is available at www.kernel.org/pub/linux/kernel/people/hvr/util-linux-patch-int. You should find that you end up with modified mount and losetup commands.
Now we are ready to create a loopback encrypted filesystem using a process similar to that which we used to create a vanilla loopback filesystem. First, in order to make it difficult to differentiate between encrypted blocks and unused disk space, the file that will hold the loopback filesystem is created using /dev/urandom instead of /dev/zero:
dd if=/dev/urandom of=ciphertext.img bs=1M count=20
After creating the host file, it must be temporarily associated with a loopback device, as before. This time, however, we must tell losetup that the loopback device is to be encrypted, in this case with the AES cipher:
losetup -e aes /dev/loop0 ciphertext.img
Enter the password and possibly—depending on the cipher you decided to use—the key size you wish to use for the volume when prompted by losetup.
Creating the filesystem is done in a manner identical to that for creating a vanilla loopback device. The encryption was set up in the previous step and is now handled by the loopback driver:
mkfs -t ext2 /dev/loop0
In addition to modifying losetup, the util-linux patch also makes the mount command crypto-aware. Mounting an encrypted loopback volume is a simple process, given the correct command parameters:
mount -o loop,encryption=aes ciphertext.img \ mount point