Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to load LUKS passphrase from USB, falling back to keyboard?

I want to set up a headless Linux (Debian Wheezy) PC with whole disk encryption, with the ability to unlock the disk either with a USB drive, or by entering a passphrase by keyboard. My starting point is a fresh install using the basic whole disk encryption option in the Debian Installer, which manages everything besides /boot as a LUKS-encrypted logical volume group and gives me the keyboard option. I will describe my current solution in an answer, in hopes that it will be useful and that others can improve on it.

Here are some of the issues I had:

  • Setting up a passphrase and putting it on the USB drive.

  • Loading the USB modules in time.

  • Waiting for the USB drive to recognized by Linux before trying to read from it.

  • Identifying the correct USB drive (not some other drive that happens to be inserted).

  • Writing a "keyscript" to pull a passphrase off the USB drive.

  • Ensuring that the fall-back to keyboard kicks in in all USB failure cases.

I will accept an answer with significant improvements and upvote answers that offer contributions.

like image 576
Andrew Avatar asked Oct 31 '13 18:10

Andrew


People also ask

How do I add a passphrase to my Luks drive?

LUKS Drives can actually have multiple passphrases or key files associated with them, up to eight. To start, take a look at your drive and see how many keys it has. Chances are, you’ll only see key slot 0 occupied. That’s the first one. If you have free slots open, you can always add another passphrase to your drive.

How to encrypt the storage device SDB with Luks passphrase?

To encrypt the storage device sdb with LUKS passphrase, run the following command: Type in YES (must be in capital letters) and press < Enter >. Type in a LUKS passphrase and press < Enter >. Retype the LUKS passphrase and press < Enter >. Your storage device sdb should be encrypted with LUKS and your desired LUKS passphrase should be set.

Why does LUKS encryption fail at boot time?

A forgotten password or passphrase may cause the LUKS decryption failure at boot time. Currently, there is no way to recover LUKS passphrase. Sometimes sysadmin or user changes their LUKS password to an unknown value. Please note that LUKS currently allows a total of eight passphrase or key slots for encrypted disks.

What is LUKS encryption and how does it work?

Whichever way you choose to manage your LUKS passphrases, you’ll find that it’s one of the most flexible encryption options available. Because LUKS lets you change, manage, and remove keys, you can add new layers of security to your drive.


2 Answers

A lot of my solution is derived from the post, Using A USB Key For The LUKS Passphrase.

  1. Create a random passphrase:

    dd if=/dev/urandom bs=1 count=256 > passphrase
    
  2. Insert a USB drive. dmesg output will show the device name; assume /dev/sdd. Figure out its size:

    blockdev --getsize64 /dev/sdd
    
  3. I decided to install the passphrase at the end of the raw device, figuring it might survive any accidental use of the USB drive.

    dd if=passphrase of=/dev/sdd bs=1 seek=<size-256>
    
  4. Add the passphrase to the LUKS volume:

    cryptsetup luksAddKey /dev/sda5 passphrase
    

    This does not affect the existing hand-entered passphrase from the installer. The passphrase file can be deleted:

    rm passphrase
    
  5. Find a unique name for the USB stick, so we can identify it when present:

    ls -l /dev/disk/by-id | grep -w sdd
    

    You should see one symlink. I will call it /dev/disk/by-id/<ID>.

  6. Edit /etc/crypttab. You should see a line like:

    sdc5_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 none luks
    

    Modify it to:

    sdc5_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 /dev/disk/by-id/<ID> luks,keyscript=/bin/passphrase-from-usb
    
  7. The keyscript referred to above will need to read the passphrase from the USB device. However, it needs to do more than that. To understand how it is used, check /usr/share/initramfs-tools/scripts/local-top/cryptroot, the script that runs at boot time to unlock the root device. Note when a keyscript is set, it is simply run and the output piped to luksOpen with no other checking. There is no way to signal an error (USB drive not present) or fall back to keyboard input. If the passphrase fails, the keyscript is run again in a loop, up to some number of times; however we are not told which iteration we are on. Also, we have no control over when the keyscript is run, so we can't be sure Linux has recognized the USB drive.

    I addressed this with some hacks:

    1. Poll on the USB drive and wait 3 seconds for it to appear. This works for me, but I would love to know a better way.

    2. Create a dummy file /passphrase-from-usb-tried on first run to indicate that we have been run at least once.

    3. If we have been run at least once, or the USB drive cannot be found, run the askpass program used by cryptroot for keyboard input.

    The final script:

    #!/bin/sh
    
    set -e
    
    if ! [ -e /passphrase-from-usb-tried ]; then
        touch /passphrase-from-usb-tried
        if ! [ -e "$CRYPTTAB_KEY" ]; then
            echo "Waiting for USB stick to be recognized..." >&2
            sleep 3
        fi
        if [ -e "$CRYPTTAB_KEY" ]; then
            echo "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME) from USB key" >&2
            dd if="$CRYPTTAB_KEY" bs=1 skip=129498880 count=256 2>/dev/null
            exit
        else
            echo "Can't find $CRYPTTAB_KEY; USB stick not present?" >&2
        fi
    fi
    
    /lib/cryptsetup/askpass "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME)\nEnter passphrase: "
    

    Finally, we need to ensure that this script is available in the initramfs. Create /etc/initramfs-tools/hooks/passphrase-from-usb containing:

    #!/bin/sh
    
    PREREQ=""
    
    prereqs() {
            echo "$PREREQ"
    }
    
    case "$1" in
            prereqs)
                    prereqs
                    exit 0
            ;;
    esac
    
    . "${CONFDIR}/initramfs.conf"
    . /usr/share/initramfs-tools/hook-functions
    
    copy_exec /bin/passphrase-from-usb /bin
    
  8. The USB drivers were not present in my initramfs. (It appears they are by default in later versions of Debian.) I had to add them by adding to /etc/initramfs-tools/modules:

    uhci_hcd
    ehci_hcd
    usb_storage
    
  9. When all is done, update the initramfs:

    update-initramfs -u
    
like image 78
Andrew Avatar answered Oct 14 '22 08:10

Andrew


It would be ideal to me if I could simply have a small USB stick containing a passphrase that will unlock the disk. Not only would that be handy for servers (where you could leave the USB stick in the server - the goal is to be able to return broken harddisks without having to worry about confidential data), it would also be great for my laptop: Insert the USB stick when booting and remove it after unlocking the cryptodisk.

I have now written a patch that will search the root dir of all devices for the file 'cryptkey.txt' and try decrypting with each line as a key. If that fails: Revert to typing in the pass phrase.

It does mean the key cannot contain \n, but that would apply to any typed in key, too. The good part is that you can use the same USB disk to store the key for multiple machines: You do not need a separate USB disk for each. So if you have a USB drive in your physical key ring, you can use the same drive for all the machines you boot when being physically close.

You add the key with:

cryptsetup luksAddKey /dev/sda5

And then put the same key as a line in a file on the USB/MMC disk called 'cryptkey.txt'. The patch is here:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864647

If the USB drivers, MMC drivers or the filesystems are not present in your initramfs, you need to add them by adding to /etc/initramfs-tools/modules:

uhci_hcd
ehci_hcd
usb_storage
nls_utf8
nls_cp437
vfat
fat
sd_mod
mmc_block
tifm_sd
tifm_core
mmc_core
tifm_7xx1
sdhci
sdhci_pci

When all is done, update the initramfs:

update-initramfs -u

It can be found as patch and file at: https://gitlab.com/ole.tange/tangetools/tree/master/decrypt-root-with-usb

like image 25
Ole Tange Avatar answered Oct 14 '22 09:10

Ole Tange