├── README.md └── decrypt_keyctl /README.md: -------------------------------------------------------------------------------- 1 | # decrypt_keyctl 2 | 3 | A passphrase caching script to be used in `/etc/crypttab` on Debian and Ubuntu. 4 | When there are multiple cryptsetup (either plain or LUKS) volumes with the same 5 | passphrase, it is tedious to input the passphrase more than once. 6 | 7 | Just add this script as keyscript to your /etc/crypttab and it will cache the 8 | passphrase of all cryptab entries with the same identifier. 9 | 10 | Either copy `decrypt_keyctl` into the default search path for keyscripts from 11 | cryptsetup `/lib/cryptdisks/scripts/`. So you can just write `keyscript=decrypt_keyctl` 12 | in `/etc/crypttab`, or use a random path of your choice and give the full path 13 | e.g `keyscript=/sbin/decrypt_keyctl`. 14 | 15 | As a countermeasure against you misstyping your password please add `:` to the end of the 16 | first key identifier. That means the script always asks for a passphrase on that 17 | specific key entry. 18 | 19 | ## Requirements 20 | 21 | - Debian cryptsetup package with `/etc/crypttab` handling and keyscript option 22 | - Tested with Debian Lenny, Squeeze and Sid 23 | - Installed and working keyutils package (keyctl) 24 | - Needs `CONFIG_KEYS=y` in your kernel configuration 25 | 26 | 27 | ## What For? 28 | 29 | The current state for dm-crypt in Linux is that it is single threaded, thus 30 | every dm-crypt mapping only uses a single core for crypto operations. 31 | To use the full power of your many-core processor it is thus necessary to split 32 | the dm-crypt device. For Linux software raid arrays the easiest segmentation is to 33 | just put the dm-crypt layer below the software raid layer. 34 | 35 | But with a 5 disk raid5 it is a rather daunting task to input the passphrase five 36 | times. 37 | This is what this keyscripts solve for you. 38 | 39 | 40 | ## Usage 41 | 42 | Best shown by example 43 | 44 | - 5 disks 45 | - Linux software raid5 46 | 47 | ``` 48 | Layer: 49 | sda sdb sdc ... sde 50 | +-----------+ +-----------+ 51 | | LUKS | | LUKS | 52 | | +-------+ | | +-------+ | 53 | | | RAID5 | | | | RAID5 | | 54 | | | ... | | | | ... | | 55 | ``` 56 | 57 | Crypttab Entries: 58 | 59 | ``` 60 | 61 | sda_crypt /dev/sda2 main_data_raid: luks,keyscript=decrypt_keyctl 62 | sdb_crypt /dev/sdb2 main_data_raid luks,keyscript=decrypt_keyctl 63 | ... 64 | sde_crypt /dev/sde2 main_data_raid luks,keyscript=decrypt_keyctl 65 | ``` 66 | 67 | ## How does it work 68 | 69 | ### Crypttab Interface 70 | 71 | A keyscript is added to options including a keyfile definition as third 72 | parameter in the crypttab file. The keyscript is called with the keyfile as the 73 | first and only parameter. Additionally there are a few environment variables 74 | set but currently are not used by this keyscript (man 5 crypttab for exact 75 | description). 76 | 77 | ### Keyscript 78 | 79 | Keyctl_keyscript uses the Linux kernel keyring facility to securly cache 80 | passphrases between multiple invocations. 81 | The keyfile parameter from cryptab is used to find the same passphrase between 82 | multiple invocations. 83 | 84 | Currently the cache timeout is 60 seconds and not configurable (please report a 85 | bug if it is too low for you). 86 | 87 | ## Problems 88 | 89 | Passphrase is piped between processes and could end up in unsecured memory, thus later swapped to disk! 90 | 91 | **Warning** 92 | Use of encrypted swap recommend! 93 | 94 | ## Hints 95 | 96 | To remove all traces of your passphrase from kernel keyring left by this script you may want to cleanup the keyring 97 | afterwards with the following command: 98 | 99 | ``` 100 | sudo keyctl clear @u 101 | ``` 102 | -------------------------------------------------------------------------------- /decrypt_keyctl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # decrypt_keyctl - to use in /etc/crypttab as keyscript 3 | # Allows to cache passwords for cryptdevices for 60s 4 | # The same password is used for for cryptdevices with the same identifier. 5 | # The keyfile parameter, which is the third field from /etc/crypttab, is 6 | # used as identifier in this keyscript. 7 | # 8 | # sample crypttab entries: 9 | # test1 /dev/sda1 test_pw: luks,keyscript=decrypt_keyctl 10 | # test2 /dev/sda2 test_pw luks,keyscript=decrypt_keyctl 11 | # test3 /dev/sda3 test_other_pw luks,keyscript=decrypt_keyctl 12 | # 13 | # test1 and test2 have the same identifier thus test2 does not need a password 14 | # typed in manually 15 | # 16 | # Identifiers ending with : are asked for every time. Use this for your first 17 | # groupkey entry. 18 | 19 | die() 20 | { 21 | echo "$@" >&2 22 | exit 1 23 | } 24 | 25 | # check for keygroup ending with ':' 26 | CRYPTTABID_="$1" 27 | TMP_="${CRYPTTABID_%:}" 28 | if [ "x$CRYPTTABID_" != "x$TMP_" ]; then 29 | ASKFORKEY_="true" 30 | CRYPTTABID_="$TMP_" 31 | else 32 | ASKFORKEY_="false" 33 | fi 34 | 35 | # the keyfile given from crypttab is used as identifier in the keyring 36 | # including the prefix "cryptkey:" 37 | ID_="cryptkey:${CRYPTTABID_}" 38 | TIMEOUT_='60' 39 | ASKPASS_='/lib/cryptsetup/askpass' 40 | STTY_='/bin/stty' 41 | PW_READER_='undefined' 42 | PROMPT_="Caching passphrase for ${CRYPTTAB_SOURCE}: " 43 | 44 | test -x "$STTY_" && PW_READER_='stty' # 1. backup method 45 | test -x "$ASKPASS_" && PW_READER_='askpass' # prefered method 46 | 47 | KID_=$(keyctl search @u user "$ID_" 2>/dev/null) 48 | if [ $? -ne 0 ] || [ -z "$KID_" ] || [ "$ASKFORKEY_" = "true" ]; then 49 | # key not found, ask the user 50 | case "$PW_READER_" in 51 | askpass) 52 | KEY_=$($ASKPASS_ "$PROMPT_") || die "Error executing $ASKPASS_" 53 | ;; 54 | stty) # disable echoing with stty 55 | $STTY_ -echo 56 | if ! read -r KEY_; then 57 | $STTY_ echo 58 | die "Error reading key from /dev/stdin" 59 | else 60 | $STTY_ echo 61 | echo >&2 62 | fi 63 | ;; 64 | *) # first try to read the posix way, then at least give the user a chance 65 | echo -n "$PROMPT_" >&2 66 | if ! read -res KEY_; then 67 | echo 68 | echo "ERROR: Can not disable echoing, YOUR PASSWORD WILL BE VISIBLE!" >&2 69 | echo "This can be fixed if you add either $ASKPASS_" >&2 70 | echo "or $STTY_ to your initramfs" >&2 71 | echo -n "$PROMPT_" >&2 72 | if ! read -r KEY_; then 73 | die "Error reading key from /dev/stdin" 74 | else 75 | echo >&2 76 | fi 77 | else 78 | echo >&2 79 | fi 80 | ;; 81 | esac 82 | KID_=$(echo -n "$KEY_" |keyctl padd user "$ID_" @s) 83 | [ -z "$KID_" ] && die "Error adding passphrase to kernel keyring" 84 | if ! keyctl setperm $KID_ 0x3f3f0000; then 85 | keyctl unlink $KID_ @s 86 | die "Error setting permissions on key ($KID_), removing" 87 | fi 88 | keyctl unlink $KID_ @s 89 | keyctl link $KID_ @u 90 | if ! keyctl timeout $KID_ $TIMEOUT_; then 91 | keyctl unlink $KID_ @u 92 | die "Error setting timeout on key ($KID_), removing" 93 | fi 94 | else 95 | echo "Using cached passphrase for ${CRYPTTAB_SOURCE}." >&2 96 | fi 97 | keyctl pipe $KID_ 98 | --------------------------------------------------------------------------------