Linux Encrypted Filesystems

In the age of mobile devices that contain private information, whether it’s personal or business information, encrypting your devices is a good idea. Filesystem encryption allows you to encrypt a single partition or even an entire hard drive. When configuring correctly, this will help mitigate privacy issues from stolen devices.

One of the solutions for encrypting a file system in Linux is to use LUKS. LUKS stands for “Linux Unified Key Setup”.

I created a logical volume to use as a test bed for the encrypted file system:

[root@sgnhv ~]# lvs
  LV         VG       Attr     LSize   Pool Origin Data%  Move Log Copy%  Convert
  lv_data    vg_sgnhv -wi-ao-- 500.00g                                                                                      
  lv_root    vg_sgnhv -wi-ao--  50.00g                                           
  lv_swap    vg_sgnhv -wi-ao--   5.88g                                           

[root@sgnhv ~]# lvcreate -n lv_crypto -L 1G vg_sgnhv
  Logical volume "lv_crypto" created

[root@sgnhv ~]# lvs
  LV         VG       Attr     LSize   Pool Origin Data%  Move Log Copy%  Convert
  lv_crypto  vg_sgnhv -wi-a---   1.00g                                           
  lv_data    vg_sgnhv -wi-ao-- 500.00g                                                                                      
  lv_root    vg_sgnhv -wi-ao--  50.00g                                           
  lv_swap    vg_sgnhv -wi-ao--   5.88g

As you can see, I have a new 1 GB logical volume called lv_crypto. Now it’s time to get into the nitty gritty of setting up LUKS. The first thing that we need to do is encrypt the lv_crypto volume with the luksFormat extension.

[root@sgnhv ~]# cryptsetup luksFormat /dev/vg_sgnhv/lv_crypto

WARNING!
========
This will overwrite data on /dev/vg_sgnhv/lv_crypto irrevocably.

Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase: 
Verify passphrase:

Now that we have the lv_crypto logical volume encrypted, we need to use the luksOpen extension to create a device mapper to crypt_dev_mapper. The device mapper acts as an interface between dm-crypt and the device. From there, we can create the file system and mount it.

[root@sgnhv ~]# ls /dev/mapper/
control             vg_sgnhv-lv_data  vg_sgnhv-lv_libvirt  vg_sgnhv-lv_swap
vg_sgnhv-lv_crypto  vg_sgnhv-lv_home  vg_sgnhv-lv_root

[root@sgnhv ~]# cryptsetup luksOpen /dev/vg_sgnhv/lv_crypto crypt_dev_mapper
Enter passphrase for /dev/vg_sgnhv/lv_crypto:

As you can see, there is now a device mapper called crypt_dev_mapper, which is the device mapper that dm-crypt created to interact with the data in the encrypted volume. There is also vg_sgnhv-lv_crypto, which is the encrypted logical volume. From here on out, we’ll be interacting with crypt_dev_mapper. If you create your file system directly on the lv_crypto logical volume, you will over-write the encryption, rendering it a normal everyday logical volume.

[root@sgnhv ~]# ls /dev/mapper/
control           vg_sgnhv-lv_crypto  vg_sgnhv-lv_home     vg_sgnhv-lv_root
crypt_dev_mapper  vg_sgnhv-lv_data    vg_sgnhv-lv_libvirt  vg_sgnhv-lv_swap

As mentioned, we’ll create the file system on the dm-crypt created device mapper. In this case, I’m using the ext4 file system.

[root@sgnhv ~]# mkfs -t ext4 /dev/mapper/crypt_dev_mapper 
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
65408 inodes, 261632 blocks
13081 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=268435456
8 block groups
32768 blocks per group, 32768 fragments per group
8176 inodes per group
Superblock backups stored on blocks: 
 32768, 98304, 163840, 229376

Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 26 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

By issuing the blkid command, you can see that the lv_crypto logical volume is labeled a a crytpo_LUKS file system type and the crypt_dev_mapper is labeled as a ext4 file system type.

[root@sgnhv ~]# blkid | grep crypt
/dev/mapper/vg_sgnhv-lv_crypto: UUID="993b91fd-e3f2-4764-9453-3e6bf64c44b9" TYPE="crypto_LUKS" 
/dev/mapper/crypt_dev_mapper: UUID="4b034d56-2216-43af-86ac-98b9abb0a3fe" TYPE="ext4" 

Once the filesystem has been created, you can now mount the drive and start writing data to it, as seen below.

root@sgnhv ~]# mount /dev/mapper/crypt_dev_mapper /mnt/

[root@sgnhv ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/vg_sgnhv-lv_root
                       50G  7.5G   40G  16% /
tmpfs                 1.9G  388K  1.9G   1% /dev/shm
/dev/md127p1          485M  128M  332M  28% /boot
/dev/mapper/vg_sgnhv-lv_data
                      493G  103G  365G  22% /data
/dev/mapper/crypt_dev_mapper
                     1006M   18M  938M   2% /mnt

[root@sgnhv ~]# dd if=/dev/urandom of=/mnt/somedata bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 1.23517 s, 8.5 MB/s

[root@sgnhv ~]# ls /mnt/
lost+found  somedata

[root@sgnhv ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/vg_sgnhv-lv_root
                       50G  7.5G   40G  16% /
tmpfs                 1.9G  388K  1.9G   1% /dev/shm
/dev/md127p1          485M  128M  332M  28% /boot
/dev/mapper/vg_sgnhv-lv_data
                      493G  103G  365G  22% /data
/dev/mapper/crypt_dev_mapper
                     1006M   28M  928M   3% /mnt
[root@sgnhv ~]# umount /mnt/

Once you’ve accessed the data that you needed, you can umount and close the dm-crypt device mapper, which will remove the crypt_dev_mapper device. The luksClose extension closes the interface with the device mapper.

[root@sgnhv ~]# cryptsetup luksClose crypt_dev_mapper

Now accessing the encrypted device using the luksOpen and luksClose extension is fine. In fact, a simple bash or perl script could be written to help facilitate the process. Every time you use the luksOpen extension, LUKS will ask you for the passphrase that you used initially set up.

However, if you want your system to initialize the encrypted file system and even mount it at boot, you will need to follow a few extra steps.

The first option is simply adding the dm-crypt device mapper name and the logical volume path to the /etc/crypttab file. This will create the dm-crypt mapper on boot. This will also require that you be present at the console when the computer boots up, as the computer will ask you for the LUKS passphrase before it maps the dm-crypt mapper. If you’re not available at the console, then the boot will hang until you enter the passphrase.

[root@sgnhv ~]# vim /etc/crypttab 
[root@sgnhv ~]# cat /etc/crypttab 
crypt_dev_mapper /dev/vg_sgnhv/lv_crypto

There is however, an option of using a key file. To make a key file, you must create a file with some random data. Then you can use the luksAddKey extension to create the key.

[root@sgnhv ~]# dd if=/dev/urandom of=/etc/crypt_dev_mapper.key bs=1k count=4
[root@sgnhv ~]# cryptsetup luksAddKey /dev/vg_sgnhv/lv_crypto /etc/crypt_dev_mapper.key 
Enter any passphrase: 

Once the key has been created, you can add the key path in the /etc/crypttab file in the third column. In the crypttab man page, it states the third column is for adding a password. This is incorrect and it will not work if you enter the passphrase there.

Also, be sure to make the key file only readable to root, otherwise when when init_crypt function initializes and looks at the permissions of the file, it will give you a warning about it being insecure. In some instances, it will refuse to read the file, thus failing to mount the encrypted file system.

[root@sgnhv ~]# vim /etc/crypttab 
[root@sgnhv ~]# cat /etc/crypttab 
crypt_dev_mapper /dev/vg_sgnhv/lv_crypto /etc/crypt_dev_mapper.key
[root@sgnhv ~]# chmod 400 /etc/crypt_dev_mapper.key 

Once that is setup, you can modify your /etc/fstab to have the file system mounted at boot.

[root@sgnhv ~]# vim /etc/fstab 
[root@sgnhv ~]# tail -1 /etc/fstab 
/dev/mapper/crypt_dev_mapper /crypt  ext4 defaults 1 0

You can test the functionality out, without rebooting by doing the following:

[root@sgnhv ~]# cryptsetup luksClose /dev/mapper/crypt_dev_mapper 
[root@sgnhv ~]# bash
[root@sgnhv ~]# . /etc/init.d/functions 
[root@sgnhv ~]# init_crypto 1
[root@sgnhv ~]# mount -a                                   [  OK  ]
[root@sgnhv ~]# df -h | grep crypt
/dev/mapper/crypt_dev_mapper
                     1006M   18M  938M   2% /crypt

As you can see, the encrypted file system was mounted without asking for a passphrase. This configuration will be persistent across reboots.

Now for a public service announcement. It’s actually more food for thought. If you are having your computer mount your encrypted file system on boot without any kind of interaction to authenticate the process, what good does it do to encrypt the file system in the first place?

For my personal preference, encrypting a notebooks entire filesystem or even a tablet or smart phone should be the course of action. In Linux, that can be done during the install. Otherwise, I’d propose something like TruCrypt. Other than that, encrypting thumb drives would be handy.