FS#15016 - [cryptsetup] Keys for non-root LUKS partitions should be read as raw data from block device

Attached to Project: Arch Linux
Opened by Heiko Baums (cyberpatrol) - Tuesday, 09 June 2009, 01:05 GMT
Last edited by Andrea Scarpino (BaSh) - Thursday, 09 December 2010, 08:00 GMT
Task Type Feature Request
Category Packages: Core
Status Closed
Assigned To Aaron Griffin (phrakture)
Thomas Bächler (brain0)
Architecture All
Severity Low
Priority Normal
Reported Version
Due in Version Undecided
Due Date Undecided
Percent Complete 100%
Votes 2
Private No


For LUKS encrypted root partitions it is possible to store a keyfile hidden as raw data onto a USB stick with the dd command. This has the advantage, that the key is saved on a USB stick, but can't be found be just mounting the USB stick.

To use this key to unlocking the root partition, in grub's menu.lst the kernel parameter "cryptkey=BLOCKDEVICE:OFFSET:SIZE" has to be set.

This is read by this part of the encrypt hook:
# Read raw data from the block device
# ckarg1 is numeric: ckarg1=offset, ckarg2=length
dd if=${ckdev} of=${ckeyfile} bs=1 skip=${ckarg1} count=${ckarg2} >/dev/null 2>&1

Unfortunately it is not possible to store the key for encrypted non-root partitions in the same way, because /etc/rc.sysinit can only read normal files, which are set in /etc/crypttab.

/etc/rc.sysinit should also be able to read keys for non-root partitions as raw data from a block device in the same or a similar way as it is done by the encrypt hook.

The appropriate line in /etc/crypttab could then be similar to the kernel parameter in /boot/grub/menu.lst:

But the key read from the USB stick and written temporarily onto the HDD or into a tmpfs by dd should of course be wiped after unlocking the encrypted device.

This way the keys for non-root partitions don't need to be saved on the root partition. Even if the root partition is encrypted and it's not that likely, that this happens, the keys could be read, if the root partition is mounted and the root account is hacked. But reading a key from a USB stick as raw data could increase the security for paranoid users.

And I guess implementing this is not much more work - well, a bit more work - than copying the appropriate part of the encrypt hook into /etc/rc.sysinit.

See also this paragraph for root partitions in the wiki:
This task depends upon

Closed by  Andrea Scarpino (BaSh)
Thursday, 09 December 2010, 08:00 GMT
Reason for closing:  Implemented
Additional comments about closing:  http://projects.archlinux.org/initscript s.git/commit/?id=392990639656d14db854aaf 62d3a0a471c013111
Comment by Thomas Bächler (brain0) - Tuesday, 09 June 2009, 06:52 GMT
This is now the second or third request to implement one of the features of the initramfs crypto into crypttab, this looks like a big crypttab code rewrite. Don't expect this to be done soon, there's a long list of initscripts bugs I need to take care of. Generally, I think we can do it.
Comment by Heiko Baums (cyberpatrol) - Tuesday, 09 June 2009, 08:16 GMT
I don't think, that this has to be a big crypttab code rewrite. I don't know the other requests, but for this feature request you just need to add a new elif or else clause in the already existing if construct, which looks into /etc/crypttab and see if the PASSWORD field in /etc/crypttab is in the form "home /dev/sdaX BLOCKDEVICE:OFFSET:SIZE".

Into this else or elif clause you just put the appropriate code from /lib/initcpio/hooks/encrypt, which I posted in my original bug report:
# Read raw data from the block device
# ckarg1 is numeric: ckarg1=offset, ckarg2=length
dd if=${ckdev} of=${ckeyfile} bs=1 skip=${ckarg1} count=${ckarg2} >/dev/null 2>&1

Maybe I can write a patch later.

I'm just not sure, where to let dd write the keyfile temporarily when reading it from the USB key. I guess the best would be to write it to /dev/shm, the tmpfs, and to wipe it there after the partitions are unlocked.
Comment by Thomas Bächler (brain0) - Tuesday, 09 June 2009, 09:56 GMT
Not this particular patch, but there are more feature-requests for crypttab pending.

A problem is that there is no tmpfs mounted at the time the encrypted volumes are openened. We could abuse /dev or mount something temporarily and then umount it. I agree that we shouldn't write it on the hard drive (which is also read-only at the time).
Comment by Heiko Baums (cyberpatrol) - Tuesday, 09 June 2009, 14:24 GMT
It shouldn't be necessary to write the keyfile temporarily to tmpfs or the hard disk, because according to the manpages cryptsetup can read the key from stdin with `cryptsetup -d -` and dd can write the output to stdout with `dd -if=BLOCKDEVICE` without the -df parameter.

So it should be possible to read the keyfile with something like this: `cryptsetup --key-file - luksOpen ${cryptdev} ${cryptname} ${CSQUIET} < dd -if=BLOCKDEVICE bs=1 skip=OFFSET count=SIZE`

The fact, that the keyfile is temporarily stored in RAM this way, shouldn't matter. because the key is stored in RAM anyway to be able to de- and encrypt the data on the fly. But this is by design, and I doubt, that there is a harddisk encryption method, which doesn't need the key in RAM.
Comment by Heiko Baums (cyberpatrol) - Tuesday, 09 June 2009, 14:25 GMT
> without the -df parameter

Of course without the -of parameter.
Comment by Heiko Baums (cyberpatrol) - Wednesday, 10 June 2009, 23:18 GMT
Well, here's the fix.

Now you can add a line like this to /etc/crypttab:
home /dev/sda3 /dev/usbstick:15678954:2048

Piping the keyfile from dd to cryptsetup doesn't work, but there is already or still a tmpfs at /dev/shm, so the keyfile can be temporarily written to this directory. After booting the keyfile isn't in /dev/shm anymore, so I guess this tmpfs is still from the initrd.
Comment by Heiko Baums (cyberpatrol) - Wednesday, 10 June 2009, 23:38 GMT
Made a small mistake during some copy & paste actions.
Here's the correct patch.
Comment by Aaron Griffin (phrakture) - Friday, 12 June 2009, 15:50 GMT
This seems pretty complex. Thomas, any opinion on this patch? Without knowing too much about what problem this solves, it seems a bit overcomplicated to me.
Comment by Heiko Baums (cyberpatrol) - Friday, 12 June 2009, 18:30 GMT
Aaron, it's not that complicated. The lines with the ck* variables just split the parameter $cpass into three values (the device, where the key is saved, the offset, where the key begins and the size of the key), so the the password field in /etc/crypttab can be set to /dev/usbstick:OFFSET:SIZE as it can be done with the kernel parameter cryptkey=. The same technique is also used in the kernel's PKGBUILD to split the kernel name. ;-)

Have used these "complicated" commands to be able to split this variable only with bash commands and to avoid third party dependencies like cut, which also should save a bit time. dd is of course necessary to read the hidden key from the USB stick, which is also written by dd onto the USB stick.

The rest is not really complicated. It's nearly the same as the encrypt hook and the other encryption methods in rc.sysinit do.

This patch is to be able to save a LUKS key hidden onto a USB stick e.g. as described in the wiki article I mentioned in the original feature request above.
Comment by Heiko Baums (cyberpatrol) - Sunday, 14 June 2009, 01:49 GMT
Gerardo,  FS#10465  is a completely different issue, which applies to the encryption of the root partition in the encrypt hook.
This feature request applies to reading the key from a blockdevice like a USB stick by dd for the encryption of non-root partitions in /etc/rc.sysinit.
Comment by Heiko Baums (cyberpatrol) - Sunday, 14 June 2009, 01:52 GMT
Gerardo, wanted to say, you should remove  FS#10465  from the related tasks.