Encrypting removable media in Linux using dm-crypt and LUKS

The dm-crypt tool is as an encryption layer for the device-mapper used by all major Linux distributions to encrypt storage volumes. I’m going to describe here how to use it for encryption of e.g. USB-sticks or any other removable media used quite often to transfer or backup data.

LUKS

LUKS (Linux Unified Key Setup) does not provide any encryption. It’s a tool creating and managing a partition header containing all information required by encryption/decryption tools. A big advantage of using LUKS is a fact that it does not use directly the passphrase provided by user to encrypt the whole partition. The user’s passphrase is used to encrypt a master key, so we can easily add another passphrase for a different user (up to 8 at the same time) or remove a possibly compromised one.

Prerequisites

Before starting we should ensure that the following Linux kernel options are set in case we compile our own kernel. I would say that all major distributions are shipped with a kernel configuration containing all required options. So normally no action is required here unless you know what I’m talking about (Lächeln)

Device Drivers  --->
  Block devices  --->
    <*> Loopback device support
    Multiple devices driver support (RAID and LVM)  --->
      <*>   Device mapper support
      <*>     Crypt target support
Cryptographic options  --->
  <*>   LRW support (EXPERIMENTAL)
  <*>   XTS support (EXPERIMENTAL)
  <*>   SHA224 and SHA256 digest algorithm
  <*>   AES cipher algorithms (i586)
                     or ( depends on your platform )
  <*>   AES cipher algorithms (x86_64)

We will also need the cryptosetup with LUKS support installed. Again for example on Fedora everything is included in the pre-installed kernel modules. But if we need to install it ourselves, then here are some install commands for two Linux distributions.
on Gentoo

emerge cryptsetup

on Fedora

yum install cryptsetup-luks

or we use another way to install packages according to the distribution.

Preparing a volume

Before any encryption starts it’s recommended to check the disk for bad blocks and also overwrite the disk with random data. This operation can take a very long time as generating random numbers is a very CPU intensive operation. In case when the disk is represented by the id usb-_USB_DISK_2.0_073A172504C1-0:0 in the /dev/disk/by-id directory, use the following

badblocks -c 10240 -s -w -t random -v /dev/disk/by-id/usb-_USB_DISK_2.0_073A172504C1-0\:0

Warning

This operation erases all data on target drive so please double check if the device name is really the one you want to erase and encrypt.

Note

Using a symlink located in the /dev/disk/by-id/ is safer than addressing directly the device in a directory /dev/, because a device name can be changed when a new disk is plugged in. For example the ID of my USB disk is already mentioned usb-_USB_DISK_2.0_073A172504C1-0:0.

To create an encrypted LUKS partition on the device e.g. /dev/sdc use one of the following commands.

For kernel 2.6.24 or newer use the most secure XTS mode

cryptsetup --cipher aes-xts-plain --verify-passphrase --key-size 512 --verbose luksFormat /dev/sdc

For kernel 2.6.20 or newer use the LRW mode

cryptsetup --cipher aes-lrw-benbi --verify-passphrase --key-size 384 --verbose luksFormat /dev/sdc

If a volume is going to be used on a very old Linux distribution or you don’t want to use the modes LRW or XTS currently (ver. 2.6.31) marked as EXPERIMENTAL (means not really properly tested), then use the less secure CBC mode

cryptsetup --cipher aes-cbc-essiv:sha256 --verify-passphrase --key-size 256 --verbose luksFormat /dev/sdc

We’ll be asked to confirm the operation by typing uppercase ‘yes’ and entering a LUKS passphrase used to encrypt a master encryption key. The entered passphrase is important, it will be requested always when the volume is mounted to a file system.

In the next step we set a device mapping in order to use our encrypted partition. We create a virtual device which can be mounted. Everything written into this virtual device will be transparently encrypted before writing into the physical device and everything will be decrypted before being read.

cryptsetup luksOpen /dev/disk/by-id/usb-_USB_DISK_2.0_073A172504C1-0\:0 crypt-usbdisk

where crypt-usbdisk is a name of a block device created in a directory /dev/mapper. We can choose any valid file name.

Now the encrypted volume is mapped and we can use it as any block device. So let’s create the ext3 file system by

mkfs.ext3 /dev/mapper/crypt-usbdisk

Mounting the encrypted volume works as for any other disk for example mount into a directory /mnt/usbstorage (directory must exist) can be done by

mount -o rw /dev/mapper/crypt-usbdisk /mnt/usbstorage

And that’s it. The volume in /mnt/usbstorage can be used as any other storage and anybody without knowledge of a passphrase wouldn’t be able to read our data. (well, most likely, read more about AES)

Before disconnecting the volume must be properly closed in order to flush the write cache and other operations. So to umount and close the LUKS volume

umount /mnt/usbstorage
cryptsetup luksClose crypt-usbdisk

now the USB disk can be safely physically unplugged.

Encrypted and unencrypted data together on the USB disk

We may also need to use our USB disk with other operating systems to store unprotected data as usual, but also have the possibility to protect a sensitive data when working on systems supporting dm-crypt. What we can do is creating a regular file which will be visible by all systems. And within the file we will create our encrypted file system accessible only after providing a passphrase on a system with an installed dm-crypt. So for example you can use your disk on a Mac Book and store your documents there, but you won’t be able (without additional effort) to access the encrypted part. And the same disk can be afterwards plugged into your Linux desktop and we can write or read data protected against unauthorized access.

For now we expect that a USB disk is mounted at /mnt/usbstorage

Note

The file can be created on any data storage within a regular file. The USB disk is just an example of creating of a portable encrypted data container.

Create a file of the required size on the USB disk e.g. in the directory /mnt/usbstorage/crypt

dd if=/dev/urandom of=dmcrypt-storage bs=1024 count=50000

This command creates a 50MB file named dmcrypt-storage filled with random data.

Now we associate a loop device with the created regular file. First we check the name of first unused loop device

losetup -f

In my case was the output /dev/loop/0 so let’s attach the file

losetup /dev/loop/0 /mnt/usbstorage/crypt/dmcrypt-storage

The following steps are the same as in the previous case. We need to initialize a LUKS partition using a loop device, open it and create a file system on it.

cryptsetup --cipher aes-xts-plain --verify-passphrase --key-size 512 --verbose luksFormat /dev/loop/0
cryptsetup luksOpen /dev/loop/0 my-encrypted-volume
mkfs.ext3 /dev/mapper/my-encrypted-volume

Now a new volume can be mounted for example at a directory /mnt/encrypted-disk (the directory must exist)

mount -o rw /dev/mapper/my-encrypted-volume /mnt/encrypted-disk

so we can use the new directory as any other. Everything stored in /mnt/encrypted-disk will be transparently encrypted and persisted on the usb disk in the file dmcrypt-storage. The whole USB disk can be used on any operating system as usual without any restriction, but 50MB of it are reserved for an encrypted file system.

To safely close the encrypted file execute following commands

umount /mnt/encrypted-disk
cryptsetup luksClose my-encrypted-volume
losetup -d /dev/loop/0

Bash scripts to automate connecting and disconnecting encrypted volumes

As you can see connecting and disconnecting of the encrypted volume contains several steps. Hence we create a script checking some prerequisites and mounting an encrypted file system within a file on an USB disk. The scripts would need to be adjusted as the file and directory names change according to your situation. The scripts need to be executed with root privileges.

mount-encr-disk.sh
#!/bin/bash
export USB_DISK_ID='usb-_USB_DISK_2.0_073A172504C1-0:0'
export DISK_MOUNT_POINT='/mnt/usb'
export ENCR_DISK_MOUNT_POINT='/mnt/encrypted-disk'
export ENCR_CONTAINER='/mnt/usb/crypt/dmcrypt-storage'
if [ -n "`mount | grep ${ENCR_DISK_MOUNT_POINT}`" ]; then
  echo "A mount point ${ENCR_DISK_MOUNT_POINT} is busy. An encrypted filesystem is probably already mounted."
  exit
fi
if [ -h /dev/disk/by-id/${USB_DISK_ID} ]; then
  echo "Disk is plugged in, mounting to ${DISK_MOUNT_POINT} ..."
  mount /dev/disk/by-id/${USB_DISK_ID} ${DISK_MOUNT_POINT}
  if [ -f ${ENCR_CONTAINER} ]; then
    LOOP_DEV=`losetup -f`
    echo "Assigning an encrypted file ${ENCR_CONTAINER} to ${LOOP_DEV} ..."
    losetup ${LOOP_DEV} ${ENCR_CONTAINER}
    echo "Opening an encrypted volume ..."
    cryptsetup luksOpen ${LOOP_DEV} my-usb-disk
    mount -o rw,defaults /dev/mapper/my-usb-disk ${ENCR_DISK_MOUNT_POINT}
    echo "Encrypted volume is mounted to ${ENCR_DISK_MOUNT_POINT}"
  else
    echo "The container with encrypted filesystem was not found in ${ENCR_CONTAINER}"
  fi
else
  echo "Expected USB disk is pobably not plugged in"
fi

And the script closing the encrypted volume and umounting the partitions

umount-encr-disk.sh
#!/bin/bash
export DISK_MOUNT_POINT='/mnt/usb'
export ENCR_DISK_MOUNT_POINT='/mnt/encrypted-disk'
export ENCR_CONTAINER='/mnt/usb/crypt/dmcrypt-storage'
if [ -z "`mount | grep ${ENCR_DISK_MOUNT_POINT}`" ]; then
  echo "A mount point ${ENCR_DISK_MOUNT_POINT} does not exist in mtab. Disk is not mounted."
  exit
fi
umount ${ENCR_DISK_MOUNT_POINT}
cryptsetup luksClose my-usb-disk
LOOP_DEV=`losetup -j ${ENCR_CONTAINER} | awk -F':' '{ print $1 }'`
echo "Unassigning the ${LOOP_DEV} ..."
losetup -d ${LOOP_DEV}
echo "Umounting ${DISK_MOUNT_POINT} ..."
umount ${DISK_MOUNT_POINT}

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*

18 − four =