#!/bin/bash -ex

function cryptsetup ()
{
	sleep 1;
	command cryptsetup "$@";
	ret="$?";
	sleep 1; # udev...
	return $ret;
}

function cleanup ()
{
	umount /mnt || :;
	cryptsetup remove "$cname" || :;
	losetup -d "$blk";
}

trap "cleanup; echo FAILED" ERR

blk="/dev/loop94";
cname="_dev_loop94";
cblk="/dev/mapper/$cname";
p128="128bitsXXXXXXXXX"
p256="256bitsXXXXXXXXXXXXXXXXXXXXXXXXX"
p512="512bitsXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

rm -f t-crypt.fs;
truncate -s $[64*1048576] t-crypt.fs;
losetup "$blk" t-crypt.fs;

# Use of openssl key assumes dmcrypthash=plain
echo "TEST-k9-$LINENO";
echo -en "basekey" | openssl bf-cbc -pass pass:letmein >t-crypt.key;
openssl bf-cbc -d -pass pass:letmein <t-crypt.key | \
	cryptsetup -c serpent create "$cname" "$blk";
mkfs.ext4 "$cblk";
cryptsetup remove "$cname";
echo letmein | ./mount.crypt -vo fsk_cipher=bf-cbc,fsk_hash=md5,keyfile=t-crypt.key,cipher=serpent,hash=ripemd160,keysize=256 "$blk" /mnt;
PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;

# Test keysize interaction
echo "TEST-k8-$LINENO:";
dd if=/dev/urandom of=t-crypt.key bs=4k count=1;
echo basekey | cryptsetup luksFormat "$blk";
echo basekey | cryptsetup luksAddKey "$blk" t-crypt.key;
cryptsetup luksOpen --key-file t-crypt.key "$blk" "$cname";
mkfs.ext4 "$cblk";
cryptsetup luksClose "$cname";
./mount.crypt -vo keyfile=t-crypt.key,fsk_cipher=none "$blk" /mnt;
PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;

# Test keyfile passthru
echo "TEST-k7-$LINENO:";
echo -en "$p256" | cryptsetup luksFormat "$blk";
echo -en "$p256" | cryptsetup luksOpen "$blk" "$cname";
mkfs.ext4 "$cblk";
cryptsetup luksClose "$cname";
echo -en "$p256" >t-crypt.key;
./mount.crypt -vo keyfile=t-crypt.key,fsk_cipher=none "$blk" /mnt;
PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;

# test umount by container
echo "TEST-k6-$LINENO:";
./mount.crypt -vo keyfile=t-crypt.key,fsk_cipher=none "$blk" /mnt;
PMT_DEBUG_UMOUNT=1 ./umount.crypt "$blk";

# Test multiple key slots
echo "TEST-k5-$LINENO:";
echo -en "abc" | cryptsetup luksFormat "$blk";
echo -en "abc\nxyz\n" | cryptsetup luksAddKey "$blk";
echo -en "abc" | cryptsetup luksOpen "$blk" "$cname";
mkfs.ext4 "$cblk";
cryptsetup luksClose "$cname";
echo -en "abc" | ./mount.crypt -v "$blk" /mnt;
PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;
echo -en "xyz" | ./mount.crypt -v "$blk" /mnt;
PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;

xts_checks ()
{
	# we pick XTS here because it is one cipher that allows keysize=512
echo "TEST-k4-$LINENO:";
echo -en "$p512" | \
	cryptsetup --key-file=- -c aes-xts-plain \
	-h sha512 -s 512 create "$cname" "$blk";
mkfs.ext4 "$cblk";
cryptsetup remove "$cname";
echo -en "$p512" | \
	./mount.crypt -vo "hash=sha512,keysize=512,cipher=aes-xts-plain" \
	"$blk" /mnt;
PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;

echo "TEST-k3-$LINENO:";
echo -en "$p512" | \
	cryptsetup --key-file=- -c aes-xts-plain \
	-h plain -s 512 create "$cname" "$blk";
mkfs.ext4 "$cblk";
cryptsetup remove "$cname";
echo -en "$p512" | \
	./mount.crypt -vo "keysize=512,cipher=aes-xts-plain" \
	"$blk" /mnt;
PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;

# Test pmt-ehd style keyfile
echo "TEST-k2-$LINENO:";
echo -en "$p512" >/dev/shm/p512.key;
echo -en "$p512" | openssl bf-cbc -pass pass:abc >/dev/shm/p512.enc;
cryptsetup --key-file=/dev/shm/p512.key -c aes-xts-plain -h plain -s 512 \
	create "$cname" "$blk";
mkfs.ext4 "$cblk";
cryptsetup remove "$cname";
echo -en abc | \
	./mount.crypt -vo keyfile=/dev/shm/p512.enc,cipher=aes-xts-plain,fsk_cipher=bf-cbc,fsk_hash=md5 \
	"$blk" /mnt;
PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;

}

modprobe -q xts || :;
if grep -q '\b''xts''\b' /proc/crypto 2>/dev/null; then
	xts_checks
fi;

# Test implicit libcryptsetup truncation after hashing
echo "TEST-k1-$LINENO:";
for p in "short" "$p128" "$p256" "$p512"; do
	echo -en "$p" | cryptsetup --key-file=- -c aes-cbc-essiv:sha256 \
		-h sha512 create "$cname" "$blk";
	mkfs.ext4 "$cblk";
	cryptsetup remove "$cname";
	echo -en "$p" | ./mount.crypt -vo \
		hash=sha512,cipher=aes-cbc-essiv:sha256 "$blk" /mnt;
	PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;
done;

# Test truncation with various cipher block sizes
echo "TEST-k0-$LINENO:";
for ((k = 32; k <= 448; k += 8)); do
	echo -en "$p512" | cryptsetup --key-file=- -c blowfish \
		-h sha512 -s "$k" create "$cname" "$blk";
	mkfs.ext4 "$cblk";
	cryptsetup remove "$cname";
	echo -en "$p512" | ./mount.crypt -vo \
		"hash=sha512,keysize=$k,cipher=blowfish" \
		"$blk" /mnt;
	PMT_DEBUG_UMOUNT=1 ./umount.crypt /mnt;
done;

echo -e "\e[32m""All tests passed""\e[0m";
trap "" ERR;
cleanup;
