barrass.dev

Storing Files in Encrypted Disk Images

Posted Tuesday 09 April 2019 at 18:05

Estimated reading time: 8 mins

Everyone has data they want to protect from prying eyes. Some hide it in a folder labelled “PRIVATE DO NOT OPEN”, followed by a maze of folders labelled “SERIOUSLY STOP OPENING THESE”, but of course there are better ways of protecting your data. Recently I was thinking about ways large collections of files could be encrypted. Of course, one could just use e.g. gpg to encrypt the files individually, but this will not encrypt any metadata, like filenames or the directory structure. Something like an encrypted partition will hide this information, and can be locked and unlocked to gain access to the files inside. An encrypted partition is easy to make when setting up a new computer or drive, but things become more problematic when the system is already configured, with files already in place and no space left for a new partition. The solution I came up with is to use image files. These image files essentially act as a virtual hard disk on which we can place an encrypted partition. This article is a guide on how to create an encrypted partition inside such an image file, and how to then use it as an encrypted “locker” for storing data.

Required Software

There are a few requirements to install, for which I will provide the apt commands needed to install them on Ubuntu. If you’re using a different distro, you’ll need to find these packages yourself.

We will also be using udisks to mount the image without root. All that’s needed to install on Ubuntu is cryptsetup; everything else should be available as standard.

sudo apt install cryptsetup

Making the Image

In order to create the image, you need root access. This is required for the formatting stage of creating the image. I am not currently aware of any way to get around this, however root access is not required in order to mount your image.

For the purposes of this article, I’m going to be creating a 50MB image file called “encrypted.img”, containing an encrypted ext4 partition.

The blank image file will be made using dd. To do this, we use the following command:

dd if=/dev/zero of=<filename> bs=1M count=<size in MB> status=progress

So to create my example, I would do

dd if=/dev/zero of=encrypted.img bs=1M count=50 status=progress

Before we can do anything more with it, we need to create a partition table and partition in the image. This can be accomplished with fdisk. Execute:

fdisk <filename>

(be aware, TAB autocompletion may not work for this – fdisk isn’t generally used for managing image files. Make sure to type the image file name in full and it will work just fine)

From here, we want to double check the properties of the image with the p command:

Command (m for help): p
Disk encrypted.img: 50 MiB, 52428800 bytes, 102400 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x1a2a9193

Now we can make a new partition with n [RET] p [RET] 1 [RET] [RET] [RET]. This will make a new Linux-format partition that fills the drive. If we re-run the p command, this partition should now be visible.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-102399, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-102399, default 102399): 

Created a new partition 1 of type 'Linux' and of size 49 MiB.

Command (m for help): p
Disk encrypted.img: 50 MiB, 52428800 bytes, 102400 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x1a2a9193

Device         Boot Start    End Sectors Size Id Type
encrypted.img1       2048 102399  100352  49M 83 Linux

Finally, write the changes by executing w.

This disk is now mountable, which will allow us to format it as an encrypted partition. We will mount it using udisksctl, by executing:

udisksctl loop-setup -f <filename>

Make note of which loopback device the image gets mounted on – in my case, this was /dev/loop0.

With the image mounted as a loopback device, we can now use it as though it were a real drive with real partitions. This is how we will format the partition as an encrypted partition. We will use cryptsetup to provide LUKS encryption for our partition.

First of all, the blank partition on the drive must be formatted. This action requires root, so make sure to check and double check which partition you’re formatting. Check twice, write once.

First off, format the partition with a LUKS header with the following command:

sudo cryptsetup luksFormat /dev/loop0p1

Replace /dev/loop0 with your loopback device. When prompted, enter “YES” in uppercase and the secure passphrase you wish to use to decrypt your partition. With any luck, the command will exit without error and you will have a successfully encrypted partition! This partition will, however, lack any kind of filesystem, so you won’t yet be able to store any data on it. First, you have to open the partition:

sudo cryptsetup luksOpen /dev/loop0p1 encrypted-partition

Enter your passphrase when prompted. This will open your encrypted partition and map it to /dev/mapper/encrypted-partition, which will now behave just like any other unencrypted partition. This can then be formatted. To format as ext4, use:

sudo mkfs.ext4 /dev/mapper/encrypted

Now we can mount the drive (either with sudo mount or udisksctl mount -b):

udisksctl mount -b /dev/mapper/encrypted-partition

or…

sudo mount /dev/mapper/encrypted <mount point>

Now we can do whatever we need here, before unmounting the partition and finally re-locking it:

udisksctl unmount -b /dev/mapper/encrypted-partition
sudo cryptsetup luksClose encrypted-partition
udisksctl loop-delete -b /dev/loop0

That’s it! The partition has been successfully created, formatted, opened and closed.

Mounting and Unmounting

Of course, you’re not going to want to have to go through all of that to manually mount, open, mount and then unmount, close, unmount every time you want to access your partition, and it would be much more convenient if the partition could be accessed without needing root access. Well, udisksctl actually includes commands to unlock (open) and lock (close) your encrypted partitions from user-space, as well as the facilities needed to make loopback devices and mount partitions. Therefore I’ve created two bash functions below that you can include in your ~/.bashrc or ~/.bash_aliases that will automate the procedure.

mount_encrypted_image() {
    if [ "$1" = "" ];
    then
	echo "First argument must be file!"
	return 0
    fi

    filename="$1"
    LOOP="$(udisksctl loop-setup -f $filename | awk 'NF>1{ print substr($NF, 1, length($NF)-1) }')"
    echo "${LOOP}p1"
    unlocked="$(udisksctl unlock -b ${LOOP}p1 | awk 'NF>1{ print substr($NF, 1, length($NF)-1) }')"
    udisksctl mount -b $unlocked
    echo $unlocked > "/tmp/${filename}.device"
}

umount_encrypted_image() {
    if [ "$1" = "" ];
    then
	echo "First argument must be file!"
	return 0
    fi

    filename="$1"
    loop="$(losetup | awk 'FNR>=2{ print $1,$6 }' | grep $filename | awk 'FNR==1{ print $1 }')"
    unlocked="$(cat /tmp/${filename}.device)"
    udisksctl unmount -b "$unlocked" || true
    rm "/tmp/${filename}.device"
    udisksctl lock -b "${loop}p1"
    udisksctl loop-delete -b "$loop"
}

These two functions will set up the loopback devices and mount your partition for you, and then take it down when you need, just from the filename of your image file. To mount your encrypted file, simply run mount_encrypted_image <filename> and enter your passphrase when prompted. The partition will be mounted and should become available through your favourite file manager. You can do everything you need and then close up the partition with umount_encrypted_image <filename>.

The partition should be safely unmounted and closed on system shutdown but if it’s important, make sure to do it manually before you shutdown. I personally have had no problems shutting down with the partition still mounted, but your mileage may vary.


Hopefully this guide has been helpful to you. If everything has gone correctly, you should now have an encrypted disk image that you can use like a “locker” for any sensitive data you wish to keep encrypted, as an alternative to something like encfs. That said, I can’t make any guarantees about the safety of this method. Instead, think of this more as one step in the chain, and put other cryptographic safeguards between your data and anyone who wishes to snoop on it. Thanks for reading!