Encrypted Logical Volume Management
- Existing Layout
- Optimised Layout
- Data Back-Up
- Configure Logical Volume Management (LVM)
- Write Windows image
- Install Ubuntu
- Restart System and Test
- Install Software
Encrypted Logical Volume Management
This article shows how to use the Ubuntu Hardy Desktop Live CD to build and install to a secure encrypted Logical system that requires a key-file on an external USB memory stick in order to start. It also applies to Intrepid and Jaunty with minor adjustments. It is designed to secure portable PCs (netbooks, notebooks, laptops, etc.). It is based on my previous article: Hardy RAID-5 Encrypted with Logical Volume Management.
The existing organisation and usage of the laptop was preventing an upgrade from Gutsy to Hardy: sda6 (12.8GiB - the Gutsy / partition) was too full, and I had too many customisations I didn't want to lose. Most of the partitions were at or near capacity. I decided to backup all the data to other disks and do a clean install that allowed me to create an optimum configuration that included encryption and LVM.
In my case the laptop PC was fully utilising the 200GB (186GiB) hard disk:
fdisk -ul /dev/sda Disk /dev/sda: 200.0 GB, 200049647616 bytes 255 heads, 63 sectors/track, 24321 cylinders, total 390721968 sectors Units = sectors of 1 * 512 = 512 bytes Disk identifier: 0xf7fc3a6e Device Boot Start End Blocks Id System /dev/sda1 2048 19531775 9764864 27 Unknown /dev/sda2 * 19531776 77008895 28738560 7 HPFS/NTFS /dev/sda3 77008896 81008896 2000000+ 82 Linux swap / Solaris /dev/sda4 81015795 390716864 154850535 5 Extended /dev/sda5 81015858 81497744 240943+ 83 Linux /dev/sda6 81497808 108406619 13454406 83 Linux /dev/sda7 108406683 120551759 6072538+ 83 Linux /dev/sda8 120551823 390716864 135082521 83 Linux
- sda1 9.3GiB Sony Recovery
- sda2 27.4GiB Windows Vista
- sda3 1.9GiB Linux Swap
- sda5 235.3MiB /boot
- sda6 12.8GiB / (Gutsy - primary OS)
- sda7 5.8GiB / (Ubuntu+1 testing)
- sda8 128.8GiB /home
Note: The Data Back-Up step was done before the partition-table changes detailed here were performed. However, it seemed more logical to keep the before and after partition layout sections together in this article.
I wanted to simplify the Linux organisation, drop the almost 10GB taken up by the Sony Recovery partition, and shuffle the Windows Vista partition closer to the start of the disk. I also needed the LVM flexibility to shrink, grow, remove and create volumes to help with advanced testing.
- sda1 251.0MiB /boot
- sda2 27.4GiB Windows Vista
- sda3 4.0GiB Linux Swap
- sda4 154.8GiB Linux (encrypted) + LVM VG + / (Hardy), /var, /home, / (Ubuntu+1) and spare
I used cfdisk to create the revised layout (I initially used fdisk to ensure the Windows partition was exactly the same size as previously but cfdisk reported "FATAL ERROR: Bad primary partition 3: Partition ends in the final partial cylinder" so, since cfdisk's reputation is so good, I let it do the work. The result is that the Windows Vista partition is slightly bigger than the NTFS file-system image that was backed up, but Vista's Disk Management tool can expand the NTFS live file-system to ensure the slack space will be used.
fdisk -ul /dev/sda Disk /dev/sda: 200.0 GB, 200049647616 bytes 255 heads, 63 sectors/track, 24321 cylinders, total 390721968 sectors Units = sectors of 1 * 512 = 512 bytes Disk identifier: 0x4abc0f4b Device Boot Start End Blocks Id System /dev/sda1 63 498014 248976 83 Linux /dev/sda2 * 498015 57994649 28748317+ 7 HPFS/NTFS /dev/sda3 57994650 65995019 4000185 82 Linux swap / Solaris /dev/sda4 65995020 390716864 162360922+ 83 Linux
I copied a large amount of non-core data directories (Source-code repositories, audio-book libraries, camcorder library, etc.) to an external USB2 160GB drive. It already had a lot of data on it so I then used rsync to copy all of /, /boot, /home, and the Vista partition image to a RAID-5 server over a 100Mbps ethernet link.
Total data moved over ethernet was 30GiB + 10GiB + 27.4GiB and it took about 3.5 hours.
I started the laptop with the Hardy Desktop Live CD, installed the sshfs package from the universe repository, and mounted the network server in the Live CD environment:
sudo su sed -i 's/^# \(deb .*universe\)/\1/' /etc/apt/sources.list apt-get update apt-get install sshfs mkdir /mnt/remote sshfs firstname.lastname@example.org: /mnt/remote
I mounted the local hard drive partitions into the Live CD environment:
mkdir /mnt/rootfs mkdir /mnt/home mount /dev/sda6 /mnt/rootfs mount /dev/sda5 /mnt/rootfs/boot mount /dev/sda8 /mnt/home
I kept /home on a separate mount-point so I could rsync the root file-system and home separately. These operations took several hours:
rsync -ae ssh --delete /mnt/home/ email@example.com:Backups/home/ rsync -ae ssh --delete /mnt/rootfs/ firstname.lastname@example.org:Backups/rootfs/
I copied an image of the Windows Vista partition (27.4GiB) to the network server:
dd if=/dev/sda2 bs=512000 of=/mnt/remote/Backups/sda2-Vista.img
I copied an image of the Sony Recovery partition (10GB) to the external USB2 hard disk:
dd if=/dev/sda1 bs=512000 of=/media/disk/Backups/sda1-SonyRecovery.img
Finally, I made a backup of the master boot record (MBR) sector and a textual log from fdisk:
dd if=/dev/sda bs=512 count=1 of=/mnt/remote/Backups/mbr-sector.bin fdisk -ul /dev/sda > /mnt/remote/Backups/sda-fdisk.txt
First, install the cryptography package:
apt-get install cryptsetup
Load the kernel module:
Randomise the disk surface
By ensuring every sector of the disk partition is written with random data, a potential attacker will have great difficulty locating encrypted data that they might want to try to decrypt. If the surface of the disk was written with zeros (using if=/dev/zero) or some other predictable values encrypted data would be easy to identify if the disk were to fall into hostile hands.
Option 1: The Long Way
This is likely to take a long time - possibly 24 hours or more:
dd if=/dev/urandom of=/dev/sda4
Check the progress by sending the USR1 signal to the dd process from another terminal window:
ps -ef | sed -n 's/[a-z ]*\([0-9]*\).* dd.*/\1/p' | while read PID; do kill -USR1 $PID; done
The dd terminal will report its statistics:
6243380+0 records in 6243379+0 records out 3196610048 bytes (3.2 GB) copied, 559.041 s, 5.7 MB/s
Wait until dd finishes.
Option 2: The Short Cut
We can achieve most of the benefits with a short-cut. As always, evaluate the method based on your priorities. In this, a small (I chose 500MB) temporary file is created and then repeated written to the disk. It is much faster since the pseudo-random number generator only runs for a fraction of the time. The size of the temporary file (which is kept in RAM since this is the Live CD environment) is determined by the amount of system RAM. Here, the laptop has 2GB RAM so 500MB is reasonable:
SIZE=500000000 TOTAL=$( echo "1024 * $(fdisk -ul /dev/sda4 | sed -n ',^/dev/sda4 *[-09]* * [0-9]* *\([0-9]*\).*,\1,p')" | bc) SEEK=0 dd if=/dev/urandom of=/tmp/urandom.dat bs=$SIZE count=1 while [ $TOTAL -gt 0 ]; do echo "Seek=$SEEK Total=$TOTAL" dd if=/tmp/urandom.dat of=/dev/sda4 bs=$SIZE count=1 seek=$SEEK SEEK=$((SEEK + 1)) TOTAL=$((TOTAL - SIZE)) done rm /tmp/urandom.dat
Option 2a: Short Cut Script to Encrypt LVMs
Although not used in this scenario, at other times I've inverted the organisation of the disk so that the LVMs are created first and then individual logical volumes are encrypted rather than encrypting the entire raw disk partition. This is helpful when some volumes might be better off un-encrypted (shared access, software development/hacking, virtual machine disk images, etc.)
In these cases I create a 500MB random file in /tmp/urandom.dat
dd if=/dev/urandom of=/tmp/urandom.dat bs=500000000 count=1
and an accompanying script /tmp/encrypt.sh:
#!/bin/bash RANDOM_DATA=/tmp/urandom.dat SIZE=$(ls -l $RANDOM_DATA | cut -f5 -d\ ) SECTOR=512 if [ ! -z $1 ]; then let TOTAL=$(echo "$SECTOR * $(lvdisplay -c $1 | cut -f7 -d:)" | bc) echo "Writing $TOTAL bytes random data to $1 from $RANDOM_DATA (size=$SIZE)" SEEK=0 while [ $TOTAL -gt 0 ]; do echo "Seek=$SEEK Total=$TOTAL" dd if=$RANDOM_DATA of=$1 bs=$SIZE count=1 seek=$SEEK SEEK=$((SEEK + 1)) TOTAL=$((TOTAL - SIZE)) done fi
The script is called with the name of a logical volume and it calculates how large it is and then loops until the random data file has filled the volume:
/tmp/encrypt.sh /dev/data/home Writing 49996103680 bytes random data to /dev/data/home from /tmp/urandom.dat (size=500000000) Seek=0 Total=49996103680 1+0 records in 1+0 records out 500000000 bytes (500 MB) copied, 12.3475 s, 40.5 MB/s Seek=1 Total=49496103680 ...
Choosing a Key-File
The key-file is kept on an external USB memory stick. There are various ways to create and store the key-file. Many guides recommend generating a random key from /dev/random but in my opinion anyone that managed to get access to the memory stick could easily locate the key-file because of its totally random contents, unless many 'fake' keys were also on the memory stick.
My preferred method now is to use a real file. Install the Hardy Desktop Live image on the USB memory stick so it is bootable on any system. Because the installation has a persistent /home/ I can copy some music and image files onto it and use one of those as the key-file. The reason I choose music and images is that most MP3 and PNG or JPG files are highly compressed and their data can have a high degree of variability, and is hard to predict. An attacker would need to know the name of the key-file to determine which of the thousands of files was the key-file. To do that, they'd need access to the encrypted system itself.
For the purposes of this guide let us assume we're using a self-created music file called theme-song.mp3 (Being self-created no-one else will have the same file - in other words, don't use a commonly shared file).
Put the file on the USB memory stick and then plug it into the new system. Ensure it is mounted. In this example the USB key has two volumes on it (ubuntu & casper-rw) and the persistent files are in the casper-rw volume which usually is auto-mounted at /media/casper-rw (see Installing Ubuntu on USB pendrive using Linux.
Encrypting the Disk
Now encrypt the large sda4 partition that will eventually use LVM:
cryptsetup --hash sha512 --key-size 256 --cipher aes-cbc-essiv:sha256 \ luksFormat /dev/sda4 /media/casper-rw/home/tj/Media/theme-song.mp3 WARNING! ======== This will overwrite data on /dev/sda4 irrevocably. Are you sure (Type uppercase yes): YES Command successful
Open the encrypted device, giving it the name sda4encrypted:
cryptsetup --key-file /media/casper-rw/home/tj/Media/theme-song.mp3 luksOpen /dev/sda4 sda4encrypted key slot 0 unlocked. Command successful.
There will now be a new device:
ls -1 /dev/mapper control sda4encrypted
Configure Logical Volume Management (LVM)
First install the LVM package:
apt-get install lvm2
LVM Tools Confuse Megabytes with Mebibytes
The LVM tool reports can be confusing because they use the wrong size suffixes (such as MB and GB). The problem is, a gigabyte (GB) is 1,000MB, a megabyte (MB) is 1,000 kilobytes, and a kilobyte (KB) is 1,000 bytes. However, LVM uses binary-based calculations, not the decimal, with KB = 1,024, MB = 1,024KB, and GB = 1,024MB. LVM should use MiB and GiB suffixes to indicate binary-based measurements.
The result is, if you use fdisk to create (for example) a 3,256MB partition (3.256 x 1000 x 1000 x 1000 = 3256000000 bytes) on a physical device and then create an LVM physical volume with it, the reports from pvdisplay and vgdisplay will show the size as 3.04GB. (3.04 x 1024 x 1024 x 1024 = 3264175144.96). In fact, 3,256MB = 3.256GB = 3.032386303 GiB so the lvm tools have rounded-up to the next tenth.
It looks as if you've miscalculated or lost disk space somewhere, but in fact LVM tools are causing confusion.
Determine the Number and Size of Logical Extents in Logical Volumes
Logical volume size is defined as the number of logical extents (LE), the size of which is the same for all logical volumes in a volume group and is the same as the physical extent (PE) size. Use vgdisplay to find out:
vgdisplay VGraid5 --- Volume group --- VG Name VGraid5 System ID Format lvm2 Metadata Areas 1 Metadata Sequence No 4 VG Access read/write VG Status resizable MAX LV 0 Cur LV 3 Open LV 3 Max PV 0 Cur PV 1 Act PV 1 VG Size 163.39 GB PE Size 4.00 MB Total PE 41829 Alloc PE / Size 33040 / 129.06 GB Free PE / Size 8789 / 34.33 GB VG UUID V0kRhd-oFLa-hq21-9eCs-kAnm-e1BW-xK7GPT
The PE Size (physical extent size) for this volume group is 4.00MB. The Total PE (number of extents) is 43,794.
So, in fact, the PE Size is 4.00MiB (4.00 x 1024 x 1024 = 4,194,304 bytes), or 4.194304MB (4.194304 x 1000 x 1000 = 4,194,304 bytes).
To make later calculations easier set up some definitions:
export GB=1000000000 export MB=1000000 export GiB=1073741824 export MiB=1048576
Create LVM volumes
Create the physical volume and volume group:
pvcreate /dev/mapper/sda4encrypted Physical volume "/dev/mapper/sda4encrypted" successfully created vgcreate -v VGencrypted /dev/mapper/sda4encrypted Adding physical volume '/dev/mapper/sda4encrypted' to volume group 'VGencrypted' Creating directory "/etc/lvm/archive" Archiving volume group "VGencrypted" metadata (seqno 0). Creating directory "/etc/lvm/backup" Creating volume group backup "/etc/lvm/backup/VGencrypted" (seqno 1). Volume group "VGencrypted" successfully created
Create the logical volume 'root' using 15GB in the volume group 'VGencrypted':
export PES_BYTES=$(echo "$(vgdisplay VGencrypted | sed -n 's/.*PE Size *\([0-9\.]*\) .*/\1/p') * $MiB" | bc) EXTENTS=$(echo "15 * $GB / $PES_BYTES" | bc); echo $EXTENTS 3576 lvcreate -l $EXTENTS -n root VGencrypted Logical volume "root" created
Repeat for /var/ (5GB) and /home/ (75% of remaining free space):
EXTENTS=$(echo "5 * $GB / $PES_BYTES" | bc); echo $EXTENTS 1192 lvcreate -l $EXTENTS -n var VGencrypted Logical volume "var" created lvcreate -l 75%FREE -n home VGencrypted Logical volume "home" created
Using vgdisplay you can see this will leave ~34GB of free space. If or when one of the existing logical volumes reaches capacity simply use lvextend to allocate more extents from the volume group - no need to shuffle data or partitions around. I shall be using some of this space for the Ubuntu+1 testing file-system.
vgdisplay VGencrypted | grep 'Free PE' Free PE / Size 8718 / 34.05 GB
Check the devices are available:
ls -1 /dev/mapper control sda4encrypted VGencrypted-home VGencrypted-root VGencrypted-var
Write Windows image
To ensure when Ubuntu installs it writes a suitable GRUB menu that provides for booting to Windows, copy the Windows image from the back-up and into its target partition. This assumes the remote system is still mounted:
dd if=/mnt/remote/Backups/sda2-Vista.img of=/dev/sda2
Check the image consistency:
ntfsresize --info --no-action /dev/sda2 ntfsresize v2.0.0 (libntfs 10:0:0) Device name : /dev/sda2 NTFS volume version: 3.1 Cluster size : 4096 bytes Current volume size: 29428277760 bytes (29429 MB) Current device size: 29428285440 bytes (29429 MB) Checking filesystem consistency ... 100.00 percent completed Accounting clusters ... Space in use : 19489 MB (66.2%) Collecting resizing constraints ... You might resize at 19488083968 bytes or 19489 MB (freeing 9940 MB). Please make a test run using both the -n and -s options before real resizing!
No errors or warnings during the consistency scan so the system is ready for Ubuntu.
Now the system has all the devices ready for formatting with file-systems and Windows in place, so installation of the operating system can begin.
Run the Ubuntu installer by double-clicking the Install icon on the Live CD desktop. Select the language, time-zone and keyboard layout.
In the partitioner (Prepare disk space dialog) choose Manual, then press the Forward button.
After it has scanned the disks it will present a list of devices. As well as the physical devices (/dev/sda, /dev/sdb, etc.) there will be the logical devices just created with names beginning /dev/mapper/. The choice of device names should make it straight-forward to identify the intended purpose of each.
The device list will show all the devices in the system.
Select /dev/sda1. Press the Edit partition button. Change Use as to Ext3. Tick the Format check-box. Set the mount point to /boot.
Select /dev/sda3. Press the Edit partition button. Change Use as to swap area. .
Select /dev/mapper/VGencrypted-home. Press the New partition table button. Select the free space. Press the New partition button. Choose Primary partition, use all the space (accept the default value for partition size), location at Beginning. Use as Ext3. Set the mount point to /home.
Select /dev/mapper/VGencrypted-root. Press the New partition table button. Select the free space. Press the New partition button. Choose Primary partition, use all the space (accept the default value for partition size), location at Beginning. Use as Ext3. Set the mount point to / (root).
Select /dev/mapper/VGencrypted-var. Press the New partition table button. Select the free space. Press the New partition button. Choose Primary partition, use all the space (accept the default value for partition size), location at Beginning. Use as Ext3. Set the mount point to /var.
Review the list to ensure it is correct, then press the Forward button to commit the changes.
Continue the installation process, answering the Who are you? questions.
On the Ready to install page, review the choices.
Finally, when you're happy with all the choices, press the Install button and wait whilst the installer runs.
When it finishes DO NOT restart the system - some additional configuration is required before the system is restarted so it will boot successfully.
Now a series of additional steps is required to ensure the new system can successfully boot.
Mount the Target System
Prepare the installation for access using chroot:
mkdir /mnt/target mount /dev/mapper/VGencrypted-root /mnt/target mount /dev/mapper/VGencrypted-var /mnt/target/var mount /dev/mapper/VGencrypted-home /mnt/target/home mount /dev/sda1 /mnt/target/boot mount -o bind /proc /mnt/target/proc mount -o bind /dev /mnt/target/dev
Install cryptsetup and lvm2
The installer didn't install the packages needed for the system to understand the disk configuration, so install them manually:
chroot /mnt/target /bin/bash -c "apt-get install cryptsetup dmsetup lvm2"
Encrypted Disk Configuration
Write the configuration of /dev/mapper/sda4encrypted so the system knows how to open it. It will use a shell script that is executed early in the boot process from the initrd image:
echo "sda4encrypted /dev/disk/by-uuid/$(vol_id --uuid /dev/sda4) /home/tj/Media/theme-song.mp3 luks,keyscript=/usr/local/sbin/crypto-usb-key.sh" >> /mnt/target/etc/crypttab
There are several suitable shell scripts already existing. I chose to modify one written by Wejn and Rodolfo Garcia published at How to setup passwordless disk encryption in Debian Etch. It is attached to my article on encrypted RAID-5 LVM ready for downloading.
My modifications enable the script to report progress via usplash or console, detect USB block devices, scan all partitions on the device (the original script only checked the first partition), auto-detect and load the file-system type driver, and output more informative messages.
Copy it into the new system (ensure the path and name match that specified in /mnt/target/etc/crypttab):
wget http://tjworld.net/raw-attachment/wiki/Linux/Ubuntu/HardyRAID5EncryptedLVM/crypto-usb-key.sh \ -O /mnt/target/usr/local/sbin/crypto-usb-key.sh chroot /mnt/target /bin/bash -c "chmod a+x /usr/local/sbin/crypto-usb-key.sh"
Update Initial RAM Disk (initrd)
chroot /mnt/target /bin/bash -c "update-initramfs -u all" update-initramfs: Generating /boot/initrd.img-2.6.24-19-generic
Restart System and Test
With everything written to the disks it is time to restart:
shutdown -r now
Remove the installation CD from the drive when prompted.
When the system starts ensure the BIOS isn't configured to try booting from a USB device before the hard disk.
Insert the stick into a USB port and let the system start.
If using usplash you should see a message similar to "Success loading key-file from sdb1 (casper-rw)" early in the boot process when crypto-usb-key.sh locates the key-file. If it fails you'll see "FAILED to find suitable USB key-file ..." followed by "Try to enter the LUKS password:". At this point, if the device has a pass-phrase as well as a key-file you can type it instead of using the key-file.
If that fails you'll need to enable debugging within the script by changing:
To do this the initial RAM disk image needs updating. That means the encrypted volume must be opened and mounted and the chroot environment recreated from the Live CD.
Because that involves a lot of steps I put all the commands into a script. The script is attached to this article as update-liveCD-encryptedLVM.sh. It will install the packages, configure and unlock the devices, recreate the chroot environment, download and install the latest version of crypto-usb-key.sh, then update the initial RAM disk image.
Restart the system using the Live CD and open a terminal, then:
sudo su wget http://tjworld.net/raw-attachment/wiki/Linux/Ubuntu/HardyEncryptedLVM/update-liveCD-encryptedLVM.sh chmod a+x update-liveCD-encryptedLVM.sh
The script requires the key-file name be assigned to the environmental variable KEYFILE:
Now make the changes and update the initial RAM disk image:
sed -i 's/^\(DEBUG=\)$FALSE/\1$TRUE/' /mnt/target/usr/local/sbin/update-usb-key.sh update-initramfs -u all
You might also want to remove the "splash" option from the kernel command-line in the GRUB configuration (either in the file /boot/grub/menu.lst or by pressing Escape when GRUB is starting after a reboot to edit the menu directly). This will ensure that the large number of debug messages from the script are easily readable on the console, rather than scrolling up too fast in usplash.
Now the system can be restarted and hopefully the messages will help identify the cause of the problem, and suggest a solution.
Once the problem is fixed don't forget to change the debug setting back to $FALSE and update the initial RAM disk image.
Now the system is running Hardy there are a series of tasks required to return it to the same working state it had previously.
- Install the latest software updates
- Install any proprietary drivers (Nvidia graphics, Wireless network, etc.)
- Install required packages based on the list of installed packages from the previous installation (now on the remote back-up)
- Install latest software updates (to the additional packages)
- Copy /home back from the remote back-up
- Copy data back from the external USB2 disk
The easy way to get the list of installed packages from the back-up (if it wasn't creating before Gutsy was removed) is:
mkdir /mnt/remote sshfs email@example.com: /mnt/remote chroot /mnt/remote/Backups/rootfs /bin/bash -c "dpkg-query -l | grep '^.[hi].*'" >installed-packages.txt
Now the list is in the local file installed-packages.txt.
Installing Ubuntu on USB pendrive using Linux
Ubuntu hard drive encryption with external key
Installing Ubuntu 7.04 on an Encrypted LVM Partition For Root, Swap, and Home
How to setup passwordless disk encryption in Debian Etch
Encrypted Storage with LUKS, RAID and LVM2