Encrypting an external device with LUKS
I, like many other folks out there, use a small USB drive to store personal documents and other files. It works as a useful backup in case my system fails or gets stolen. However, since I am always traveling this has always made me nervous, because it is too easy to lose a drive the size of a coin.
As I only ever plug it into a Linux machine (I already keep it formatted as ext4 ), it seems sensible to encrypt it with LUKS. Also, it is annoying to write a new password all the time, so — since my threat model considers my laptop to be safe and only accessible by me — let’s also setup the device to auto decrypt whenever plugged on it.
Important: Throughout this post, we will use the dummy /dev/sdX to refer to the device descriptor. Make sure to check right name for your setup. Also, guarantee that the device is unmounted, specially if you use an automount daemon like udiskie.
Wipe It Out
First of all let’s substitute everything This step is optional, but useful if you are already storing something in the device.
Make sure the device is unmount and let’s shred it.
sudo shred -v -n 1 /dev/sdX
You can also use dd to write from /dev/urandom if you prefer. Check the Arch Wiki for possible methods of wiping a disk.
Encrypt Drive
If you didn’t follow the previous step, do keep in mind that this one is not optional and it will delete everything in the drive. Backup accordingly.
We are using the Linux kernel’s support for full-disk encryption via dm-crypt . We users interact with it using the cryptsetup command. Let’s use it to format the whole drive using LUKS2 headers .
sudo cryptsetup luksFormat /dev/sdX --type luks2 --label drive
You will be prompted for a password when running this command. For now, this is the only way to access the data in this device. Make sure to remember it. Also, the label drive can be anything you want.
Now let’s open the drive and assign a name to it.
sudo cryptsetup open --type luks2 /dev/sdX drive-name
It will prompt you for the password and map the decrypted device to /dev/mapper/drive-name .
I am going to format it with as ext4 because it is fast, stable, and the encryption scheme already only works on Linux. But VFAT or almost any other should work well enough.
sudo mkfs.ext4 /dev/mapper/drive-name
Now your drive is ready to use! You can close and remove it if you want.
sudo cryptsetup close drive-name
Whenever you want to use it, you will have to first “open” the drive (decrypt) and only then mount its partition. Notice that the mapped name can be anything you want.
sudo cryptsetup open --type luks2 /dev/sdX usb sudo mkdir -p /media/usb sudo mount /dev/mapper/usb /media/usb
Auto-Opening and Mounting
This whole opening and closing, mounting and unmounting dance can get tiresome pretty quickly. If you trust a machine, you can let it decrypt your USB drive automatically.
Keyfile
Till now, our device only opens with a password. Let’s allow it to also be opened using a keyfile. This can be any file you want: random bytes, a giant riddle written in a txt, your dog’s picture, etc. For the sake of simplicity and entropy, we are going with 4kB of randomness. For good measure, also only allow your user to see and edit the file.
dd if=/dev/urandom of=/path/to/keyfile bs=1024 count=4 chown "$USER":"$USER" /path/to/keyfile chmod 600 /path/to/keyfile
Remember that /path/to/keyfile must be somewhere safe, or it defeats the whole purpose. If you have an encrypted home folder, you can keep it as a dotfile in there, for example.
Allow the keyfile to open your device.
sudo cryptsetup luksAddKey /dev/sdX /path/to/keyfile
You can verify that it worked by checking that there are two keyslots in the output of (one for the password, and another for the keyfile)
sudo cryptsetup luksDump /dev/sdX
Now you can open without a password!
sudo cryptsetup open --type luks2 --key-file /path/to/keyfile /dev/sdb usb
Automount with udiskie
If you have an automount setup, it is necessary to instruct it on where to find the keyfile.
I will show it for udiskie because that is what I use and because I don’t want to mount the drive at boot, but at user level I imagine it is similar for any other setup though.
Start by checking the device’s UUID,
lsblk -ndo UUID /dev/sdX
And proceed to create or edit $HOME/.config/udiskie/config.yml to link this UUID to the keyfile. You must write a section like this:
device_config: - id_uuid: <DEVICE UUID> keyfile: /path/to/keyfile
Keep in mind that the keyfile must be readable by the user running udiskie .
Conclusion
After spending some time searching for encryption solutions, I ended up with this one, which leaves most of the magic to the Linux kernel itself.
Below is a small proof-of-concept script automating the whole process. Make sure to edit it when adapting to your workflow.
See full script #!/bin/sh # Use this script by passing the device name # and an optional keyfile name. # usb-encrypt "/dev/sdX" "/path/to/keyfile" DEVICE=$1 KEYFILE=$2 NAME=$(uuidgen) # Wipe the drive sudo shred -v -n 1 "$DEVICE" # Encrypt and format sudo cryptsetup luksFormat --type luks2 --label drive "$DEVICE" sudo cryptsetup open --type luks2 "$DEVICE" "$NAME" sudo mkfs.ext4 "/dev/mapper/$NAME" # Create and assign keyfile if [ -n "$KEYFILE" ] ; then dd if=/dev/urandom of="$KEYFILE" bs=1024 count=4 sudo cryptsetup luksAddKey "$DEVICE" "$KEYFILE" chown "$USER":"$USER" "$KEYFILE" chmod 600 "$KEYFILE" # Configure udiskie if the executable exists if command -v udiskie >/dev/null 2>&1 ; then UUID="$(lsblk -dno UUID "$DEVICE")" cat >> "${XDG_CONFIG_HOME:-$HOME/.config}/udiskie/config.yml" <<EOF device_config: - id_uuid: $UUID keyfile: $KEYFILE EOF fi fi sudo cryptsetup close "$NAME"
References