http://anadoxin.org/blog

Block encryption in OpenBSD

Sun, 05 July 2015 :: #openbsd :: #crypto

OpenBSD's block encryption is slightly different than on Linux or FreeBSD.

Linux uses dm-crypt or LUKS, FreeBSD uses geli or gbde. On OpenBSD 5.7 the user can utilise softraid0 driver to acquire the same thing. Please note that you could also use vnconfig's internal encryption (Blowfish), but on vnconfig's manpage the maintainer says this method is deprecated. So, I won't even consider it here.

The plan is the same as in other systems:

  • First we need to create a container file, ideally basing its initial content on /dev/urandom or similar,

  • Second, we need to create a loop device, so the file will become a device. softraid0's driver -- bioctl accepts only devices as arguments.

  • Third, after creating the virtual device, we need to insert an encryption layer on it (softraid0),

  • Last, we can later create the filesystem and mount it to some directory.

So, let's go!

Creating a container file

This is pretty straightforward. We can use dd to copy the contents of /dev/urandom to a file:

$ dd if=/dev/urandom of=encrypted_storage.bin bs=1M count=10

This command-line will create a file with 10 megabytes of random bytes in it.

Creating a loop device

OpenBSD contains a command named vnconfig for creation of loop devices. The name comes from "virtual node configuration", where "virtual node" is a terminology used for loop devices.

The kernel installed by default supports adding 4 vn's. Since OpenBSD removed the ability to dynamically load kernel modules, I guess we're stuck with that.

Here's how you can create a loop device:

$ sudo vnconfig vnd0 encrypted_storage.bin
$ sudo vnconfig -l
vnd0: covering encrypted_storage.bin on sd0a, inode 2808930
vnd1: not in use
vnd2: not in use
vnd3: not in use

vnd0 is the name of the first virtual node that is available.

vnconfig -l showed us the status of virtual node allocation. It's easy to see that vnd0 is allocated, rest of vn's are unallocated. But, there is a slight complication.

Unlike on Linux, you don't refer to these nodes by /dev/vnd0 or anything like that. In fact, /dev/vnd0 doesn't even exist. But we'll see that in a minute.

Creating an encryption layer

First we need to prepare our device for softraid0 by creating BSD partitions.

Preparations

BSD partitions live inside normal MBR partitions, so we need to create an MBR partition first!

Creation of normal MBR partition is done by the fdisk command. The name of the device will be our vnd0 device, but we can refer to it only by the /dev/rvnd0c device. Now let's see:

  • /dev/rvnd0c is a character device for vnd0. "c" at the end of the device name means that we want to refer to the whole disk, not a partition of any kind.

  • /dev/vnd0c is a block device for vnd0. "c" at the end means the same thing as in rvnd0c.

fdisk only accepts character devices, so we need to refer to our virtual node device by using /dev/rvnd0c.

$ sudo fdisk -i /dev/rvnd0c
Do you wish to write new MBR and partition table? [n] y
Warning CHS values out of bounds only saving LBA values
Writing MBR at offset 0.

The -i argument will create a new MBR partition table with one partition covering the whole disk. This is perfect for creation of another layer of BSD partitions.

We can verify the allocation by using fdisk /dev/rvnd0c:

$ sudo fdisk /dev/rvnd0c
Disk: /dev/rvnd0c      geometry: 204/1/100 [20480 Sectors]
Offset: 0       Signature: 0xAA55
            Starting         Ending         LBA Info:
 #: id      C   H   S -      C   H   S [       start:        size ]
-------------------------------------------------------------------------------
 0: 00      0   0   0 -      0   0   0 [           0:           0 ] unused
 1: 00      0   0   0 -      0   0   0 [           0:           0 ] unused
 2: 00      0   0   0 -      0   0   0 [           0:           0 ] unused
*3: A6      1   0  29 -    203   0 100 [         128:       20272 ] OpenBSD

Now we can start creating BSD partitions. We will need 1 partition, unless your needs are different.

Creation of 1 partition can be done with disklabel. During installation of OpenBSD you've already used disklabel, so you'll probably know how to use it. disklabel seems to accept both block and character devices, so it probably doesn't matter if you pass rvnd0c or vnd0c here:

$ sudo disklabel -E /dev/rvnd0c
Label editor (enter '?' for help at any prompt)

First we can make sure our BSD partition layout is empty by using the p command:

> p
OpenBSD area: 0-20480; size: 20480; free: 20480
#                size           offset  fstype [fsize bsize  cpg]
c:              20480                0  unused

Remember, the 'c' partition is a reference to the whole disk. This output doesn't mean that there is a 'c' partition.

If it's empty, let's use a command to add a parition:

> a
partition: [a]
offset: [0]
size: [20480]
FS type: [4.2BSD] RAID

Notice I've used a different FS type here. I've used RAID filesystem type, because this partition will be used by softraid0 later. softraid0 would probably fail to install itself in 4.2BSD partition (I haven't checked that though).

Let's verify that everything went well by printing the partition table once again:

> p
OpenBSD area: 0-20480; size: 20480; free: 0
#                size           offset  fstype [fsize bsize  cpg]
a:              20480                0    RAID
c:              20480                0  unused

Everything seems OK, we can save & quit the partition table by using the q command:

> q
Write new label?: [y] y

Now our container is prepared for softraid0.

Creation of softraid0

We can finally create the encryption layer. Since we have every preprequisite already covered, this is very easy.

We will use bioctl command to interface with softraid0.

$ sudo bioctl -c C -l /dev/vnd0a softraid0

-c C will tell bioctl that we would like to use CRYPTO RAID discipline. This basically means that we won't actually use RAID functionality, we just want an encryption layer.

-l /dev/vnd0a specifies the target device we would like to use. We're giving the block device here, because bioctl wants a block device, and we specify the 'a' partition here as well, because we've created it in the disklabel step few paragraphs above.

softraid0 is the name of the driver to use, and it needs to stay just like this.

The driver tool will ask us for the passphrase. It won't be echoed, just specify it and we're done here.

$ sudo bioctl -c C -l /dev/vnd0a softraid0
Passphrase:
softraid0: CRYPTO volume attached as sd1

Make sure to write it properly, because bioctl will not ask twice.

The algorithm used is AES XTS 256, which is a standard one. You don't really have to modify it, because it's considered to be secure. You can modify the number of encryption key generation rounds with the -r option. Please check man bioctl for more information on this.

We can see that we have a new device now, sd1. It's already encrypted and we can finally create a filesystem on it.

We could partition it with fdisk and disklabel, but it seems that this isn't necessary. We can just refer to this device with the 'c' suffix, which refers to the whole disk.

Remember, the rsd1c device means that we want to access the character device of sd1c. sd1c means that we would like to refer to the whole space of sd1, without considering any partitions. newfs doesn't accept block devices, so we can't use sd1c here, we have to use rsd1c.

$ sudo newfs /dev/rsd1c
newfs: reduced number of fragments per cylinder group from 1240 to 1232 to enlarge last cylinder group
/dev/rsd1c: 9.7MB in 19952 sectors of 512 bytes
5 cylinder groups of 2.41MB, 154 blocks, 384 inodes each
super-block backups (for fsck -b #) at:
 32, 4960, 9888, 14816, 19744,

We can mount the filesystem now:

$ sudo mount /dev/sd1c /tmp/disk

Done! We have a new encrypted directory with 10 megabytes of free space in it.

$ df -h
Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/sd0a     27.6G    2.7G   23.5G    10%    /
/dev/sd1c      9.3M    2.0K    8.9M     0%    /tmp/disk

Achievement unlocked: creation of your first encrypted storage on OpenBSD ;).