dm-crypt.saout.de archive mirror
 help / color / mirror / Atom feed
* [dm-crypt] Opening a LUKS container using a USB drive
@ 2021-11-10 11:08 Mikhail Morfikov
  2021-11-10 22:40 ` [dm-crypt] " Mikhail Morfikov
  0 siblings, 1 reply; 2+ messages in thread
From: Mikhail Morfikov @ 2021-11-10 11:08 UTC (permalink / raw)
  To: dm-crypt

I've been trying to set up an encrypted LUKS container, which could be opened only when a specific 
USB device was plugged into the USB port. I partially achieved what I wanted, but there's one thing 
I couldn't figure out.

When I boot the system, it waits till I plug the right USB device in. When I do so, then it 
processes the device and decrypts the root files system, and the system boots as usual.

It starts with:

	Begin: Running /scripts/local-top...
	Waiting for device...

After plugging the USB device, I can see the following messages:

	sd 0:0:0:0 [sda] No Caching mode page found
	sd 0:0:0:0 [sda] Assuming drive cache: write through
	8+0 records in
	8+0 records out

It hangs here for a while because it tries to open the LUKS container which is an SD card, and it 
succeeds. 

Then I can see the following errors:

	Nothing to read on input
	cryptsetup: ERROR rpi_crypt: cryptsetup failed, bad password or options?
	8+0 records in
	8+0 records out
	Device rpi_crypt already exists
	Nothing to read on input
	....
	cryptsetup: ERROR rpi_crypt: maximum number of tries exceeded
	done
	Begin: Running /scripts/local-premount ... done
	...
	
After the last cryptsetup error, the system continues to boot without any issue and it works well. 
So what's wrong with it?



Here's the full setup.

I created the LUKSv2 container in the following way:

	# cryptsetup luksFormat /dev/mmcblk0p2 \
	  --type luks2 \
	  --cipher aes-xts-plain64 \
	  --key-size 512 \
	  --hash sha512 \
	  --pbkdf argon2i \
	  --pbkdf-force-iterations 4 \
	  --pbkdf-memory 524288 \
	  --pbkdf-parallel 2 \
	  --label rpi \
	  --subsystem "" \
	  --use-random \
	  --verify-passphrase \
	  --verbose
	  
And then I created an EXT4 file system:

	# cryptsetup luksOpen /dev/mmcblk0p2 rpi_crypt

	# mke2fs \
		-t ext4 \
		-m 0 \
		-L rootfs \
		-J size=128 \
		-O 64bit,has_journal,extents,huge_file,flex_bg,metadata_csum,dir_nlink,extra_isize,^resize_inode,^uninit_bg \
		-E lazy_itable_init=0,lazy_journal_init=0 \
		/dev/mapper/rpi_crypt

The SD card looks like this:

	# lsblk -o "NAME,SIZE,FSTYPE,TYPE,LABEL,MOUNTPOINT,UUID,PARTUUID" /dev/mmcblk0
	NAME           SIZE FSTYPE      TYPE  LABEL  MOUNTPOINT UUID                                 PARTUUID
	mmcblk0       28.8G             disk
	├─mmcblk0p1    256M vfat        part  boot              B05C-D0C4                            0d03b705-01
	└─mmcblk0p2   28.6G crypto_LUKS part  rpi               0b9b66eb-d5ec-4371-80e3-f3a6ae92e0be 0d03b705-02
	  └─rpi_crypt 28.6G ext4        crypt rootfs /media/rpi 0ca2062b-142b-4826-bb74-d465ca89b554

This is the /etc/fstab entry:

	UUID=0ca2062b-142b-4826-bb74-d465ca89b554  /   ext4    defaults,lazytime,errors=remount-ro  0 1

This is the /etc/crypttab entry:

	rpi_crypt  UUID=0b9b66eb-d5ec-4371-80e3-f3a6ae92e0be   none  luks,keyscript=/usr/sbin/unlock-rpi,initramfs,keyslot=1

In the kernel cmdline I added luks.crypttab=no to disable the systemd cryptsetup generator as it 
doesn't support many crypttab options.

The LUKS container can be opened at boot without issues when the luks,initramfs options are 
specified in /etc/crypttab , but in this way I would have to enter the password manually each time I
boot the system, and my RPI doesn't have a keyboard connected. Instead I wanted to use a USB 
drive to open the LUKS container. I mean the device is used in this process and not a keyfile 
that sits inside of the device's file system. That's why I used keyscript=/usr/sbin/unlock-rpi in 
/etc/crypttab . Here's the content of the script:

	#!/bin/sh

	dd if=/dev/usbkey bs=512 skip=100 count=8 | \
	 cryptsetup luksOpen /dev/mmcblk0p2 rpi_crypt --key-file=-

To get the /dev/usbkey device, I have the following UDEV rule:

	ACTION=="add", KERNEL=="sd?", \
	 ENV{ID_SERIAL_SHORT}=="0019E06B9C8ABE41C7A2C3EC", \
	 SYMLINK+="usbkey%n"
	 
So the script reads the 4096 bytes starting at certain point of the pendrive, then it hands the 
data to cryptsetup and the device can be unlocked.

Both of the files are included in the initramfs/initrd image.

The keyfile was added to the LUKS header in the following way:

	# dd if=/dev/random of=/tmp-ram/keyfile bs=1 count=4096
	# cryptsetup luksAddKey /dev/mmcblk0p2 /tmp-ram/keyfile --hash sha512
	# cryptsetup luksDump /dev/mmcblk0p2
	LUKS header information
	...
	  1: luks2
		Key:        512 bits
		Priority:   normal
		Cipher:     aes-xts-plain64
		Cipher key: 512 bits
		PBKDF:      argon2i
		Time cost:  4
		Memory:     185496
		Threads:    4
		Salt:       79 04 9f 36 26 2f da 5d 1c c0 a1 be 8a 73 6f c5 
					d8 c7 55 97 a0 cf ee 5c ec ae 20 11 06 d0 27 62 
		AF stripes: 4000
		AF hash:    sha512
		Area offset:290816 [bytes]
		Area length:258048 [bytes]
		Digest ID:  0
	...

Since the keyfile was added to the keyslot number 1, I used also the keyslot=1 option in 
/etc/crypttab.

The keyfile was also burned to the pendrive using the following commands:

	# dd if=/dev/urandom of=/dev/sda bs=512 count=2047 seek=1
	# dd if=/tmp-ram/keyfile of=/dev/sda bs=512 seek=100

To make all this work, I had to add two things to the initramfs/initrd image: 1) a hook, 2) a 
script:

Here's the /etc/initramfs-tools/hooks/unlock-rpi hook, which copies the keyscript to the image:

	#!/bin/sh

	set -e

	PREREQ=""
	prereqs()
	{
	   echo "$PREREQ"
	}

	case $1 in
	prereqs)
	   prereqs
	   exit 0
	   ;;
	esac

	[ -r /usr/share/initramfs-tools/hook-functions ] || exit 0
	. /usr/share/initramfs-tools/hook-functions

	copy_exec /usr/local/bin/unlock-rpi /usr/sbin/
	chmod +x  /usr/sbin/unlock-rpi

And here's the /etc/initramfs-tools/scripts/local-top/delay-decrypt' script, which delays the boot 
process till the right USB device is plugged in (since I created a link to the block device, I had 
to check for link and not for the block device):

	#!/bin/sh

	PREREQ="udev"
	prereqs()
	{
	   echo "$PREREQ"
	}

	case $1 in
	prereqs)
	   prereqs
	   exit 0
	   ;;
	esac

	# source for log_*_msg() functions, see LP: #272301
	. /scripts/functions

	# Default PATH differs between shells, and is not automatically exported
	# by klibc dash.  Make it consistent.
	export PATH=/sbin:/usr/sbin:/bin:/usr/bin

	DEVICE=/dev/usbkey
	if [ ! -L "$DEVICE" ]; then
		echo -e "\nWaiting for device..." >&2
		until [ -L "$DEVICE" ]; do
			sleep 1
		done
	fi

	exit 0

So what's wrong with this setup, and why it tries to open the LUKS container multiple times even 
when it succeeds for the very first time after the USB device was plugged in?
_______________________________________________
dm-crypt mailing list -- dm-crypt@saout.de
To unsubscribe send an email to dm-crypt-leave@saout.de

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [dm-crypt] Re: Opening a LUKS container using a USB drive
  2021-11-10 11:08 [dm-crypt] Opening a LUKS container using a USB drive Mikhail Morfikov
@ 2021-11-10 22:40 ` Mikhail Morfikov
  0 siblings, 0 replies; 2+ messages in thread
From: Mikhail Morfikov @ 2021-11-10 22:40 UTC (permalink / raw)
  To: dm-crypt

Ok, I've managed to solved this issue. The problem was in the decription script, so instead of the 
following: 

    dd if=/dev/usbkey bs=512 skip=100 count=8 | \
    cryptsetup luksOpen /dev/mmcblk0p2 rpi_crypt --key-file=-

it should be just:

    dd if=/dev/usbkey bs=512 skip=100 count=8

Since the output of the script itself is passed to cryptsetup, the piped cryptsetup command isn't 
needed anymore.

Also the initramfs hook is useless, as the keyscript will be copied if it's present in the same 
location pointed by the option. So for instance keyscript=/usr/sbin/unlock-rpi requires the script 
to be under /usr/sbin/unlock-rpi in the encrypted system, and it will be copied automatically to 
initramfs/initrd image.


On 10/11/2021 12.08, Mikhail Morfikov wrote:
> I've been trying to set up an encrypted LUKS container, which could be opened only when a specific 
> USB device was plugged into the USB port. I partially achieved what I wanted, but there's one thing 
> I couldn't figure out.
> 
> When I boot the system, it waits till I plug the right USB device in. When I do so, then it 
> processes the device and decrypts the root files system, and the system boots as usual.
> 
> It starts with:
> 
> 	Begin: Running /scripts/local-top...
> 	Waiting for device...
> 
> After plugging the USB device, I can see the following messages:
> 
> 	sd 0:0:0:0 [sda] No Caching mode page found
> 	sd 0:0:0:0 [sda] Assuming drive cache: write through
> 	8+0 records in
> 	8+0 records out
> 
> It hangs here for a while because it tries to open the LUKS container which is an SD card, and it 
> succeeds. 
> 
> Then I can see the following errors:
> 
> 	Nothing to read on input
> 	cryptsetup: ERROR rpi_crypt: cryptsetup failed, bad password or options?
> 	8+0 records in
> 	8+0 records out
> 	Device rpi_crypt already exists
> 	Nothing to read on input
> 	....
> 	cryptsetup: ERROR rpi_crypt: maximum number of tries exceeded
> 	done
> 	Begin: Running /scripts/local-premount ... done
> 	...
> 	
> After the last cryptsetup error, the system continues to boot without any issue and it works well. 
> So what's wrong with it?
> 
> 
> 
> Here's the full setup.
> 
> I created the LUKSv2 container in the following way:
> 
> 	# cryptsetup luksFormat /dev/mmcblk0p2 \
> 	  --type luks2 \
> 	  --cipher aes-xts-plain64 \
> 	  --key-size 512 \
> 	  --hash sha512 \
> 	  --pbkdf argon2i \
> 	  --pbkdf-force-iterations 4 \
> 	  --pbkdf-memory 524288 \
> 	  --pbkdf-parallel 2 \
> 	  --label rpi \
> 	  --subsystem "" \
> 	  --use-random \
> 	  --verify-passphrase \
> 	  --verbose
> 	  
> And then I created an EXT4 file system:
> 
> 	# cryptsetup luksOpen /dev/mmcblk0p2 rpi_crypt
> 
> 	# mke2fs \
> 		-t ext4 \
> 		-m 0 \
> 		-L rootfs \
> 		-J size=128 \
> 		-O 64bit,has_journal,extents,huge_file,flex_bg,metadata_csum,dir_nlink,extra_isize,^resize_inode,^uninit_bg \
> 		-E lazy_itable_init=0,lazy_journal_init=0 \
> 		/dev/mapper/rpi_crypt
> 
> The SD card looks like this:
> 
> 	# lsblk -o "NAME,SIZE,FSTYPE,TYPE,LABEL,MOUNTPOINT,UUID,PARTUUID" /dev/mmcblk0
> 	NAME           SIZE FSTYPE      TYPE  LABEL  MOUNTPOINT UUID                                 PARTUUID
> 	mmcblk0       28.8G             disk
> 	├─mmcblk0p1    256M vfat        part  boot              B05C-D0C4                            0d03b705-01
> 	└─mmcblk0p2   28.6G crypto_LUKS part  rpi               0b9b66eb-d5ec-4371-80e3-f3a6ae92e0be 0d03b705-02
> 	  └─rpi_crypt 28.6G ext4        crypt rootfs /media/rpi 0ca2062b-142b-4826-bb74-d465ca89b554
> 
> This is the /etc/fstab entry:
> 
> 	UUID=0ca2062b-142b-4826-bb74-d465ca89b554  /   ext4    defaults,lazytime,errors=remount-ro  0 1
> 
> This is the /etc/crypttab entry:
> 
> 	rpi_crypt  UUID=0b9b66eb-d5ec-4371-80e3-f3a6ae92e0be   none  luks,keyscript=/usr/sbin/unlock-rpi,initramfs,keyslot=1
> 
> In the kernel cmdline I added luks.crypttab=no to disable the systemd cryptsetup generator as it 
> doesn't support many crypttab options.
> 
> The LUKS container can be opened at boot without issues when the luks,initramfs options are 
> specified in /etc/crypttab , but in this way I would have to enter the password manually each time I
> boot the system, and my RPI doesn't have a keyboard connected. Instead I wanted to use a USB 
> drive to open the LUKS container. I mean the device is used in this process and not a keyfile 
> that sits inside of the device's file system. That's why I used keyscript=/usr/sbin/unlock-rpi in 
> /etc/crypttab . Here's the content of the script:
> 
> 	#!/bin/sh
> 
> 	dd if=/dev/usbkey bs=512 skip=100 count=8 | \
> 	 cryptsetup luksOpen /dev/mmcblk0p2 rpi_crypt --key-file=-
> 
> To get the /dev/usbkey device, I have the following UDEV rule:
> 
> 	ACTION=="add", KERNEL=="sd?", \
> 	 ENV{ID_SERIAL_SHORT}=="0019E06B9C8ABE41C7A2C3EC", \
> 	 SYMLINK+="usbkey%n"
> 	 
> So the script reads the 4096 bytes starting at certain point of the pendrive, then it hands the 
> data to cryptsetup and the device can be unlocked.
> 
> Both of the files are included in the initramfs/initrd image.
> 
> The keyfile was added to the LUKS header in the following way:
> 
> 	# dd if=/dev/random of=/tmp-ram/keyfile bs=1 count=4096
> 	# cryptsetup luksAddKey /dev/mmcblk0p2 /tmp-ram/keyfile --hash sha512
> 	# cryptsetup luksDump /dev/mmcblk0p2
> 	LUKS header information
> 	...
> 	  1: luks2
> 		Key:        512 bits
> 		Priority:   normal
> 		Cipher:     aes-xts-plain64
> 		Cipher key: 512 bits
> 		PBKDF:      argon2i
> 		Time cost:  4
> 		Memory:     185496
> 		Threads:    4
> 		Salt:       79 04 9f 36 26 2f da 5d 1c c0 a1 be 8a 73 6f c5 
> 					d8 c7 55 97 a0 cf ee 5c ec ae 20 11 06 d0 27 62 
> 		AF stripes: 4000
> 		AF hash:    sha512
> 		Area offset:290816 [bytes]
> 		Area length:258048 [bytes]
> 		Digest ID:  0
> 	...
> 
> Since the keyfile was added to the keyslot number 1, I used also the keyslot=1 option in 
> /etc/crypttab.
> 
> The keyfile was also burned to the pendrive using the following commands:
> 
> 	# dd if=/dev/urandom of=/dev/sda bs=512 count=2047 seek=1
> 	# dd if=/tmp-ram/keyfile of=/dev/sda bs=512 seek=100
> 
> To make all this work, I had to add two things to the initramfs/initrd image: 1) a hook, 2) a 
> script:
> 
> Here's the /etc/initramfs-tools/hooks/unlock-rpi hook, which copies the keyscript to the image:
> 
> 	#!/bin/sh
> 
> 	set -e
> 
> 	PREREQ=""
> 	prereqs()
> 	{
> 	   echo "$PREREQ"
> 	}
> 
> 	case $1 in
> 	prereqs)
> 	   prereqs
> 	   exit 0
> 	   ;;
> 	esac
> 
> 	[ -r /usr/share/initramfs-tools/hook-functions ] || exit 0
> 	. /usr/share/initramfs-tools/hook-functions
> 
> 	copy_exec /usr/local/bin/unlock-rpi /usr/sbin/
> 	chmod +x  /usr/sbin/unlock-rpi
> 
> And here's the /etc/initramfs-tools/scripts/local-top/delay-decrypt' script, which delays the boot 
> process till the right USB device is plugged in (since I created a link to the block device, I had 
> to check for link and not for the block device):
> 
> 	#!/bin/sh
> 
> 	PREREQ="udev"
> 	prereqs()
> 	{
> 	   echo "$PREREQ"
> 	}
> 
> 	case $1 in
> 	prereqs)
> 	   prereqs
> 	   exit 0
> 	   ;;
> 	esac
> 
> 	# source for log_*_msg() functions, see LP: #272301
> 	. /scripts/functions
> 
> 	# Default PATH differs between shells, and is not automatically exported
> 	# by klibc dash.  Make it consistent.
> 	export PATH=/sbin:/usr/sbin:/bin:/usr/bin
> 
> 	DEVICE=/dev/usbkey
> 	if [ ! -L "$DEVICE" ]; then
> 		echo -e "\nWaiting for device..." >&2
> 		until [ -L "$DEVICE" ]; do
> 			sleep 1
> 		done
> 	fi
> 
> 	exit 0
> 
> So what's wrong with this setup, and why it tries to open the LUKS container multiple times even 
> when it succeeds for the very first time after the USB device was plugged in?
> 
_______________________________________________
dm-crypt mailing list -- dm-crypt@saout.de
To unsubscribe send an email to dm-crypt-leave@saout.de

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-11-10 22:43 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-10 11:08 [dm-crypt] Opening a LUKS container using a USB drive Mikhail Morfikov
2021-11-10 22:40 ` [dm-crypt] " Mikhail Morfikov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).