public key for key on smartcard exported to ascii armor format or imported into gpg keyring
if you dont have this you may have to create new keys and certs for the smartcard
gpg --export > /etc/cryptsetup-initramfs/pubring.gpg
working system with LUKS encrypted root.
If you haven't set that up yet do so before using these instructions
gpg smartcard
the email address associated with the gpg private key on the smartcard
Install prerequisites
SET variables
create binary key
add binary key to LUKS
encrypt key with gpg
copy encrypted binary key to somewhere it can be accessed on boot
set boot to use the smartcard
update grub
if you want a faster recovery you may want to backup your current boot files with something like this
sudo tar -czf /boot/initrd.bak.tar /boot/initrd*
sudo apt install pinentry-tty pinentry-curses opensc scdaemon libccid pcscd pcsc-tools
These instructions work with some variables. The first is the luks root device. Set it in LUKS_DEV. In this example we are using the 27th partition on the first drive => sda27. Change as needed for your system.
LUKS_TARGET_DEV=/dev/sda27
Then we get the UUID associated with this device and the name of the luks mapper. It's the first column in /etc/crypttab for the root partition.
GUID=`sudo blkid -s UUID -o value $LUKS_TARGET_DEV`
NAME="$(awk -v guid="$GUID" '!/^[[:space:]]*#/ && NF && $2=="UUID=" guid {print $1; exit}' /etc/crypttab)"
create a binary key that will be added to a LUKS keyslot. I recommend putting this in a location with no hardware under it so that it minimizes risk of exposure. I've been using /run/
KEY=/run/user/1000/key
dd if=/dev/urandom of=$KEY bs=250 count=1
Now I add the new key to the encrypted LUKS root partition
sudo cryptsetup luksAddKey "${LUKS_TARGET_DEV}" ${KEY}
Next, I use the gpg public key to encrypt the binary key so that it can be stored anywhere safely. If this is the first time I use this I need to import the public key associated with the smartcard.
gpg --import /etc/cryptsetup-initramfs/pubring.gpg
gpg --trust-model=always --yes --default-recipient-self --encrypt --armor $KEY
I prefer to keep the public key and the encrypted luks key in /boot since it is not encyrpted on my system. I also put the encyrpted luks key into the template for the initial ram disk that is created for booting the system. If you have a process that copies these into the initrd you can put them wherever you want.
sudo mv $KEY.asc /etc/cryptsetup-initramfs/cryptkey.gpg
sudo cp /etc/cryptsetup-initramfs/cryptkey.gpg /boot
sudo cp /etc/cryptsetup-initramfs/pubring.gpg /boot
Now all the keys are all in place for use in the boot process. Add another line to /etc/crypttab and comment out the first line. Lastly, update the ramdisk to make it all work. might want to backup the current working ramdisk too.
if [ -z "$NAME" ] || [ -z "$GUID" ]; then
echo "Error! missing key information!"
else
sudo sed -i "s/^$NAME/#$NAME/g" /etc/crypttab
echo "$NAME UUID=$GUID /etc/cryptsetup-initramfs/cryptkey.gpg luks,keyscript=decrypt_gnupg-sc" | sudo tee -a /etc/crypttab
fi
If you are running a different kernel than you want because the one you were working on got trashed we dont want to trash the only working kernel. Here we will set the kernel version that we plan to update. then we will update the initrd. If you need to see the available kernels you may use this
find /boot -maxdepth 1 -type f \( -name 'vmlinuz-*' -o -name 'initrd.img-*' \) -printf '%f\n' | sed -E 's/^(vmlinuz-|initrd.img-)//' | sort -V | uniq
Now set the target and update
LUKS_TARGET_KERNEL=<my version>
sudo update-initramfs -u -k $LUKS_TARGET_KERNEL
If I was using grub to boot I would update grub to remove splash screen because otherwise I can't see the prompt for pin entry.
sudo su
sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"/GRUB_CMDLINE_LINUX_DEFAULT="quiet"/g' /etc/default/grub
update-grub
After a successful restart I customize the smartcard boot script to allow a fall back to passphrase.