#!/usr/bin/bash # # Copyright 2014 - 2024 Senderek Web Security, Ireland. All rights reserved. # # # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # # Author: Ralf Senderek # # license: GNU General Public License version 3 or higher # description: starts an encrypted filesystem on boot up via systemd # config: /etc/systemd/system/secureboot2.service # /etc/systemd/system/secureboot2-halt.service # /etc/systemd/system/securebootpassword # /usr/lib/secureboot/.rebootonfailure # date: 3/5/2024 TERMINAL=/dev/tty8 NAME=secure REBOOT="no" BASE=/usr/lib/secureboot FILE=securefilesystem LOOPDEVICE=$BASE/loopdevice LOG=$BASE/log BLOCKFILE=$BASE/.rebootonfailure # set SHORTCUT="yes" if you wish to use either a USB memory key or the USB DONGLE # make sure that your computer is used in a safe environment and remove the setting # when you move out of the safe environment ! # see /lib/secureboot/readme.OTP for details SHORTCUT="no" # old encrypted big files traditionally use ripemd160 to hash the passphrase in order to generate a AES key. CREATE="/sbin/cryptsetup open --type plain --cipher="aes-cbc-essiv:sha256" --key-size=256 --hash=ripemd160" # You can switch to sha256, if you create a new filesystem instead of using your old one. # DEFAULT ASKPASS=/bin/systemd-ask-password BOOTKEYDEVICE=/dev/sda1 BOOTKEY=/mnt/securebootkey TMPBOOTKEY=/tmp/securebootkey BOOTKEYHASH=$BASE/securebootkey.sha256 # print error message if permissions are not -r-------- root PERMS=$(/bin/ls -l /usr/lib/secureboot/secure.OTP | /bin/cut -c-10) if [[ $PERMS = "-r--------" ]] then . /usr/lib/secureboot/secure.OTP else echo "The permissions on /usr/lib/secureboot/secure.OTP must be -r--------" fi if [ ! -d /$NAME ] ; then /bin/mkdir /$NAME fi RET=0 ########################################################################## mounterror() { echo -en "\\0033[1;31m" echo "Mounting a secure filesystem failed." echo -en "\\0033[0;39m" } ########################################################################## errorreboot() { echo -en "\\0033[1;31m" echo "REBOOTING NOW ..." echo -en "\\0033[0;39m" } ########################################################################## success() { echo -en "\\0033[1;32m" echo "### SUCCESSFUL ###" echo -en "\\0033[0;39m" } ########################################################################## green() { echo -en "\\0033[1;32m" echo "### $1 ###" echo -en "\\0033[0;39m" } ########################################################################## orange() { echo -en "\\0033[1;33m" echo "### $1 ###" echo -en "\\0033[0;39m" } ########################################################################## cleanup(){ echo "Cleaning up ..." /sbin/losetup -a ls -l /dev/mapper/$NAME 2> /dev/null > /dev/null if [[ $? == 0 ]] then echo "Remove mapping ..." /sbin/cryptsetup remove $NAME fi if [[ -f $LOOPDEVICE ]] then echo "Remove loopdevice $LOOP ..." LOOP=$(cat $LOOPDEVICE 2> /dev/null ) /sbin/losetup -d $LOOP > /dev/null 2>&1 rm $LOOPDEVICE fi # get filename if it is a symlink LINK=$(ls -l $BASE/$FILE) FILENAME=${LINK##* } for D in $(/sbin/losetup -a | /bin/grep $FILENAME | cut -f1 -d:) do echo "Removing $D" losetup -d $D done } ########################################################################## haltfilesystem () { RET=0 LOOP=$(cat $LOOPDEVICE 2> /dev/null) echo echo "Unmounting the secure filesystem on /$NAME" mount | grep "on /$NAME " 2> /dev/null > /dev/null if [[ $? = 0 ]] then echo "Waiting for /secure to be removed ..." date > $LOG for X in $(/sbin/fuser -m /$NAME) do /bin/kill -9 $X 2>/dev/null done echo "trying to unmount /$NAME ..." >> $LOG /bin/umount -v /dev/mapper/$NAME >> $LOG 2>&1 /bin/mount | grep "on /$NAME" >> $LOG 2>&1 /bin/umount -v /dev/mapper/$NAME >> $LOG 2>&1 /bin/mount | grep "on /$NAME" >> $LOG 2>&1 /bin/umount -v /dev/mapper/$NAME >> $LOG 2>&1 /bin/mount | grep "on /$NAME" >> $LOG 2>&1 /bin/ls -l /dev/mapper/$NAME >> $LOG echo "removing cryptsetup ... " >> $LOG /sbin/cryptsetup close $NAME >> $LOG 2>&1 echo "removing losetup ... " >> $LOG /sbin/losetup -d $LOOP >> $LOG 2>&1 /sbin/losetup -a >> $LOG rm $LOOP 2> /dev/null echo "DONE." >> $LOG else echo "/$NAME is not mounted." cleanup RET=0 fi } ########################################################################## umountfilesystem () { RET=0 LOOP=$(cat $LOOPDEVICE 2> /dev/null) echo echo "Unmounting the secure filesystem on /$NAME" /bin/mount | grep "on /$NAME " 2> /dev/null > /dev/null if [[ $? = 0 ]] then echo "Trying to unmount /$NAME ..." /bin/umount -v /dev/mapper/$NAME /bin/mount | /bin/grep "on /$NAME " 2> /dev/null if [[ $? = 0 ]] then echo "Error: Cannot unmount /$NAME. Filesystem is busy." RET=3 else /bin/ls -l /dev/mapper/$NAME 2> /dev/null > /dev/null if [[ $? != 0 ]] then echo "No mapping for /$NAME exists." RET=0 else /sbin/cryptsetup remove $NAME [[ $? = 0 ]] && echo "Mapping removed ..." /sbin/losetup -d $LOOP [[ $? = 0 ]] && echo "Loop device removed ..." rm $LOOPDEVICE RET=0 fi fi else echo "/$NAME is not mounted." cleanup RET=0 fi } ########################################################################## mountfilesystem () { LOOP=$(losetup -f) RET=0 if /bin/mount | /bin/grep "on /$NAME " 2>&1 > /dev/null then echo "/$NAME is still mounted." RET=1 else echo "Setting up a secure filesystem on $LOOP" if [[ ! -f $BASE/$FILE ]] then echo "No crypto filesystem $NAME available." RET=2 else # create a loop device /sbin/losetup $LOOP $BASE/$FILE 2> /dev/null RET=$? if [[ $RET != 0 ]] then echo "Error : Cannot create loop device $LOOP." RET=3 else echo $LOOP > $LOOPDEVICE REBOOT="yes" RETV=1 # FIRST try USB key # USB is not mounted if [[ -b $BOOTKEYDEVICE ]] && [[ $SHORTCUT = "yes" ]] then echo "USB key ..." /bin/mount $BOOTKEYDEVICE /mnt 2> /dev/null if [[ -f $BOOTKEY ]] && [[ "x${OTP}" != "x" ]] then /bin/rm $TMPBOOTKEY 2> /dev/null /bin/sha256sum $BOOTKEY | cut -c-64 > $TMPBOOTKEY if /bin/diff $BOOTKEYHASH $TMPBOOTKEY 2> /dev/null > /dev/null then orange "Trying to read key from device" > $TERMINAL echo > $TERMINAL # get the passphrase from HEXOR PW=$($BASE/hexor $(cat $BOOTKEY) $OTP) echo $PW | ${CREATE} $LOOP $NAME RETV=$? KEYSOURCE=USB PW="7.,;sjiwudhhhee[wyr@#1teysm,mz" unset PW fi # destroy the temporary hashfile rm $TMPBOOTKEY 2> /dev/null else orange "USB device is not available" fi umount /mnt else RETV=5 fi if [[ $RETV != 0 ]] && [[ $SHORTCUT = "yes" ]] then echo "USB dongle ..." # if no $BOOTKEYDEVICE available # try USB dongle orange "Trying to read key from USB dongle" > $TERMINAL FINGERPRINT=$(lsusb | sha256sum | cut -c-40) PW=$($BASE/hexor $FINGERPRINT $USBOTP) # TEST is used to check if the recovered passphrase will work # As with using sha256 as the hash instead of ripemd160 hashing # only once would result to have the AES-key = sha256sum($PW) stored # in the root-readable file. # So hashing twice will protect both $PW and the AES-key TEST=$(echo -n "$PW" | sha256sum | sha256sum | cut -c-40) if [ "x$TEST" = "x$KEYHASH" ] then echo $PW | ${CREATE} $LOOP $NAME RETV=$? KEYSOURCE=DONGLE else orange "USB dongle is not available" RETV=7 fi if [[ $RETV != 0 ]] then /sbin/cryptsetup remove $NAME fi PW="7.,;sjiwudhhhee[wyr@#1teysm,mz" unset PW fi # try to catch a passphrase from user input if [[ $RETV != 0 ]] then green "Trying to read key from $TERMINAL " > $TERMINAL # try terminal green "Please enter your PASSPHRASE: " > $TERMINAL $ASKPASS " " < $TERMINAL | ${CREATE} $LOOP $NAME RETV=$? ls -l /dev/mapper/$NAME > $TERMINAL fi if [[ $RETV != 0 ]] then # cryptsetup failed echo "Error : Cannot create /dev/mapper/$NAME." orange "Error : Cannot create /dev/mapper/$NAME." /sbin/losetup -d $LOOP rm $LOOPDEVICE RET=4 else # fsck echo /sbin/fsck -y /dev/mapper/$NAME 2> /dev/null > /dev/null RETV=$? if [[ $RETV != 0 ]] then if [[ $KEYSOURCE = "USB" ]] then orange "The passphrase provided by the USB memory key is incorrect" fi if [[ $KEYSOURCE = "DONGLE" ]] then orange "The passphrase provided by the USB DONGLE is incorrect" orange "Please update USBOTP" fi fi # try to mount new filesystem /bin/mount /dev/mapper/$NAME /$NAME 2> /dev/null > /dev/null if [[ $? != 0 ]] then # mount failed umountfilesystem mounterror RET=5 if [[ $REBOOT == "yes" ]] then # REBOOT, if not blocked if [[ -f $BLOCKFILE ]] then errorreboot /sbin/reboot else echo echo " To stop the boot process here, " echo " create the file /usr/lib/secureboot/.rebootonfailure" echo fi fi else # everything is fine! green "/secure mounted successfully" > $TERMINAL /bin/df | /bin/grep /dev/mapper/$NAME RET=0 fi fi fi fi fi } ########################################################################## start() { mountfilesystem sleep 1 if [[ $RET = 0 ]] then success fi } ########################################################################## stop() { umountfilesystem echo if [[ $RET != 0 ]] then echo -en "\\0033[1;31m" echo "################ FAILED #################" echo -en "\\0033[0;39m" echo else echo -en "\\0033[1;32m" echo "################ REMOVED ################" echo -en "\\0033[0;39m" echo fi } ########################################################################## halt () { haltfilesystem } ########################################################################## restart() { stop start } case "$1" in start) start ;; stop) stop ;; halt) halt ;; cleanup) cleanup ;; restart) restart ;; force-reload) restart ;; *) echo "Usage: /usr/lib/secureboot/secureboot2 [start|stop|halt|cleanup|restart|force-reload]" exit 1 esac exit $RET