#!/bin/bash CIPHER_XTS_PLAIN="aes-xts-plain64" CIPHER_CBC_ESSIV="aes-cbc-essiv:sha256" CIPHER_CBC_TCW="serpent-cbc-tcw" # TODO: mode with LMK TEST_KEYRING_NAME="keyringtest_keyring" LOGON_KEY_16_OK="dmtst:lkey_16" LOGON_KEY_32_OK="dmtst:lkey_32" LOGON_KEY_64_OK="dmtst:lkey_64" HEXKEY_16="be21aa8c733229347bd4e681891e213d"; HEXKEY_32="bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; HEXKEY_64="34f95b96abff946b64f1339ff8653cc77c38697c93b797a496f3786e86eed7781850d5112bbae17d209b8310a8f3a034f1cd297667bc0cd1438fad28d87ef6a1" DEVSIZEMB=16 DEVSECTORS=$((DEVSIZEMB*1024*1024/512)) NAME=testcryptdev CHKS_DMCRYPT=vk_in_dmcrypt.chk CHKS_KEYRING=vk_in_keyring.chk PWD="aaa" CRYPTSETUP=../cryptsetup function remove_mapping() { [ -b /dev/mapper/$NAME ] && dmsetup remove $NAME # unlink whole test keyring [ -n "$TEST_KEYRING" ] && keyctl unlink $TEST_KEYRING "@u" >/dev/null rmmod scsi_debug 2>/dev/null rm -f $CHKS_DMCRYPT $CHKS_KEYRING } function skip() { [ -n "$1" ] && echo "$1" remove_mapping exit 77 } function fail() { [ -n "$1" ] && echo "$1" echo "FAILED at $(caller)" remove_mapping exit 2 } # $1 hexbyte key # $2 type # $3 description # $4 keyring function load_key() { local tmp="$1" shift echo -n "$tmp" | xxd -r -p | keyctl padd $@ >/dev/null } function dm_crypt_keyring_support() { VER_STR=$(dmsetup targets | grep crypt | cut -f2 -dv) [ -z "$VER_STR" ] && fail "Failed to parse dm-crypt version." VER_MAJ=$(echo $VER_STR | cut -f 1 -d.) VER_MIN=$(echo $VER_STR | cut -f 2 -d.) # run the test with dm-crypt v1.15.0+ on purpose # the fix is in dm-crypt v1.18.1+ [ $VER_MAJ -gt 1 ] && return 0 [ $VER_MAJ -lt 1 ] && return 1 [ $VER_MIN -ge 15 ] } function test_and_prepare_keyring() { keyctl list "@s" > /dev/null || skip "Current session keyring is unreachable, test skipped" TEST_KEYRING=$(keyctl newring $TEST_KEYRING_NAME "@u" 2> /dev/null) test -n "$TEST_KEYRING" || skip "Failed to create keyring in user keyring" keyctl search "@s" keyring "$TEST_KEYRING" > /dev/null 2>&1 || keyctl link "@u" "@s" > /dev/null 2>&1 load_key "$HEXKEY_16" user test_key "$TEST_KEYRING" || skip "Kernel keyring service is useless on this system, test skipped." } add_device() { modprobe scsi_debug $@ delay=0 if [ $? -ne 0 ] ; then echo "This kernel seems to not support proper scsi_debug module, test skipped." exit 77 fi sleep 2 DEV=$(grep -l -e scsi_debug /sys/block/*/device/model | cut -f4 -d /) DEV="/dev/$DEV" [ -b $DEV ] || fail "Cannot find $DEV." } [ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped." which dmsetup >/dev/null 2>&1 || skip "Cannot find dmsetup, test skipped" which keyctl >/dev/null 2>&1 || skip "Cannot find keyctl, test skipped" which xxd >/dev/null 2>&1 || skip "Cannot find xxd, test skipped" which sha1sum > /dev/null 2>&1 || skip "Cannot find sha1sum, test skipped" modprobe dm-crypt || fail "dm-crypt failed to load" dm_crypt_keyring_support || skip "dm-crypt doesn't support kernel keyring, test skipped." test_and_prepare_keyring add_device dev_size_mb=$DEVSIZEMB dd if=/dev/urandom of=$DEV bs=1M count=$DEVSIZEMB oflag=direct > /dev/null 2>&1 || fail #test aes cipher with xts mode, plain IV echo -n "Testing $CIPHER_XTS_PLAIN..." dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_XTS_PLAIN $HEXKEY_32 0 $DEV 0" || fail sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail dmsetup remove $NAME || fail load_key "$HEXKEY_32" logon $LOGON_KEY_32_OK "$TEST_KEYRING" || fail "Cannot load 32 byte logon key type" dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_XTS_PLAIN :32:logon:$LOGON_KEY_32_OK 0 $DEV 0" || fail sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail dmsetup remove $NAME || fail diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" # same test using message dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_XTS_PLAIN $HEXKEY_32 0 $DEV 0" || fail sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail dmsetup remove $NAME || fail dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_XTS_PLAIN $HEXKEY_32 0 $DEV 0" || fail dmsetup suspend $NAME || fail dmsetup message $NAME 0 key wipe || fail dmsetup message $NAME 0 "key set :32:logon:$LOGON_KEY_32_OK" || fail dmsetup resume $NAME || fail sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail dmsetup remove $NAME || fail diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" echo "OK" #test aes cipher, xts mode, essiv IV echo -n "Testing $CIPHER_CBC_ESSIV..." dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_ESSIV $HEXKEY_16 0 $DEV 0" || fail sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail dmsetup remove $NAME || fail load_key "$HEXKEY_16" logon $LOGON_KEY_16_OK "$TEST_KEYRING" || fail "Cannot load 16 byte logon key type" dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_ESSIV :16:logon:$LOGON_KEY_16_OK 0 $DEV 0" || fail sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail dmsetup remove $NAME || fail diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" # same test using message dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_ESSIV $HEXKEY_16 0 $DEV 0" || fail sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail dmsetup remove $NAME || fail dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_ESSIV $HEXKEY_16 0 $DEV 0" || fail dmsetup suspend $NAME || fail dmsetup message $NAME 0 key wipe || fail dmsetup message $NAME 0 "key set :16:logon:$LOGON_KEY_16_OK" || fail dmsetup resume $NAME || fail sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail dmsetup remove $NAME || fail diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" echo "OK" #test serpent cipher, cbc mode, tcw IV echo -n "Testing $CIPHER_CBC_TCW..." dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_TCW $HEXKEY_64 0 $DEV 0" || fail sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail dmsetup remove $NAME || fail load_key "$HEXKEY_64" logon $LOGON_KEY_64_OK "$TEST_KEYRING" || fail "Cannot load 16 byte logon key type" dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_TCW :64:logon:$LOGON_KEY_64_OK 0 $DEV 0" || fail sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail dmsetup remove $NAME || fail diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksum mismatch (corruption)" # same test using message dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_TCW $HEXKEY_64 0 $DEV 0" || fail sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail dmsetup remove $NAME || fail dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_TCW $HEXKEY_64 0 $DEV 0" || fail dmsetup suspend $NAME || fail dmsetup message $NAME 0 key wipe || fail dmsetup message $NAME 0 "key set :64:logon:$LOGON_KEY_64_OK" || fail dmsetup resume $NAME || fail sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail dmsetup remove $NAME || fail diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" echo "OK" echo -n "Test LUKS2 key refresh..." echo $PWD | $CRYPTSETUP luksFormat --type luks2 --luks2-metadata-size 16k --luks2-keyslots-size 4064k --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --force-password $DEV || fail echo $PWD | $CRYPTSETUP open $DEV $NAME || fail $CRYPTSETUP status $NAME | grep -q -i "location:.*keyring" || skip "LUKS2 can't use keyring. Test skipped." dd if=/dev/mapper/$NAME bs=1M iflag=direct status=none | sha1sum > $CHKS_KEYRING || fail echo $PWD | $CRYPTSETUP refresh $NAME --disable-keyring || fail $CRYPTSETUP status $NAME | grep -q -i "location:.*keyring" && fail "Key is still in keyring" dd if=/dev/mapper/$NAME bs=1M iflag=direct status=none | sha1sum > $CHKS_DMCRYPT || fail diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksum mismatch (corruption)" echo "OK" remove_mapping