initial commit

master
Gaspar Chilingarov 7 years ago
parent 58812f2668
commit 1490d1e858

@ -1,2 +1,81 @@
# ubuntu-luks-autounlock
Scripts to automatically unlock LUKS encrypted partitions based on machine environment
# Ubuntu LUKS auto unlock
## Do not miss information
This is part of educational materials about Ubuntu administration from my site
[http://gasparchilingarov.com/](http://gasparchilingarov.com).
Click link and subscibe to mailing list to start learning today.
## Purpose
This script is intended to help unlocking Ubuntu system encrypted disks
automatically when it is used in known environment (at home). In all other
environments it will still ask for passwords to unlock disks.
This setup intends to protect system **only from accidental laptop theft**. If you are
potential hacking target - do not use it, your data may be at risk.
Right now scripts take into account:
* MAC address of your Wifi network
* information from your external display
If you use it without external monitor (it will pick up your build-in monitor
information) there is a risk someone can guess/scan your Wifi and find out
MAC address and be able to generate correct decryption key, so do not use it.
## Compatibility
Scripts are tested on Ubuntu 16.04 64-bit only. Use it on your own risk on other systems.
## Usage
Copy files from repository to corresponding directories on your Ubuntu system.
Run `/usr/local/bin/autounlock_install_dependency.sh` to install necessary
dependencies.
Configure your Wifi interface (most probably "wlan0"), Wifi network name and
LUKS partition key slot number in `/usr/local/etc/auto_unlock.conf`.
You can run `cryptsetup luksDump /dev/sdXXXX` to check which slots are free on
your encrypted partitions. LUKS partition can have up to 8 keys for
decyphering. Key slot `0` is used by default for your manually entered password
and cannot be used to auto-unlock.
Run `/usr/local/bin/autounlock_install_key.sh` to add or update keys on all
LUKS partitions defined in `/etc/crypttab`. Follow script prompts to finish setup.
## Add boot scripts
After adding keys to partitions you need to add correspondig scripts to do auto
unlock into initramfs.
You need to have scripts in corresponding directories under `/etc/initramfs-tools/`.
Run `update-initramfs -k all -u` to update all kernel images.
## Try it out
Reboot :) If everything went smoothly - your system will boot without asking passwords at all.
Try disconnecting external monitor or turning off Wifi and rebooting again to
confirm that it asks for password to decode partitions.
## Removing extra keys
If you want to remove auto-unlock keys use `cryptsetup luksKillSlot /dev/sdaXXXX KEYSLOT`.
KEYSLOT should be same slot you used while setting up auto-unlock keys. Do not
delete occasionally other slots, as you may be locked out of your system.
## Extra sources of information
Adding extra information sources is pretty straightforward - just keep it in
sync between `etc/initramfs-tools/scripts/local-top/cryptroot-prepare:gather_key_information()`
and `usr/local/bin/autounlock_install_key.sh`. If you need extra
binaries/drivers in initramfs - add them into
`etc/initramfs-tools/hooks/prepare_auto_unlock_deps` script.

@ -0,0 +1,64 @@
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
# These prerequisites are provided by the read-edid package.
COPY_EXEC_LIST="/usr/bin/get-edid /usr/bin/parse-edid"
# These prerequisites are provided by the base system.
COPY_EXEC_LIST="$COPY_EXEC_LIST /sbin/iwlist"
# Explicitly specify all kernel modules because automatic dependency resolution
# is unreliable on many systems.
MANUAL_ADD_MODULES_LIST="iwlwifi iwlmvm iwldvm mac80211 cfg80211"
echo "Adding $MANUAL_ADD_MODULES_LIST for network detection"
# Generic result code.
RC=0
case $1 in
prereqs)
prereqs
exit 0
;;
esac
for ii in $COPY_EXEC_LIST
do
if [ ! -x "$ii" ]
then
echo "Error: $ii is not executable."
RC=2
fi
done
if [ "$RC" -ne 0 ]
then
exit "$RC"
fi
. /usr/share/initramfs-tools/hook-functions
for ii in $COPY_EXEC_LIST
do
copy_exec "$ii"
done
for ii in $MANUAL_ADD_MODULES_LIST
do
manual_add_modules "$ii"
done
mkdir -p ${DESTDIR}/lib/firmware
for ii in `find /lib/firmware/ -name 'iwlwifi-*'`
do
cp -p $ii ${DESTDIR}/lib/firmware/
done
mkdir -p ${DESTDIR}/etc
cp -p /usr/local/etc/auto_unlock.conf ${DESTDIR}/etc/auto_unlock.conf

@ -0,0 +1,338 @@
#!/bin/sh
PREREQ=""
#
# Standard initramfs preamble
#
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
# source for log_*_msg() functions, see LP: #272301
. /scripts/functions
#
# Helper functions
#
message()
{
if [ -x /bin/plymouth ] && plymouth --ping; then
plymouth message --text="$@"
else
echo "$@" >&2
fi
return 0
}
udev_settle()
{
# Wait for udev to be ready, see https://launchpad.net/bugs/85640
if command -v udevadm >/dev/null 2>&1; then
udevadm settle --timeout=30
elif command -v udevsettle >/dev/null 2>&1; then
udevsettle --timeout=30
fi
return 0
}
parse_options()
{
local cryptopts
cryptopts="$1"
if [ -z "$cryptopts" ]; then
return 1
fi
# Defaults
cryptcipher=aes-cbc-essiv:sha256
cryptsize=256
crypthash=ripemd160
crypttarget=cryptroot
cryptsource=""
cryptheader=""
cryptlvm=""
cryptkeyscript=""
cryptkey="" # This is only used as an argument to an eventual keyscript
crypttries=3
crypttcrypt=""
cryptrootdev=""
cryptdiscard=""
CRYPTTAB_OPTIONS=""
local IFS=" ,"
for x in $cryptopts; do
case $x in
hash=*)
crypthash=${x#hash=}
;;
size=*)
cryptsize=${x#size=}
;;
cipher=*)
cryptcipher=${x#cipher=}
;;
target=*)
crypttarget=${x#target=}
export CRYPTTAB_NAME="$crypttarget"
;;
source=*)
cryptsource=${x#source=}
if [ ${cryptsource#UUID=} != $cryptsource ]; then
cryptsource="/dev/disk/by-uuid/${cryptsource#UUID=}"
elif [ ${cryptsource#LABEL=} != $cryptsource ]; then
cryptsource="/dev/disk/by-label/${cryptsource#LABEL=}"
fi
export CRYPTTAB_SOURCE="$cryptsource"
;;
header=*)
cryptheader=${x#header=}
if [ ! -e "$cryptheader" ] && [ -e "/conf/conf.d/cryptheader/$cryptheader" ]; then
cryptheader="/conf/conf.d/cryptheader/$cryptheader"
fi
export CRYPTTAB_HEADER="$cryptheader"
;;
lvm=*)
cryptlvm=${x#lvm=}
;;
keyscript=*)
cryptkeyscript=${x#keyscript=}
;;
key=*)
if [ "${x#key=}" != "none" ]; then
cryptkey=${x#key=}
fi
export CRYPTTAB_KEY="$cryptkey"
;;
tries=*)
crypttries="${x#tries=}"
case "$crypttries" in
*[![:digit:].]*)
crypttries=3
;;
esac
;;
tcrypt)
crypttcrypt="yes"
;;
rootdev)
cryptrootdev="yes"
;;
discard)
cryptdiscard="yes"
;;
esac
PARAM="${x%=*}"
if [ "$PARAM" = "$x" ]; then
VALUE="yes"
else
VALUE="${x#*=}"
fi
CRYPTTAB_OPTIONS="$CRYPTTAB_OPTIONS $PARAM"
eval export CRYPTTAB_OPTION_$PARAM="\"$VALUE\""
done
export CRYPTTAB_OPTIONS
if [ -z "$cryptsource" ]; then
message "cryptsetup: source parameter missing"
return 1
fi
return 0
}
activate_vg()
{
# Sanity checks
if [ ! -x /sbin/lvm ]; then
message "cryptsetup: lvm is not available"
return 1
fi
# Detect and activate available volume groups
/sbin/lvm vgscan
/sbin/lvm vgchange -a y --sysinit
return $?
}
setup_mapping()
{
local opts count cryptopen cryptremove NEWROOT
opts="$1"
if [ -z "$opts" ]; then
return 0
fi
parse_options "$opts" || return 1
# The same target can be specified multiple times
# e.g. root and resume lvs-on-lvm-on-crypto
if [ -e "/dev/mapper/$crypttarget" ]; then
return 0
fi
modprobe -q dm_crypt
# Make sure the cryptsource device is available
if [ ! -e $cryptsource ]; then
activate_vg
fi
# If the encrypted source device hasn't shown up yet, give it a
# little while to deal with removable devices
# the following lines below have been taken from
# /usr/share/initramfs-tools/scripts/local, as suggested per
# https://launchpad.net/bugs/164044
if [ ! -e "$cryptsource" ]; then
log_begin_msg "Waiting for encrypted source device..."
# Default delay is 180s
if [ -z "${ROOTDELAY}" ]; then
slumber=180
else
slumber=${ROOTDELAY}
fi
slumber=$(( ${slumber} * 10 ))
while [ ! -e "$cryptsource" ]; do
# retry for LVM devices every 10 seconds
if [ ${slumber} -eq $(( ${slumber}/100*100 )) ]; then
activate_vg
fi
/bin/sleep 0.1
slumber=$(( ${slumber} - 1 ))
[ ${slumber} -gt 0 ] || break
done
if [ ${slumber} -gt 0 ]; then
log_end_msg 0
else
log_end_msg 1 || true
fi
fi
udev_settle
# We've given up, but we'll let the user fix matters if they can
if [ ! -e "${cryptsource}" ]; then
echo " ALERT! ${cryptsource} does not exist."
echo " Check cryptopts=source= bootarg: cat /proc/cmdline"
echo " or missing modules, devices: cat /proc/modules; ls /dev"
panic -r "Dropping to a shell. Will skip ${cryptsource} if you can't fix."
fi
if [ ! -e "${cryptsource}" ]; then
return 1
fi
# Prepare commands
cryptopen="/sbin/cryptsetup -T 1"
if [ "$cryptdiscard" = "yes" ]; then
cryptopen="$cryptopen --allow-discards"
fi
if [ -n "$cryptheader" ]; then
cryptopen="$cryptopen --header=$cryptheader"
fi
if /sbin/cryptsetup isLuks ${cryptheader:-$cryptsource} >/dev/null 2>&1; then
cryptopen="$cryptopen open --type luks $cryptsource $crypttarget --key-file=-"
elif [ "$crypttcrypt" = "yes" ]; then
cryptopen="$cryptopen open --type tcrypt $cryptsource $crypttarget"
else
cryptopen="$cryptopen -c $cryptcipher -s $cryptsize -h $crypthash open --type plain $cryptsource $crypttarget --key-file=-"
fi
cryptremove="/sbin/cryptsetup remove $crypttarget"
NEWROOT="/dev/mapper/$crypttarget"
# Try to get a satisfactory password $crypttries times
count=0
crypttries=1
while [ $crypttries -le 0 ] || [ $count -lt $crypttries ]; do
export CRYPTTAB_TRIED="$count"
count=$(( $count + 1 ))
cryptkeyscript="/bin/cat"
cryptkey="$LOCK_FILE"
if [ ! -e "$NEWROOT" ]; then
if ! crypttarget="$crypttarget" cryptsource="$cryptsource" \
$cryptkeyscript "$cryptkey" | $cryptopen; then
message "autounlock: cryptsetup failed, gathred bad key?"
break
fi
fi
if [ ! -e "$NEWROOT" ]; then
message "cryptsetup: unknown error setting up device mapping"
return 1
fi
message "cryptsetup: $crypttarget set up successfully"
break
done
if [ $crypttries -gt 0 ] && [ $count -gt $crypttries ]; then
message "cryptsetup: maximum number of tries exceeded for $crypttarget"
return 1
fi
udev_settle
return 0
}
# Look into phisical environment around and gather information
gather_key_information()
{
if [ ! -f "/etc/auto_unlock.conf" ]; then
log_failure_msg "Auto-unlock does not have config in initramfs"
exit 0
fi
. /etc/auto_unlock.conf
udev_settle
# gather local Wifi MAC
ifconfig $WIFI_INTERFACE up
WIFI_MAC=`iwlist scanning 2>/dev/null | egrep 'Address|ESSID' | grep -B1 'ESSID:"'"${WIFI_NETWORK}"'"' | awk -F'Address: ' '/Address/ {print $2}'`
# gather external monitor EDID info
EDID_LINES=`get-edid 2>/dev/null | parse-edid | egrep 'Identifier|ModelName|VendorName|Manufactured week|DisplaySize' | LANG=C sort`
echo -e "$WIFI_MAC\n$EDID_LINES" > $LOCK_FILE
}
finish()
{
rm -f $LOCK_FILE
}
#
# Begin real processing
#
# Acquire potential key from connected devices
LOCK_FILE=/conf/autounlock.key
trap finish EXIT
gather_key_information
# Do we have any settings from the /conf/conf.d/cryptroot file?
if [ -r /conf/conf.d/cryptroot ]; then
while read mapping <&3; do
setup_mapping "$mapping" 3<&-
done 3< /conf/conf.d/cryptroot
fi
exit 0

@ -0,0 +1,3 @@
#!/bin/sh
apt install read-edid

@ -0,0 +1,100 @@
#!/bin/bash
mkdir -p /run/keytemp
LOCK_FILE="/run/keytemp/lock_key"
function finish {
rm -f $LOCK_FILE
}
trap finish EXIT
echo "Generates key based on your Wifi MAC address and infromation from your external monitor"
echo "If you do not have external monitor attached, please turn it off in /usr/local/etc/auto_unlock.conf"
echo "It can decrease security of auto unlock because Wifi MAC is visible to everyone in proximity of your location."
. /usr/local/etc/auto_unlock.conf
if [ "$KEYSLOT" = "0" ]; then
echo "Cannot use key slot 0"
exit 10
fi
echo "Looking up AP MAC for Wifi network $WIFI_NETWORK"
WIFI_MAC=`iwlist scanning 2>/dev/null | egrep 'Address|ESSID' | grep -B1 'ESSID:"'"${WIFI_NETWORK}"'"' | awk -F'Address: ' '/Address/ {print $2}'`
echo "Found MAC == |$WIFI_MAC| "
EDID_LINES=`get-edid 2>/dev/null | parse-edid | egrep 'Identifier|ModelName|VendorName|Manufactured week|DisplaySize' | LANG=C sort `
echo "Gathered display information"
echo -e "--------\n${EDID_LINES}\n-----------\n"
echo "Please verify that Wifi MAC of Access Point and display information are valid"
echo "Especially verify that your external display is recognized, not build-in one"
echo "Type in YES to set-up LUKS key based on information above"
read ANSWER
if [ "$ANSWER" != "YES" ]; then
echo "Exiting without setup"
exit 5
fi
echo -e "$WIFI_MAC\n$EDID_LINES" > $LOCK_FILE
echo "Checksum of lockfile $(md5sum $LOCK_FILE)"
echo "Stored lock file in $LOCK_FILE, please delete it manually if you cancel script execution"
echo "Parsing /etc/crypttab"
for TEXT in $(awk '/^..*$/ {print $1 ":" $2}' /etc/crypttab); do
NAME=`echo "$TEXT" | cut -d: -f1`
DEVICE=`echo "$TEXT" | cut -d: -f2`
case $DEVICE in
/dev/*) ;;
UUID=*) UUID=${DEVICE##UUID=}
DEVICE=$(blkid -U "$UUID")
;;
esac
if [ -z "$DEVICE" ]; then
continue
fi
echo "found partition $DEVICE for $NAME"
if [ ! -b $DEVICE ]; then
echo "Cannot work on $DEVICE, not a block device"
continue
fi
SLOTS=`cryptsetup luksDump $DEVICE | grep '^Key Slot'`
SLOT_USAGE=`echo "$SLOTS" | grep "Key Slot $KEYSLOT"`
echo -e "slots usage for $DEVICE\n------\n${SLOTS}\n---------\n"
SLOT_OK=
case "$SLOT_USAGE" in
*DISABLED) SLOT_OK=1 ;;
*ENABLED)
echo "Slot $KEYSLOT is used for device $NAME $DEVICE"
echo "Do you want to override it? Type YES to override"
read ANSWER
if [ "$ANSWER" != "YES" ]; then
echo "Not overriding ..."
continue
fi
cryptsetup luksKillSlot $DEVICE $KEYSLOT
SLOT_OK=1
esac
if [ "$SLOT_OK" = "1" ]; then
cryptsetup luksAddKey --key-slot $KEYSLOT $DEVICE $LOCK_FILE
fi
done

@ -0,0 +1,3 @@
WIFI_INTERFACE="wlan0"
WIFI_NETWORK="YOUR_NETWORK_NAME"
KEYSLOT=7
Loading…
Cancel
Save