VHD Encryption

Copyright 2014 by Citrix Systems, Inc. This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.


This page is for general data on encrypted VHDs. I'm starting out with simple things like how to manually create an encrypted VHD, how to load one directly using blktap2 and tap-ctl and whatever else comes to mind. Feel free to add relevant content. 

Supported Algorithms

To create an encrypted VHD we've extended vhd-util with the key command. It's pretty simple to use but first things first: we need an encryption key. We support what is typically referred to as AES-XTS-PLAIN. That means that AES is the encryption, XTS is the 'mode' for the AES algorithm, and PLAIN refers to the method by which initialization vectors are created. Since VHDs have a 2TB limit we use plain instead of plain64.

Keys

Further we support either AES 128 or 256. blktap2 selects the algorithm on start-up based on the size of the key used. One of the fun things about AES is that the key size needs to be twice that of the number associated with the algorithm. So for AES 256 you'll need a 512 bit key. So since the dd command operates in bytes we need either a key 32 or 64 bytes in size.

Let's assume our VHD is going to be called 'crypt.vhd'. From a shell in dom0:

$ dd if=/dev/urandom of=/config/platform-crypto-keys/crypt,aes-xts-plain,512.key bs=64 count=1

In this example I made a 512 bit key by reading 64 bytes from /dev/urandom. This key will cause blktap2 to use AES 256. If you want to use AES 128 read 32 bytes and substtitue 256 for 512 in the file name for the key. This format of this file name is significant so don't mess it up.

Create an Encrypted VHD

To create an encrypted VHD you only need to associate a key with the VHD and blktap2 will do the rest. So first things first we need to create a VHD. Let's make a 512MB VHD and call it 'crypt.vhd'. We'll put it in /storage/disks for good form:

$ vhd-util create -n /storage/disks/crypt.vhd -s 512

Now we take the key we created in the the previous section and associate it with the VHD. We'll start out with the easy way:

$ vhd-util key -s -n /storage/disks/crypt.vhd -k /config/platform-crypto-keys/crypt,aes-xts-plain,512.key

The command above takes the sha256 hash of the key and stores this hash in the VHD header. This allows blktap2 be sure it's using the right key when loading an encrypted VHD. Additionally we can use what vhd-util calls a nonce. This is really called a 'salt' in all the literature. Your salt should be the same size as the output of the hash function so for sha256 it should be 32 bytes. Using a salt is left as an exercise for the interested reader. Take a look at the help output by vhd-util key for other possibilities.

Note: TODO

Mount an Encrypted VHD in dom0

There are a few command sequences you can go through to accomplish this. We'll start with the simple approach and then go into a more complicated approach that's useful if you're debugging blktap2.

The Easy Way

There are a number of steps required to get blktap2 to set everything up and give us a device node in /dev/xen/blktap-2 that's attached to our VHD. There's a command that wraps all of these into a single step for ease of use and we'll start there:

$ tap-ctl create -a vhd:/storage/disks/crypt.vhd

Check your return status and you'll probably get a '126'. Look in /var/log/messages and you'll see that blktap2 requires that the environment variable 'TAPDISK2_CRYPTO_KEYDIR' be set to the directory where it should look for key files. So export this and the above command should work as expected but this time it will output the path to the device node that's been created for our VHD. You can partition this / make filesystems on it / mount and interact with it like any other block device.

The Hard Way

Say you're debugging some stuff in the tapdisk daemon and you've added some test code that dumps a bunch of stuff to the terminal to help you trace through some code path. The Easy Way shown above causes tapdisk2 to daemonize itself and run in the background so you won't be able to see any of your output. Alternatively you can manually kick off your tapdisk2 process keeping it in the foreground and attached to the console:

TAPDISK2_CRYPTO_KEYDIR=/config/platform-crypto-keys tapdisk2 -D

Now you'll get your output but you can no longer use the shortcut tap-ctl create command. Instead we need to manually walk through the steps that are wrapped by tap-ctl create in a new shell. The command above will output the PID of the tapdisk2 process we've started and we'll just call this PID from here on. Scripting this would look like so:

$ MINOR=$(tap-ctl allocate | sed -e 's&^\/dev\/xen\/blktap-2\/tapdev\([0-9]\+\)$&\1')
$ tap-ctl attach -p ${PID} -m ${MINOR}
$ tap-ctl open -p ${PID} -m ${MINOR} -a vhd:/storage/disks/crypto.vhd

First we allocate a device node that initially will have no storage backing it. The allocate command will output the path to the device node and we run that through sed to get the minor device number. Next we attach the tapdisk2 process we started on the other terminal to this device node with the attach command. Then we tell that tapdisk2 daemon to open our VHD and associate it with the same device that we just attached it to with the open command.

Once you're done with your debugging you can run the inverse of these commands in the reverse order: closedetach and deallocate. Once you detach your tapdisk2 daemon from the device node it will shutdown so fair warning.

This approach gives us the most flexibility but really isn't necessary unless you're gonna be debugging tapdisk2.