DM-Crypt
From Gentoo Linux Wiki
| Please format this article according to the Style Guidelines and Wikification suggestions, then remove this notice {{Wikify}} from the article.
Reason(s):
|
There are a lot of threads out there on how to encrypt your root file system. This howto attempts to use a new concept implemented by Clemens Fruhwirth 1 named luks.
[edit] Introduction
luks doesn't store information in configuration files that can be lost or compromised, but on the encrypted partition itself. It creates a header on the partition that contains all information required by the decryption program, such as the algorithm, mode, etc...
Another benefit of luks is that it doesn't directly use the password that you give it at the beginning to encrypt the partition. Instead, it encrypts the master key (the one used to encrypt the data) with your password. If you want to change your password ('oldpassword' for ex.), it decrypts the master key with 'oldpassword', and reencrypts it with 'newpassword'. The master key isn't changed in this procedure, it is merely reencrypted, saving you the trouble of reencrypting your entire harddrive. This is especially handy in the case of a password compromise.
It's also possible to make multiple copies of the master key, all encrypted with a different password, allowing a type of password management system. this allows you to revoke passwords if they get compromised, or give different users different passwords to access the encrypted data. luks reserves space at the beginning of the partition for 8 different password (called key slots). Be aware that anyone with ANY valid key to the drive can delete/add keys.
+--------+--------+-----+--------+----------------+ | Header | Slot 0 | ... | Slot 7 | Encrypted Data | +--------+--------+-----+--------+----------------+
Anyways, to the practical stuff... (some of this shamelessly copied from here: SECURITY Encrypting Root Filesystem with DM-Crypt)
[edit] Assumptions
- Kernel 2.6.11: disk driver builtin, ext2/reiserfs filesystem drivers builtin,
- device mapper/encryption modules dm-crypt/dm-mod builtin, aes builtin,
- ramdisk and initial ramdisk (initrd) builtin.
| Linux Kernel Configuration: General setup |
File systems --->
<*> Second extended fs support
<*> Reiserfs support
Device Drivers --->
Block devices --->
<*> Loopback device support
< > Cryptoloop Support
(4096) Default RAM disk size (kbytes)
[*] Initial RAM disk (initrd) support
Multi-device support (RAID and LVM) --->
<*> Device mapper support
<*> Crypt target support
Cryptographic options --->
<*> SHA256 digest algorithm
<*> AES cipher algorithms (i586)
|
- A empty partition for Boot on /dev/hda1 filesystem is ext2.
- A empty partition for Root on /dev/hda3 filesystem is reiserfs
- A linux system e.g on /dev/hdb or on a gentoo install cd 2006.0 ,so that you can follow all coming steps.
- You will be prompted for encryption passphrase at boot time.
- You are using udev.
- You are using grub boot loader.
- You're logged in as root.
[edit] Requirements
You'll need to emerge device-mapper:
You'll need cryptsetup 1.0.5 or newer (which contains luks support):
If you have udev you will also need the multipath-tools
[edit] Preparing Initrd Image
Now we need to create our initrd, I'll call it myinitrd. It's a simple task once you played around a bit with it. I highly recommed playing with initrd's before you go actually and encrypt your root (last step in this mini-howto). First create the image, I'm using a 4MB initrd but feel free to expand that if you need more, just remember to set the option in your kernel configuration for the maximum ramdisk size properly. (see 'Assumptions' section)
Now populate the image with required directories and files:
Linuxrc is where the action will be. It's a script file to be loaded by linux on initial boot, more below. Now you need to copy necessary files into bin, sbin and lib. For bin, copy the following from your current system:
if you use jfs:
For lib, you'll need to find out which lib files are needed by each of the binaries above. The way to do it is to run 'ldd' for each file above and copy the required libs over. Example:
linux-gate.so.1 => (0xffffe000) libc.so.6 => /lib/libc.so.6 (0x4002e000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)cp /lib/libc.so.6 /mnt/initrd/lib/ cp /lib/ld-linux.so.2 /mnt/initrd/lib/
And so on for the rest of the binaries. Or use this perl script to do it for you
#!/usr/bin/perl
chdir "/mnt/initrd/bin";
$lol = `ldd \`ls\``; #ldd of every bin
@lines = split /\n/, $lol; #put each line in array
foreach(@lines){
if($_ =~ /\/lib\/(\S+)/){ #find "/lib/*"
$hash{ $1 } = 0; #use hash to prevent duplicates
}
}
@files = keys %hash; #pull the files out of the hash
foreach (@files){ #step through each
`cp /lib/$_ /mnt/initrd/lib` #copy to initrd lib dir
}Now, we need to create necessary devices in the dev directory:
You can also try:
| Fix me: please check correctness of this |
If you are using hda2 replace the numbers above with "b 3 2". If you are unsure of the major/minor numbers you should use mount /proc and cat /proc/devices. This should be done off the ram drive (more about that later).
[edit] Initrd Scripts
Now we need to create the linuxrc and devmap_mknod.sh scripts that will be executed in the initrd. The linuxrc script should setup dm-crypt and mount root on it, then start the real init of the system. Here it is:
#!/bin/sh
export PATH=/bin:/sbin
# Get cmdline from proc
mount -t proc proc /proc
CMDLINE=`cat /proc/cmdline`
# Create /dev/mapper/control nod for udev systems
sh devmap_mknod.sh
# Mount real root and change to it
sleep 1
cryptsetup -y luksOpen /dev/hda3 root
while test $? -ne 0; do
cryptsetup -y luksOpen /dev/hda3 root;
done
umount /proc
# If you use JFS, check the filesystem before mounting to make sure it's clean.
# If it's not clean, mounting will fail.
# fsck.jfs /dev/mapper/root
mount /dev/mapper/root /new
cd /new
mkdir initrd
pivot_root . initrd
# Start init and flush ram device
exec chroot . /bin/sh <<- EOF >/dev/console 2>&1
umount initrd
rm -rf initrd
blockdev --flushbufs /dev/ram0
exec /sbin/init ${CMDLINE}
EOF
Now look at the devmap_mknod script. It has to create the /dev/mapper/control node with good values provided by /proc/devices.
#!/bin/sh
# Startup script to create the device-mapper control device
# on non-devfs systems.
# Non-zero exit status indicates failure.
DM_DIR="mapper"
DM_NAME="device-mapper"
set -e
DIR="/dev/$DM_DIR"
CONTROL="$DIR/control"
# Check for devfs, procfs
if test -e /dev/.devfsd ; then
echo "devfs detected: devmap_mknod.sh script not required."
exit
fi
if test ! -e /proc/devices ; then
echo "procfs not found; please create $CONTROL manually."
exit 1
fi
# Get major, minor, and mknod
# sed does not work as expected!
# See the discussion page if you wonder why the following two lines are commented out.
#MAJOR=$(sed -n 's/^ *\([0-9]\+\) \+misc$/\1/p' /proc/devices)
#MINOR=$(sed -n "s/^ *\([0-9]\+\) \+$DM_NAME\$/\1/p" /proc/misc)
MAJOR=`awk '/misc$/ {print $1}' /proc/devices`
MINOR=`awk '/'"$DM_NAME"'$/ {print $1}' /proc/misc`
if test -z "$MAJOR" -o -z "$MINOR" ; then
echo "$DM_NAME kernel module not loaded: can't create $CONTROL."
exit 1
fi
mkdir -p --mode=755 $DIR
test -e $CONTROL && rm -f $CONTROL
echo "Creating $CONTROL character device with major:$MAJOR minor:$MINOR."
mknod --mode=600 $CONTROL c $MAJOR $MINOR
That's basically it for the initrd.
It's advisable to test all bin files in it by chrooting and running them one by one. You should get no error messages about missing libraries.
Unmount the initrd and copy it over to /boot. If you use bootsplash you can append the bootsplash initrd to it. Note that you can still mount/unmount the image and play with it event after cat'ing the bootsplash image to it. mount knows its start and end.
With bootsplash:
Without bootsplash:
[edit] Using initramfs and busybox
Initramfs is a newer replacement for initrd which will become the new standard for booting Linux systems. At a high level it's just a different way to populate a ram disk for booting. Unfortunately, pivot_root does not work from initramfs and it looks like it never will, see http://bugzilla.kernel.org/show_bug.cgi?id=4857 , http://www.ussg.iu.edu/hypermail/linux/kernel/0510.1/0014.html , and https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=137005 . Instead of pivot_root, we will use busybox's switch_root.
Busybox is a Swiss army knife shell that contains almost everything you will need to boot. It can be installed as a statically linked binary, so you won't have to deal with copying libraries for the binaries you use.
Emerge a static busybox. If you don't want to overwrite the busybox that's already on your sytstem, use emerge's ROOT= option.
The busybox ebuild makes an inconvenient choice for the CONFIG_BUSYBOX_EXEC_PATH option. Busybox uses this setting to locate itself when it needs to execute commands. The default for this option is /proc/self/exe, which has the effect that /proc needs to be mounted for most scripts to work. When the kernel starts /linuxrc, /proc is not mounted, so the above scripts for initrd will fail. The fix is to explictly reference /bin/busybox when /proc is not mounted. If you would rather not prefix some commands with /bin/busybox, you can build your own busybox with CONFIG_BUSYBOX_EXEC_PATH="/bin/busybox". You can also save about a half meg of memory by disabling the two hundred or so unneeded commands that the ebuild includes.
[edit] Preparing the initramfs image
Initramfs uses a compressed cpio archive, rather than the raw filesystem image that initrd uses. First, create a root for your initramfs and make the top level directories:
Now copy busybox into your initramfs and hard link sh to it. Busybox doesn't include cryptsetup, so you also need to copy that. Fortunately, cryptsetup is statically linked.
cd /tmp/myroot/bin
cp /tmp/bb/bin/busybox .
for i in echo mkdir mknod mount sed sh switch_root test touch umount
do
ln busybox $i
done
cp /sbin/cryptsetup .Create the necessary devices in your dev directory. Replace hda3 with whatever device you are using for your encrypted parition. Use ls -l to get the right major and minor device numbers.
Make the initramfs archive file and copy it to /boot (do this AFTER preparing linuxrc and devmap_mknod.sh):
linuxrc for initramfs
The linuxrc script opens and mounts the encrypted root partition and then calls /sbin/init to boot the OS. Change CRDEV to point to your encrypted partition. Create this file in the root of your initramfs. When you are done, make it executable with chmod +x linuxrc. If you use the kernel's rdinit= option, you do not need an /init. Switch_root checks for /init to make sure it is being run correctly, so the script has to make sure it's there. Instead of using touch, you could just put an empty /init in the root of your initramfs.
#!/bin/sh
export PATH=/bin:/sbin
CRDEV=/dev/hda3
/bin/busybox mount -t proc proc /proc
CMDLINE=`cat /proc/cmdline`
sh devmap_mknod.sh
until /bin/cryptsetup -y luksOpen ${CRDEV} root; do :; done
mount -r /dev/mapper/root /new
# busybox switch_root insists on finding a regular file called /init
touch /init
umount /proc
exec /bin/busybox switch_root /new /sbin/init ${CMDLINE}devmap_mknod.sh for initramfs
devmap_mknod.sh is the same as for initrd, except that the busybox mkdir and mknod commands don't support long options. Create this file in the root of your initramfs.
#!/bin/sh
# Startup script to create the device-mapper control device
# on non-devfs systems.
# Non-zero exit status indicates failure.
DM_DIR="mapper"
DM_NAME="device-mapper"
set -e
DIR="/dev/$DM_DIR"
CONTROL="$DIR/control"
# Check for devfs, procfs
if test -e /dev/.devfsd ; then
echo "devfs detected: devmap_mknod.sh script not required."
exit
fi
if test ! -e /proc/devices ; then
echo "procfs not found; please create $CONTROL manually."
exit 1
fi
# Get major, minor, and mknod
# The lines with sed caused unexpected errors in busybox (1.8.2), see discussion! -Craig-
#MAJOR=$(sed -n 's/^ *\([0-9]\+\) \+misc$/\1/p' /proc/devices)
#MINOR=$(sed -n "s/^ *\([0-9]\+\) \+$DM_NAME\$/\1/p" /proc/misc)
MAJOR=`awk '/misc$/ {print $1}' /proc/devices`
MINOR=`awk '/'"$DM_NAME"'$/ {print $1}' /proc/misc`
if test -z "$MAJOR" -o -z "$MINOR" ; then
echo "$DM_NAME kernel module not loaded: can't create $CONTROL."
exit 1
fi
mkdir -p -m755 $DIR
test -e $CONTROL && rm -f $CONTROL
echo "Creating $CONTROL character device with major:$MAJOR minor:$MINOR."
mknod -m600 $CONTROL c $MAJOR $MINORAdd this to your grub.conf. Replace /bzImage-2.6.16 with the name of your kernel image. Note that we use rdinit=, not init=.
default 0
timeout 30
title bzImage-2.6.16
root (hd0,0)
kernel /bzImage-2.6.16 root=/dev/ram0 rdinit=/linuxrc ramdisk=8192 real_root=/dev/mapper/root
initrd /myiramfsNote: to debug problems try adding /bin/busybox /bin/sh to linuxrc.
[edit] Encrypting the Filesystem
This is a bit tricky. In order to encrypt the filesystem using luks, you need to be able to use a cryptsetup-luks binary, not a normal cryptsetup binary. You can do this with a gentoo install cd 2006.0 or later. Earlier versions only contain the normal cryptsetup binary. i'm going to do this using a second hard drive (/dev/hdb). i'm going to set up the encrypted partition and copy everything from the 'old' hard drive (/dev/hdb) to the 'new' one (/dev/hda).
you could do this with a livecd, by starting it with the docache option, then switching in a cd that has a cryptsetup-luks binary on it, but that's a bit more complicated than this method. note: if the livecd supports usb sticks, you could put the luks cyptsetup onto one of those and use that... just another idea...
- Ok, so now i have two hard drive in my pc the old (/dev/hdb) and the new (/dev/hda) that i will be encrypting.
- First, make sure everything that was on the drive can never be read again
(note: this is optional, and can take a LONG time)
- Now we format the partition with luks, this creates the header and master key
- Now we need to let cryptsetup create the /dev/mapper entry
- Now format the partition. i'm going to use reiserfs.
- Now mount the partition
- I'm going to copy everything from my current root partition to this new encrypted partition
(first I'm going to mount the drive I'm going to copy from at another location)
note: this howto is not quite finished, but is actively being worked on
[edit] Modifying fstab & grub.conf (& local udev rules if necessary)
We need to modify /etc/fstab to point to our new root. Here's my new fstab:
/dev/mapper/root / reiserfs noatime 0 1 /dev/hda1 /boot ext2 noauto 0 0 /dev/hda4 none swap sw 0 0 none /proc proc defaults 0 0 none /dev/shm tmpfs defaults 0 0
And here's my new grub.conf:
default 0 timeout 5 splashimage=(hd0,0)/grub/splash.xpm.gz title=Gentoo Linux (2.6.11) root (hd0,0) kernel (hd0,0)/bzImage-2.6.11 root=/dev/ram0 rw init=/linuxrc initrd (hd0,0)/myinitrd
The following section is most probably needed only in case you didn't emerge multipath-tools (they are not included yet in many (other than gentoo) distributions). If this is your case, use this line in your custom/local udev rules (e.g. in /etc/udev/00-local.rules):
[edit] Administering LUKS
For this section, we will be using a loopback file to demonstrate basic luks administration.
First you will need to create the loopback file and set it up.
[edit] Formatting
Now that we have a device, we need to format it using luks note: 'format' here means add the luks header and create a master key. this has nothing to do with the filesystem
[edit] Opening a device
Now that the device is formatted, we need to 'open' it. This means that it is set up to where we can use it in a meaningful way.
this created the device /dev/mapper/encrypted. You can choose the name as you wish
[edit] Making a Filesystem and Mounting
Now we can 'format' it again. This time format means to create a filesystem on it. I'm going to use reiserfs.
[edit] Unmounting and Closing a device
To unmount and close a file, do this:
The device /dev/mapper/encrypted no longer exists. neither does /dev/loop1.
[edit] Password management
luks allows you to easily manage passwords to your encrypted partitions/files/etc... this section explains how to add and delete passwords. Adding a Password
if you want to add another password, setup the loopback device again and use this command:
- What happened now was this
You entered the first password to decrypt the master key. you then gave cryptsetup a new password to encrypt the master key with. it then stored this new encrypted version of the master key in slot1. now you have two valid passwords for this file
to test this, you would use cryptsetup luksOpen /dev/loop1 foo and try both passwords (doing a cryptsetup luksClose foo in between of course)
note: the 'first password' can be any valid password. For example, if you have 5 valid passwords, and want to add a sixth one, you can enter any of those 5 to create the 6th. Deleting a Password
This command deletes the password stored in slot1 (the second slot)
[edit] Automatic Mounting of Encrypted User Directories
Till 14:36, 5 April 2006 (GMT): Im not using Gentoo, so I may miss some Gentoo specific details. pam_mount 0.13.0 (and maybe older releases, too) can handle luks encrypted partitions.
You can test manually whether this works with:
This should ask you for the luks passphrase, decrypts /path/to/encrypted/device and mounts it to /path/to/mountpoint If mount tells you something about crypt beeing an unknown filesystem, make sure that mount.crypt is in /sbin, it may be in /usr/bin, with a symlink:
In /etc/security/pam_mount.conf you need an entry like this:
<!-- Volume definitions --> <volume user="bob" fstype="crypt" path="/dev/mapper/vg-partition" mountpoint="/home/bob" options="noatime" />
In /etc/pam.d/system-auth you need need to add 2 lines to the default file:
auth required pam_env.so auth required pam_unix.so try_first_pass likeauth nullok # the following line is for pam_mount auth optional pam_mount.so account required pam_unix.so password required pam_cracklib.so difok=2 minlen=8 dcredit=2 ocredit=2 retry=3 password required pam_unix.so try_first_pass use_authtok nullok sha512 shadow session required pam_limits.so session required pam_env.so session required pam_unix.so session optional pam_permit.so # the following line is for pam_mount session optional pam_mount.so
Additional options about ciphers etc. are stored in the luks header of the partition after invoking the luksFormat command and they do not need to be specified here (they will even be ignored when specified).
WARNING Make sure that you luks encrypted partition ist closed after logout, umounting it is not enough. A encrypted partition /path/to/encrypted/device is normally decrypted and mapped to /dev/mapper/_path_to_encrypted_device by pam_mount. This file must not exist after the user logged out.
[edit] Encrypting swap and /tmp/
If you only encrypt the users' home directories, you might also want to encrypt swap and the places where temporary files are stored to ensure a high degree of privacy. Fortunately for those places, data persistence across sessions is not important, so they can be recreated from scratch when booting. This is accomplished by passing cryptsetup /dev/urandom as the key file. (/dev/random might not be active enough yet in the early boot stages.)
All you have to do is add (and change) some entries in /etc/fstab and in /etc/conf.d/dmcrypt. The latter is checked before fstab is interpreted and tells cryptsetup which devices to map where. You basically just insert entries for two devices: swap and tmp.
[edit] Mapping block devices to encrypted devices
Now for the first entry, to create an encrypted swap partition. Let's assume you want /dev/sda3 (probably safer in case you plug in a new hard drive: /dev/disk/by-id/ata-FOO_123456_0987-part3) to become your swap. The boot script needs to know the source (the block device to encrypt), the target (where to map it to) and the type (swap in this case) for the encryption it will perform. So enter these values to have /dev/sda3 encrypted and mapped to /dev/mapper/crypt-swap:
## swap # Swap partitions. These should come first so that no keys make their # way into unencrypted swap. # If no options are given, they will default to: -c aes -h sha1 -d /dev/urandom # If no makefs is given then mkswap will be assumed #swap=crypt-swap #source='/dev/hda2' swap=crypt-swap source='/dev/disk/by-id/ata-FOO_123456_0987-part3'
By saying that this will be for a swap partition, /dev/urandom is automatically selected as the key file.
The lines for the /tmp/ partition (mapped from /dev/disk/by-id/ata-FOO_123456_0987-part6 in this example) are a bit more complicated:
target=crypt-tmp
source='/dev/disk/by-id/ata-FOO_123456_0987-part6'
key='/dev/urandom'
options='-c aes-cbc-essiv:sha256'
pre_mount='/sbin/mkfs.ext2 -L crypto-tmp ${dev}'
post_mount='chown root:root ${mount_point}; chmod 1777 ${mount_point}'
It will be encrypted with a random key, mapped to /dev/mapper/crypt-tmp, made into an ext2 file system, and the permissions and ownership will be set appropriately after mounting. The value of the options variable is passed to cryptsetup, so you may specify anything you want here. /etc/conf.d/dmcrypt has plenty of comments and examples, so you should feel pretty comfortable there.
[edit] Mounting the mapped devices
So far, the partitions have been only mapped, but mounting now is only one simple step away: Adapt your old entries in /etc/fstab. For Linux, the /dev/mapper/foo files look like ordinary block devices:
Add these lines and don't forget to delete the old lines.
# crypto devices # encrypted swap partition /dev/mapper/crypt-swap none swap sw 0 0 # new tmp directory to /tmp, link there from /var/tmp (and /usr/tmp) /dev/mapper/crypt-tmp /tmp ext2 auto,noatime 0 2
But wait, ain't there more temporary directories than just /tmp/? Yes, but you can simply redirect them. So better shut down X now (if you had it running), delete /var/tmp/ and link there from /tmp/:
rm -r tmp/
ln -s /tmp/This should give you a fresh swap and a new /tmp/ every time you boot, and no possibility to recover data you had there after shutting down your computer.