Skip to content

Wykorzystanie nośnika USB jako klucz do odszyfrowania dysku

Tworzenie klucza

Tworzymy ram disk na potrzeby wygenerowania klucz:

bash
mount -t tmpfs -o uid=root,gid=root,mode=1700,size=10M tmpfs /mnt

Generujemy losowy klucz:

bash
dd if=/dev/random of=/mnt/keyfile bs=1 count=4096

Dodajemy klucz do nagłówka LUKS:

bash
cryptsetup luksAddKey /dev/sda3 /mnt/keyfile --hash sha512

Zapisanie klucza w MBR-GAP

MBR-GAP to przestrzeń za tablicą partycji (pierwszym sektorem nośnika), której granicę wyznacza początek pierwszej partycji dysku. Zwykle partycje są równane do 1MiB, więc MBR-GAP w takim przypadku to 2047 sektorów 512-bajtowych. Tę przestrzeń trzeba zapisać losowymi danymi, po czym w którymś miejscu umieścić wcześniej wygenerowany keyfile. By mieć pewność, że to właśnie ten obszar trzeba wyczyścić, najlepiej sprawdzić offset pierwszej partycji przez fdisk:

bash
fdisk -l /dev/sdb

Czyścimy 2047 sektorów przy pomocy dd z pominięciem pierwszego, na którym znajduje się tablica partycji:

bash
dd if=/dev/urandom of=/dev/sdb bs=512 count=2047 seek=1

Wczytajmy tablicę partycji na nowo, by sprawdzić czy wszystko z nią jest w porządku:

bash
partprobe && fdisk -l /dev/sdb
console
...
Device     Boot Start      End  Sectors  Size Id Type
/dev/sdb1        2048 30433279 30431232 14.5G  c W95 FAT32 (LBA)

Wgrywamy teraz plik klucz gdzieś w obrębie tej przestrzeni MBR-GAP, np. na offset 100:

bash
dd if=/mnt/keyfile of=/dev/sdb bs=512 seek=100

Sprawdzamy czy udało się wgrać klucz w MBR-GAP:

bash
diff --report-identical-files <(cat /mnt/keyfile) <(dd if=/dev/sdb bs=512 skip=100 count=8 status=none | cat)

Skrypt odblokowujący partycję

Tworzymy skrypt, który posłuży nam do wykrywania i automatycznego odblokowywania partycji LUKS:

bash
touch /usr/sbin/unlock-luks && chmod +x /usr/sbin/unlock-luks

Zawartość pliku /usr/sbin/unlock-luks:

sh
#!/bin/sh

usbkey=/dev/disk/by-id/usb-Generic_Flash_Disk_61BCB9FD1EA4-0:0

# Waiting for the USB key will become available on the first unlock attempt
if [ ! -e /tmp/unlock-luks-first-attempt ]; then
	touch /tmp/unlock-luks-first-attempt

	for i in `seq 1 10`; do
		if [ -b $usbkey ]; then
			break
		fi

		echo "Waiting for USB key..." >&2
		sleep 1
	done
fi

# Attempting to unlock with a USB key
if [ -b $usbkey ]; then
	echo "Loading USB key..." >&2

	dd if=$usbkey bs=512 skip=100 count=8 | cat
	exit
fi

echo "FAILED to get USB key..." >&2

# Fallback to askpass
/lib/cryptsetup/askpass "Try LUKS password or insert USB key and press ENTER: "

Przykładowy fragment /etc/crypttab:

console
sda3_crypt UUID=8dea5878-fdf0-4cd2-bafc-b14f249c9436 none luks,discard,keyscript=/usr/sbin/unlock-luks

Zapisujemy zmiany i aktualizujemy obraz initramfs:

bash
update-initramfs -k all -u