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

前端 未结 5 581
轻奢々
轻奢々 2021-01-30 23:58

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 keyb

5条回答
  •  执念已碎
    2021-01-31 01:01

    despite the great answer from @Andrew which works in previous versions. The solution actually is outdated and needs lots of tuning for ubuntu 18.04 and 19.10. So I want to share my research on this.

    There are several catches about crypttab. The sepcs actually changed a lot from 14.04 to 18.04 and to 19.10. It starts to support more parameters for cryptsetup. For example keyfile-offset, keyfile-size, etc. Some of the options e.g. nobootwait are gone. Some parameters supported in other distro already but is not supported in ubuntu yet (for example very nice parameter keyfile-timeout. This can eliminate the entire keyscript since it will automatically fallback to keyboard input after the keyfile-timeout.)

    The major pit-fall for crypttab on ubuntu is that it actually processed by 2 different processes. One is the traditionally initramfs and another is the modern systemd. Systemd is supposed to be more advanced and flexiable in many aspect. However, systemd has poor support for crypptab, there are many options such as keyscript just silently ignored. so I have no idea what is going on, until I spotted this post. Almost all the posts online about crypttab settings is for initramfs not for systemd. So we need to add initramfs to all the entries in crypttab to avoid problems.

    I also discovered a nice way to debug our keyscript and crypttab without VM or repeatedly rebooting. It is cryptdisks_start. Before we actually propagate our changes to initramfs, we should always test it with this nice command. Otherwise, you have to end-up locked out from your system and can only recover it through chroot environment.

    @andrew posted a nice way to use data hide in the raw area of a file system. However, I found it is very annoying when we want to automatically create partitions and dd the raw data to lots of usbkeys, we have to calculate the offset for all different file systems and different partition sizes. Moreover, if a user accidentally write onto the FS, there is some risk that the key got overritten. A raw partition without any FS on it makes more sense in this case. However raw partition does not have UUID which is not very useful for automatic unlocking. Thus, I would like introduce a way just use normal passphrase files on the usbkey filesystem. The major issue of passdev is it does not seek/stop during reading the file. Thus we cannot use the keyfile-offset and keyfile-size option when we want to fallback to keyboard input. Because cryptsetup will actually try to skip in the input content and if the content is shorter than keyfile-size, it raises an error. This also means if there is large offset, passdev can be very slow since it always read from beginning. However, there is no point to implement offset and keyfile size for a actual file on file system. I believe those are created for raw device.

    The crypttab

    luks-part UUID="" /dev/disk/by-uuid/:/: luks,keyfile-offset=,keyfile-size=<>,keyscript=/bin/passphrase-from-usbfs.sh,tries=,initramfs
    

    the keyscript passphrase-from-usbfs.sh utilized the /lib/cryptsetup/scripts/passdev which will wait the usb device and mount the fs then pipe out the file content. It supports the CRYPTTAB_KEY in format of /device-path/:/:.

    #!/bin/sh
    #all message need to echo to stderr, the stdout is used for passphrase
    # TODO: we may need to do something about the plymouth
    echo "CRYPTTAB_KEY=$CRYPTTAB_KEY" >&2
    echo "CRYPTTAB_OPTION_keyfile_offset=$CRYPTTAB_OPTION_keyfile_offset" >&2
    #set your offset and file size here if your system does not support those paramters
    #CRYPTTAB_OPTION_keyfile_offset=
    #CRYPTTAB_OPTION_keyfile_size=
    echo "timeout=$CRYPTTAB_OPTION_keyfile_timeout" >&2
    CRYPTTAB_OPTION_keyfile_timeout=10 # keyfile-timeout is not supported yet 
    pass=$(/lib/cryptsetup/scripts/passdev $CRYPTTAB_KEY)
    rc=$?
    if ! [ $rc -eq 0 ]; then
        echo "Can't find $CRYPTTAB_KEY; USB stick not present?" >&2
        /lib/cryptsetup/askpass "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME) Enter passphrase: "
    else
        echo "successfully load passphrase." >&2
        echo -n $pass
    fi
    
    

    The hook tell update-initramfs to copy our scripts.

    #!/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-usbfs.sh
    copy_exec /bin/passphrase-from-usb.sh
    #when using passdev we need to hook additionaly FS and binary
    copy_exec /lib/cryptsetup/scripts/passdev
    manual_add_modules ext4 ext3 ext2 vfat btrfs reiserfs xfs jfs ntfs iso9660 udf
    

    Finally I posted the updated version of passphrase-from-usb.sh which can use the new parameters in crypttab:

提交回复
热议问题