Storing Files in Encrypted Disk Images
Posted Tuesday 09 April 2019 at 18:05
Estimated reading time: 11 mins
Everyone has data they want to protect from prying eyes, from a digital diary to more nefarious material. Some hide it in a folder labelled "PRIVATE DO NOT OPEN", followed by a maze of "SERIOUSLY STOP OPENING THESE", but of course there are better ways of protecting your data. Recently I was thinking about ways files could be encrypted. I have an interest in cryptography, so I wanted to see what I could do with this to successfully encrypt some files.
My first thought was of encrypted partitions. I could make one on my hard drive quite easily, but anyone with just a little bit of computer skill could easily find such a partition, and would know I had something to hide. The solution I came up with is to use image files.
For those unaware, the image files essentially act as a virtual hard disk. This can contain partitions which can be mounted, formatted, written to and read from, much like how a swap file can be used similarly to a swap partition.
This article is a guide on how to create an encrypted partition inside such an image file, and how to then use it 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.
- cryptsetup
- Something to format with (e.g.
mkfs.ext4
)
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 is typically used for formatting real devices, not image files. Make sure to type the image file name in full and it will work just fine)
You should see something like the following:
Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognised partition table.
Created a new DOS disklabel with disk identifier 0x1a2a9193.
Command (m for help):
If you enter the command p
, you can see the properties
of your image:
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
Type the following to create a new partition in the image
([RET]
means to press the return/enter key): n
[RET] p [RET] 1 [RET] [RET] [RET]
. This creates a new
Linux-format partition that fills the drive. This partition should be
visible if you now run the p
command.
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
The actual format of the partition shouldn't matter too much --
after all, we're only going to overwrite it afterwards. However, I
personally like to make sure that the partition is blank before
proceeding. This can be done by executing t [RET] 0 [RET]
to designate the partition as empty space. You can confirm that this
has been done by executing p
again. Alternatively, if you
just want to create a mountable disk image, you can stop here.
Command (m for help): t
Selected partition 1
Partition type (type L to list all types): 0
Type 0 means free space to many systems. Having partitions of type 0 is probably unwise.
Changed type of partition 'Linux' to 'Empty'.
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 0 Empty
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, but
don't neglect the p1
suffix! This is what indicates which
partition to format. 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
Again, replace /dev/loop0
with your loopback
device. encrypted-partition
can be replaced by any
identifier, just make sure to be consistent with whatever one you
choose. Enter your passphrase when prompted. This will open your
encrypted partition and map it
to /dev/mapper/encrypted-partition
, which will behave
just like any other unencrypted partition. This can then be
formatted. To format as ext4, use:
sudo mkfs.ext4 /dev/mapper/encrypted
If you're using a format that supports Linux permissions, you'll
likely need to change the owner so that your user can write to the
drive. First 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, cd
to where the partition has been mounted and execute:
sudo chown $USER:$USER . # Take ownership of the directory
chmod o- . # Give rw to user, nothing to everyone else
You will now be able to create new files and read files in the directory whilst disallowing reading and writing to all other users. The partition can now be unmounted and re-locked, and the loopback device unmounted.
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
for you to put in your ~/.bashrc
or ~/.bash_aliases
that will automate the procedure for
you.
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. This is useful, but I can't make any guarantees about its effectiveness -- if you're using this to try and evade the law, I doubt the law will have much trouble catching you if it came to it. 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!