None of us will every accomplish anything excellent or commanding except when he listens to this whisper which is heard by him alone.”
~Ralph Waldo Emerson

lukstool.sh

Google+ Pinterest LinkedIn Tumblr +

I wrote this program a number of years ago because I was frustrated about the fact that all encryption offered to the public (no matter what the operating system or app) used minimal strength encryption by default.  This remains true today – without additional configuration and understanding of what you’re changing, all cryptography software with few exceptions use the weakest encryption possible; they practically go out of their way to do this.

It pissed me off.

Not only that but in Linux, using strong encryption involves some pretty hefty command lines that you have to type correctly every single time, and over time the probability of making a mistake is certain.

LUKS – demonstrated to be one of the most security encryption system on Linux – is based on a password.  This script abstracts that password into a separate file which is then password protected.  This way if the attacker has the password, if they don’t have the file it won’t matter.  If they have the file, they’re not getting at its contents without the password.  Getting into the encrypted volume requires multifactor : what you know and what you have, which is not normally something LUKS can do.

This script also resists the Lest We Remember memory attack by mounting fake volumes alongside the real one – the odds of recovering the correct key is 1/<no. of volumes>, which considering memory degradation makes recovery of the actual key a real bitch.

Once you copy the script to a .sh file and make it executable (chmod 755 lukstool.sh) it’ll take some practice to get used to it, but I think you’ll find it incredibly useful.  

  • You can create a 4 gig file for example and open that file as a hard drive.  Copy your photos, documents and other data into this mounted volume, then unmount it (./lukstool.sh umount /media/mountpoint) then burn it to DVD.  Safe as houses and can only be recovered by whomever has the password AND the keyfile.
  • Instead of a file you can format a partition (ie, /dev/sdb1) as a lukstool partition.  The only way to mount the resulting hard drive partition is with the keyfile and its password.

lukstool.sh
#!/bin/bash

# This script written by Whisper 
# the purpose is to create an armourfile / partition that can be mounted, with its keyfile that can be put on a USB drive
# it contains no new material really, just makes using LUKS to create and use an amourfile easy while enabling every
# security feature available consistently.  This script also does its best to ensure data and file system integrity.
# Even small parts are made functions not just for code re-use but to ensure consistency, making sure functions, no matter how
# easy, are done the same way every time.
# developed for Ubuntu, can be used with any Linux with LUKS installed
# please see www.death-zone.org - Projects - Military Grade Crypto for more information and updates
#
# 081208 * retrifitted to allow for crypto devices as well as files
# 083108 * installed checking functions, cleaned up code a little
# 090408 * tested on CentOS, modified path for sudo ease of use, improved syscheck.
#   noted differences in uuencode loads and GPG-agent.   Thanks to LuckyBambu and drendeah
# 090508 * changed the way GnuPG is referenced and tested, certified to work on CentOS / RedHat / Fedora Core
#    corrected block size and correlated armorfile size error.
# 122909 * verify randomness, augmented by the random key length (2010 -> 2099, who knows).  Correctly designed to augment
#    random even if the seed is corrupt / compromised
#       * augment GPG to ensure it's consistently set to use the right digest, no compression
#       * ability create obscuring volumes in an effort to defeat memory attack
#       * I could have bound the gpg key to a specific USB / drive, but that's VERY dangerous (USB stick dies, so does your data)
#          it also introduces key management complexity and risk.  Thus, I specifically chose not to do this
#       * validated all checks and improved specificity, verbiage, compatibility
#       * improved filesystem detection routines
#       * added 'lukstool cleanup', which will clean up any stray volumes (because however rare, when it's necessary it's
#          a pain to do all the obscuring volumes too by hand!)
#       * augmented password generation routine to 6000 characters, speeding things up while adding to the total figure
#          (4000 more characters the old way would have SUCKED
# 010710 * improved the password generation routine so much, I feel stupid for having done it the other way...
# 012010 * learned more about randomness and instructed the script to look for known /dev/random improvements and
#       warn the user as necessary
# 082010 * learned about a new way to shred devices prior to encryption that's wicked fast and scriptable - credit goes to
#       Derek at 'http://www.mail-archive.com/[email protected]/msg00020.html'
#       * incrased keysizes from 256 to 512
# 040415 * corrected minor bug in zeroing codeblock, updated verbiage.
# 051015 * changed cryptofile behavior to allow for zeroed file or urandom file (compression of file improves at
#       the cost of potential cryptoanalysis vuln)


#------------------------------------------------ Variable Declaration, user editable area - CASE MATTERS
# filesys = ext4 | ext3 | reiserfs
# I prefer ext4 for larger volumes, it's more resilient.  ext3 is best for smaller devices / files / compatibility
# ext4 if your system supports it, reiserfs if it doesn't.
filesys=ext4
# blocksize = 1024 | 2048 | 4096 - 1024 best for flash devices, 4096 for hard drives
blocksize=4096

# ensure /sbin is part of the path for sudo ease of use
# modify as necessary (/sbin?  /usr/sbin?  where's your stuff? 🙂 )
# if lukstool runcheck exits clean, then it can find all you need. Comment out if you don't like it there.
# PATH=$PATH:/sbin:/usr/sbin

# obfuscating the keys in memory by loading multiple dynamically-generated volumes at load-time in an effort to prevent memory
#    attacks.  If set to 5, for example, one of the 6 total volumes loaded is yours, the others are junk (and are automatically generated, loaded, unloaded)
#    having 6 twofish-256 keys in memory combined with memory entropy makes this a nasty shell game to play..!  Naturally it's still possible to defeat this,
#    but it would SUCK, and if a single character in the real key is corrupt it would suck even harder as the attacker can no longer focus on recovery of a single
#    key 'cause they can't tell which one is corrupt!
# each obscuring volume takes about 5 seconds to create and load
# key searching tools will hit on the first value (obscount can't be 1), and 2 would result in the correct key always being the second key found
# 3 would result in it being either the 2nd or 3rd key found (not much of a shell game)
# therefore, the best options are 4, 5 and 6.  6 is the strongest, 5 is the most compatible, therefore the 'sweet spot' is 5!
# IF OPENING VOLUME FILES - this value is NOT TO EXCEED 6!  losetup can only handle 7 concurrent mappings
# IF COPYING FROM ONE FILE-BASED VOLUME TO ANOTHER, best to set this to 0, get it done, shut down, wait, boot up and set back to 5
# valid values are 2,3,4,5,6
obscount=5
# are new crypto volumes shredded first?  I strongly recommend yes, and with the 082010 update there's no excuse not to (values 0 | 1)
shreddevice=0
# minimum number of randomness-augmenting packages running - I recommand at least one
# haveged is the best entropy pool improving solution as of 2014
numrandhelper=1
# ---------------------- probably shouldn't make changes beneath this line
# twofish is fast, cbc and essiv salting mandatory for preventing watermark attacks..  SHA512 because nothing else will do
# .gov says to use AES and Bruce Schneier created twofish - I'm going with Bruce!
# sha256 is the max that essiv salting supports
cipher="twofish-cbc-essiv:sha256"
# GPG - replaced blowfish with twofish for a number of reasons, including:
#     - it's old, twofish has had more eyes recently and the more eyes the better
#     - apparently there's a -chance- that a weak key could be selected for blowfish and broken somewhat more easily than other keys
#     - apparently it's been broken to 14 of the 16 rounds, which is a little close for comfort
# GPG compression is disabled because in fact sometimes the addition of compression can compromise the encryption algorithm
gpgcipher=twofish
gpgdigest=SHA512
gpgcompress=none
# minimum length of encrypt GPG keytoken
keylength=6000
# length of twofish crypto hash, which maxes out at 256 (unlike AES, it doesn't need 512)
keysize=256
# ----------------------

function help {
        echo "Usage: lukstool make | load | unload | check | rekey | runcheck | cleanup"
        echo "  NOTE - Never have a trailing backslash in a path!  Messes everything up."
        echo " # lukstool make"
        echo " lukstool load <source> <key> <mountpoint>"
        echo " lukstool unload <mountpoint>"
        echo " lukstool rekey <source> <key> <newkey>"
        echo " lukstool check <source> <key> <mountpoint>"
        echo " "
        echo "Examples:"
        echo "lukstool load data.dat key.gpg /media/removable"
        echo "lukstool unload /media/removable"
        echo "lukstool check data.dat key.gpg /media/removable"
        echo "lukstool rekey data.dat key.gpg new-key.gpg"
        echo "lukstool runcheck"
        echo "lukstool cleanup"

        echo "This tool detects whether you're dealing with a device or file"
        echo  "  if <source> has 'dev' in it (ie, /dev/sdb1) it acts accordingly"

        echo "'lukstool runcheck' will ensure you can run this without any grief - use this first!"
}

function dieroller {
        # this routine can go up to a 100-sided die
        # returns variable 'total'
        iterations=1
        total=0
        numdie=$1
        sided=$2
        number=
        if [ $sided -gt 100 ]; then
                errcheck "dieroller-sided"
        fi

        while [ $iterations -le $numdie ]; do
                #fetch random number from sysrandom
                # confirm it's 4 digits or more
                acceptable=0
                while [ $acceptable -eq 0 ]; do
                        getrand=$RANDOM
                        if [ $(echo $getrand | wc -c) -ge 5 ]; then
                                acceptable=1
                        fi
                done
                charcount=$(($(echo $getrand | wc -c)-1))
                #reverse number to make leading zeroes possible
                countdown=$charcount
                while [ $countdown -gt 0 ]; do
                        number=$number$(echo $getrand | cut -b$countdown)
                        countdown=$(($countdown-1))
                done
                #create divisor based on size of random number
                divisor=1
                count=1
                while [ $count -le $charcount ]; do
                        divisor=$(echo "$divisor * 10" | bc)
                        count=$(($count+1))
                done

                roll=$(echo "(($number * $sided) / $divisor) +1" | bc)
                total=$(echo "$total + $roll" | bc)
                iterations=$(($iterations+1))
                #reset number variable for next iteration, if there is one
                number=
        done
}

function errcheck {
        if [ $? -ne 0 ]; then
                echo "Error detected, section '$1'"
                loopclean
                exit 1
        fi
}
function testperm {
                # permission test
                if [ "$1" = "root" ]; then
                        if [ "$(whoami)" != "root" ]; then
                                echo "error - this must be done as root"
                                exit 1
                        fi
                else
                        sudo touch /root/testfile
                        if [ $? -ne 0 ]; then
                                echo "error - you must have sudo access"
                                exit 1
                        else
                                sudo rm /root/testfile
                        fi
                fi
}

function loopclean {
        # cldevice expected to be full path
        sync
        if [ -n "$mapper" ] && [ -e /dev/mapper/$mapper ]; then
                sudo cryptsetup luksClose /dev/mapper/$mapper
                if [ $? -ne 0 ]; then
                        echo "Device activity detected - waiting for a few.."
                        sleep 3
                        # try again (sometimes device mappers interfere)
                        sudo cryptsetup luksClose /dev/mapper/$mapper
                        if [ $? -ne 0 ]; then
                                echo "Error detected, loopclean-luksclose"
                                exit 1
                        fi
                fi
        fi
        if [ "$cldevice" != "" ] && [ "$(sudo losetup -a | grep "$cldevice")" != "" ]; then
                sudo losetup -d $cldevice
                if [ $? -ne 0 ]; then
                        echo "Error detected, loopclean-loopd"
                        exit 1
                fi
        fi
        # flush keybuffer in place to prevent memory attacks
        keybuffer=$(sudo head -c $(($keylength+300)) /dev/zero)
}

function mountcheck {
        if [ -n "$(mount | grep "$1"| cut -d " " -f 3 | grep "$1")" ]; then
                echo "Mountpoint already in use - exiting.."
                exit 1
        fi
}

function genkey {
        total=0
        echo -n "Generating strong key...."
        unset keybuffer
        charcount=0
        while [ $charcount -le $keylength ]; do
                echo -n "."
                # pull out from urandom any 'visible' chracters (alnum, punct)
                keybuffer=$keybuffer$(head -c300 /dev/urandom | tr -dc '[:graph:]')
                charcount=$(echo $keybuffer | wc -c)
        done
        echo "complete ("$(echo $keybuffer | wc -c) "characters)."
        if [ $(echo $keybuffer | wc -c) -ge $keylength ]; then
                echo "The following passphrase unlocks your keyfile, and thus the armour file / device."
                echo "Enter the passphrase for your new keyfile (twice)."
                echo "It needs to be longer than 30 characters and have some uppercase characters, numbers and punctuation."
                echo "(note - is okay to ignore any gpg-agent error that may follow)"
                echo -n "Press enter to continue..."
                read proceed
                # this method ensures the key never hits the hard drive
                echo $keybuffer | sudo gpg --no-secmem-warning --no-random-seed-file --cipher-algo $gpgcipher \
                        --digest-algo $gpgdigest --compress-algo $gpgcompress --symmetric --force-mdc -a > $1
                errcheck create-keyfile
        else
                echo "Unexpected error with key generation routine!  Faulting.."
                exit 1
        fi
}

function fileordev {
        if [ -n "$(echo $filename | grep "/dev/")" ]; then
                if [ -e $filename ]; then
                        isdevice=1
                        if [ -z "$cldevice" ]; then
                                cldevice=$filename
                                mapper=$(echo $filename | cut -d "/" -f3)-map-ltool
                        fi
                else
                        errcheck fileordev-dev-doesnt-exist
                fi
        else
                isdevice=0
                if [ -z "$cldevice" ]; then
                        cldevice="$(sudo losetup -f)"
                        if [ -z "$cldevice" ]; then
                                echo "Error - no loop devices available!"
                                exit 1
                        else
                                mapper=$(echo $cldevice | cut -d "/" -f3)-map-ltool
                        fi
                fi
        fi
}

function obfuscate {
        case "$1" in
                create)
                        echo "Creating obfuscating volume, stand by.."
                        obsdatesec=$(date +%s)
                        obscurefile="/tmp/obscurevol$obsdatesec"
                        obscuremap="obscurevol$obsdatesec"
                        # generate scrap volumes with zeroes as contents, but no file system, minimum size possible
                        dcfldd if=/dev/zero of=$obscurefile.dat bs=1024 count=2088 2>&1 > /dev/null
                        # loop the file into a device
                        loopdev="$(sudo losetup -f)"
                        if [ -n "$loopdev" ]; then
                                sudo losetup $loopdev $obscurefile.dat
                                errcheck obfuscate-losetup
                                #generate throw-away key
                                obskey="$(sudo head -c 10 /dev/urandom)"
                                echo $obskey | sudo cryptsetup --cipher $cipher --key-size $keysize luksFormat $loopdev 2>&1 > /dev/null
                                errcheck obfuscate-cryptsetup
                                # mount the scrap volume
                                echo $obskey | sudo cryptsetup luksOpen $loopdev $obscuremap 2>&1 > /dev/null
                                errcheck obfuscate-mount
                        else
                                echo "Error - no loop devices available!  'lukstool cleanup' needs to be run."
                                exit 1
                        fi
                ;;
                destroy)
                        obscurevols="$(ls /dev/mapper | grep obscurevol)"
                        if [ -n "$obscurevols" ]; then
                                echo "Cleaning up obscuring volumes.."
                                for obsvolume in $(ls /dev/mapper | grep obscurevol); do
                                        sudo cryptsetup luksClose /dev/mapper/$obsvolume
                                        errcheck obscure-luksclose
                                        sudo losetup -d "$(sudo losetup -a | grep $obsvolume | cut -d ":" -f1)"
                                        errcheck obscure-losetupclose
                                        rm /tmp/$obsvolume.dat
                                        errcheck obscure-rmobsvolume
                                done
                        else
                                echo "No obscuring volumes found."
                        fi
                ;;
        esac
}

function performmount {
                fileordev
                if [ $isdevice -eq 0 ]; then
                        sudo losetup $cldevice $filename
                fi

                gpg --no-secmem-warning --quiet --decrypt $filekey | sudo cryptsetup luksOpen $cldevice $mapper
                errcheck armorfile-load

                if [ -n "$(sudo head -c 66000 /dev/mapper/$mapper | grep "ReIsEr2Fs")" ]; then
                        echo "Mounting reiserfs.."
                        sudo mount -t reiserfs /dev/mapper/$mapper $mounttarget
                        errcheck ext4-reiser-mount
                else
                        filesystemstatus="$(sudo tune2fs -l /dev/mapper/$mapper)"
                        if [ -n "$(echo "$filesystemstatus" | grep "Filesystem features" | grep "huge_file")" ]; then
                                echo "Mounting ext4.."
                                sudo mount -t ext4 /dev/mapper/$mapper $mounttarget
                                errcheck ext4-mount
                        else
                                echo "Mounting ext3.."
                                sudo mount -t ext3 /dev/mapper/$mapper $mounttarget
                                errcheck ext3-mount
                        fi
                fi
}

function checkrand {
        # checks for randomness improvement software, two or more passes
        # caller of this function checks for hasrand value
        hasrand=0
        if [ -n "$(ps -ef | grep "haveged" | grep -v "grep")" ]; then
                hasrand=$((hasrand+1))
        fi
        if [ -n "$(ps -ef | grep "timer_entropyd" | grep -v "grep")" ]; then
                hasrand=$((hasrand+1))
        fi
        if [ -n "$(ps -ef | grep "video_entropyd" | grep -v "grep")" ]; then
                hasrand=$((hasrand+1))
        fi
        if [ -n "$(ps -ef | grep "audio_entropyd" | grep -v "grep")" ]; then
                hasrand=$((hasrand+1))
        fi
        if [ -n "$(ps -ef | grep "randomsound" | grep -v "grep")" ]; then
                hasrand=$((hasrand+1))
        fi
}

case "$1" in
        make)
                testperm root
                checkrand
                if [ $hasrand -lt $numrandhelper ]; then
                        echo "WARNING - random number entropy not improved by randomness improvement software!"
                        echo "  this will result in your cryptofile being tough, but not as tough as it should be."
                        echo "  Please review www.death-zone.org - Projects - Military Grade Cryptofile - Real Randomness Comes First!"
                        echo .
                        echo "Press ENTER to proceed, or CNTL-C to abort!"
                        read proceed
                fi

                echo "This script creates a luks cryptofile / device AND its correlating physical key"

                echo -n "  enter name of target file or device (example - /home/cryptofile.dat | /dev/sdb1 ): "
                read filename

                fileordev

                echo -n "  enter name of key file (example - /home/cryptofile-key.gpg): "
                read keyfile
                echo -n "  enter mountpoint for testing (example - /media/removable): "
                read mountpoint

                mountcheck $mountpoint

                echo -n "  name of owner (will 'chown name:users; chmod 700'): "
                read owner

                genkey $keyfile

                if [ $isdevice -eq 0 ]; then
                        echo "minimum sizes - ext3, ext4 - 8 Mb.  Reuserfs - 32Mb"
                        echo -n "  enter size of target file in megs: "
                        read size
                        # if shreddevice eq 0, then just use zero, but if clearing slack matters
                        # then use urandom. This improves compressability of the file at the potential cost
                        # of cryptoanalysis vulnerability.
                        if [ $shreddevice -eq 0 ]; then
                          echo "shreddevice=0 : Creating data file with zeroes.."
                        else
                          echo "shreddevice=1 : Creating data file from urandom.."
                        fi
                        case $blocksize in
                                1024)
                                        if [ $shreddevice -eq 0 ]; then
                                          dd if=/dev/zero of=$filename bs=$blocksize count=$(($size * 1024))
                                        else
                                          dd if=/dev/urandom of=$filename bs=$blocksize count=$(($size * 1024))
                                        fi
                                ;;
                                2048)
                                        if [ $shreddevice -eq 0 ]; then
                                          dd if=/dev/zero of=$filename bs=$blocksize count=$(($size * 512))
                                        else
                                          dd if=/dev/urandom of=$filename bs=$blocksize count=$(($size * 512))
                                        fi
                                ;;
                                4096)
                                        if [ $shreddevice -eq 0 ]; then
                                          dd if=/dev/zero of=$filename bs=$blocksize count=$(($size * 256))
                                        else
                                          dd if=/dev/urandom of=$filename bs=$blocksize count=$(($size * 256))
                                        fi
                                ;;
                        esac

                        losetup $cldevice $filename
                else
                        if [ $shreddevice -eq 0 ]; then
                                echo "not clearing slack space on $filename as per configuration - bad idea, but it'll be fast.."
                        else
                                echo "Clearing slack space on $cldevice.."
                                echo "  This not only clears slack but makes the entire volume cryptographically consistent."
                                echo "  NOTE - this could take a very long time, especially on USB sticks..!"
                                echo "  This has the added benefit of confirming device integrity."
                                echo "  General rate - 120 gig / hour on a hard disk - You could hit CNTL-C now"
                                echo "  and pick up later if you really have to."
                                echo "  NOTE - because of the way this is done, if you try to compress the partition you"
                                echo "  will get zero compression as a result - true random."
                                echo "You will get status by means of amount written as well as how long it took afterwards."
                                echo "Press ENTER once to continue (and then wait a while..) or press CNTL-C to abort.."
                                read pressenter
                                # create one-time crypto device on the target partition, the key to the device is randomly generated
                                # with a randomized, throw-away key it doesn't need to be a brutal cipher but it does need to be
                                # truly random - check out the reference URL's for more information
                                cryptsetup create --cipher $cipher random_sdx $cldevice -d /dev/urandom
                                # send /dev/zero (fast) to be encrypted by the kernel and written
                                time dcfldd if=/dev/zero of=/dev/mapper/random_sdx bs=$blocksize
                                #clean up the one-time device
                                cryptsetup remove /dev/mapper/random_sdx
                        fi
                fi

                echo "Formatting cryptovolume.."

                echo $keybuffer | cryptsetup --cipher $cipher --key-size $keysize luksFormat $cldevice
                errcheck armorfile-format

                echo "Initial mount of armourfile / device.."
                echo $keybuffer | cryptsetup luksOpen $cldevice $mapper
                errcheck armorfile-mount

                echo "Successfully mounted - formatting with filesystem '$filesys'..."
                case $filesys in
                        ext4)
                                mkfs.ext4 -q -b $blocksize /dev/mapper/$mapper
                                errcheck ext4-format
                        ;;
                        ext3)
                                mke2fs -j -b $blocksize /dev/mapper/$mapper
                                errcheck ext3-format
                        ;;
                        reiserfs)
                                mkfs.reiserfs -b $blocksize -q /dev/mapper/$mapper
                                errcheck reiserfs-format
                        ;;
                        *)
                                echo "filesys variable improperly set (ext4 | ext3 | reiserfs) - aborting!"
                                loopclean
                                exit 1
                        ;;
                esac

                mount /dev/mapper/$mapper $mountpoint
                errcheck final-mount

                echo "New device is now mounted. Updating ownership..."
                chown $owner:users $mountpoint
                chmod 700 $mountpoint
                sync
                umount $mountpoint
                loopclean
                chown $owner:users $filename
                chown $owner:users $keyfile
                if [ $isdevice -eq 0 ]; then
                        chmod 600 $filename
                else
                        chmod 700 $filename
                fi
                chmod 400 $keyfile

                echo "Device unmounted, permissions updated."
                echo "Now run 'lukstool check $filename $keyfile $mountpoint' as owner ($owner) for final check."
                echo "When the check is complete and everything looks good, you can load the volume as regular user."
        ;;
        load)
                # lukstool load data.dat key.gpg /media/removable"

                testperm

                if [ -z $4 ]; then
                        help
                        exit 1
                else
                        filename=$2
                        filekey=$3
                        mounttarget=$4
                fi
                if ! [ -e $filename ]; then
                        echo "Error - file to load does not exist ($filename) - exiting."
                        exit 1
                fi
                mountcheck $mounttarget

                if [ $obscount -gt 1 ]; then
                        # randomize load order, though the real volume should never be the first one
                        totalvols=$((obscount+1))
                        dieroller 1 $obscount
                        # dieroller returns value 'total'
                        realmount=$(($total+1))
                        obscount=1
                        while [ $obscount -le $totalvols ]; do
                                if [ $obscount -eq $realmount ]; then
                                        performmount
                                else
                                        obfuscate create
                                fi
                                obscount=$((obscount+1))
                        done
                else
                        performmount
                fi
        ;;
        uload|unload|umount|unmount|close)
                # lukstool unload /media/removable

                testperm

                if [ -z $2 ]; then
                        help
                        exit 1
                else
                        mounttarget=$2
                fi

                sync
                if [ -n "$(lsof +f -- $mounttarget)" ]; then
                        echo "Unable to unmount '$mounttarget' as there are open files on that volume - aborting!"
                        echo "Results of lsof: "
                        echo "$(lsof +f -- $mounttarget)"
                        exit 1
                fi

                mapper="$(mount | grep mapper | grep "$mounttarget" | cut -d "/" -f4 | cut -d " " -f1)"
                cldevice="/dev/$(echo $mapper | cut -d "-" -f1)"

                sync
                sudo umount $mounttarget
                errcheck umount-target

                sudo cryptsetup luksClose /dev/mapper/$mapper
                if [ $? -ne 0 ]; then
                        # try again (sometimes device mappers interfere)
                        echo "Device activity detected - waiting for a few.."
                        sleep 3
                        sudo cryptsetup luksClose /dev/mapper/$mapper
                        errcheck uload-luksclose
                fi

                if [ -n "$(echo $cldevice | grep loop)" ]; then
                        sudo losetup -d $cldevice
                        errcheck loopclean-losetup-d
                fi

                # remove any obfuscating volumes
                if [ $obscount -ne 0 ]; then
                        obfuscate destroy
                fi

        ;;
        check)
                # this routine checks the integrity of a given file, key and filesystem
                # lukstool check data.dat key.gpg /media/removable

                testperm

                if [ -z $4 ]; then
                        help
                        exit 1
                else
                        filename=$2
                        filekey=$3
                        mounttarget=$4
                fi

                haserror=0

                # it's all good, right?
                if  [ -e $filename ]; then
                        if [ -e $filekey ]; then
                                if [ -d $mounttarget ]; then
                                        mountcheck $mounttarget
                                        echo "Cryptovolume, key and test mount point confirmed, proceeding.."
                                else
                                        errcheck check-notarget
                                fi
                        else
                                errcheck check-nokey
                        fi
                else
                        errcheck check-nofile
                fi

                echo "Checking general GPG program configuration.."
                echo -n "       "
                gpg --list-keys
                if [ $? -eq 0 ]; then
                        echo "GPG working normally"
                else
                        echo "ERROR - problem with GPG detected."
                        haserror=1
                fi

                echo "Reviewing key checksum.."
                echo -n "       "
                if [ -z "$(gpg --no-secmem-warning --verify $filekey 2>&1 | grep -v "signatures failed")" ]; then
                        echo "GPG Key integrity good."
                else
                        echo "GPG Key integrity check failed."
                        haserror=1
                fi

                echo "Checking GPG armorfile integrity - please enter your password for this step:"
                gpgfileparam="$(gpg -v --list-packets $filekey 2>&1)"
                errcheck check-gpgpass
                gpgfileparamcypher=$(echo "$gpgfileparam" | grep "symkey enc packet" | cut -d " " -f7 | cut -d "," -f1)
                gpgfileparamhash=$(echo "$gpgfileparam" | grep "symkey enc packet" | cut -d "," -f 4 | cut -d " " -f3)
                gpgfileparamsaltcount=$(echo "$gpgfileparam" | grep "salt" | grep "count" | cut -d "," -f2 | cut -d " " -f3)
                echo "Checking cipher.."
                echo -n "       "
                if [ $gpgfileparamcypher -ne 4 ] && [ $gpgfileparamcypher -ne 10 ]; then
                        echo "GPG Key is not Blowfish or Twofish encrypted ($(echo "$gpgfileparam" | grep "encrypted data" | cut -d ":" -f2))"
                        haserror=1
                else
                        echo "good"
                fi
                echo "Checking compression status."
                echo -n "       "
                if [ -n "$(echo "$gpgfileparam" | grep "compressed packet")" ]; then
                        echo "WARNING - GPG keyfile utilizes compression, indicating it's an old blowfish key.  Probably secure, but old.."
                else
                        echo "good"
                fi

                echo "Checking GPG Keysize and content integrity - please enter your password again (last time):"
                echo -n "       "
                keybuffer="$(gpg --no-secmem-warning --decrypt $filekey)"
                errcheck check-key-decrypt

                if [ $(echo $keybuffer | wc -c) -lt $keylength ]; then
                        echo "GPG key decrypts, but keylength is too short!"
                        echo "Armourfile password not adequate, whole thing needs to be regenerated (lukstool script tampered with?)"
                        haserror=1
                        exit 1
                else
                        echo "  Keysize is good (> $keylength characters)."
                fi

                echo "Checking load process:"
                fileordev

                if [ $isdevice -eq 0 ]; then
                        sudo losetup $cldevice $filename
                        errcheck check-losetup
                fi

                echo "Checking for null LUKS keyslot values.."
                echo -n "       "
                echo "" | sudo cryptsetup luksOpen $cldevice $mapper
                if [ $? -eq 0 ]; then
                        echo " ERROR - NULL password on LUKS volume! Back up data, create a new one and destroy the old one (script tampered with?)."
                        haserror=1
                else
                        echo "  LUKS keyslots are not null, proceeding.."
                fi

                # get data from luks volume for examination
                luksvol="$(sudo cryptsetup luksDump $cldevice 2>&1 )"

                echo "Checking for extra LUKS keyslots..."
                echo -n "       "
                if [ $(echo $luksvol | grep ENABLED | wc -l) -gt 1 ]; then
                        echo " ERROR - LUKS volume has more than one keyslot - back door present..?"
                        haserror=1
                else
                        echo "  Only one keyslot found, proceeding.."
                fi

                echo "Confirming LUKS volume integrity:"
                if [  $? -eq 0 ]; then
                        if [  $(echo "$luksvol" | grep "Key Slot" | grep ENABLED | wc -l) -eq 1 ]; then
                                echo "  no back door keys..."
                                if [ -n "$(echo "$luksvol" | grep "MK bits" | grep $keysize)" ]; then
                                        echo "  LUKS using $keysize-bit master key.."
                                else
                                        echo "ERROR - LUKS not using a $keysize bit key, volume needs to be re-created (script tampered with?)"
                                        haserror=1
                                fi
                                if [ -n "$(echo "$luksvol" | grep "Cipher mode" | grep sha256)" ] && [ -n "$(echo "$luksvol" | grep "Hash spec" | grep sha1)" ]; then
                                        echo "  LUKS volume SHA salting confirmed correct."
                                else
                                        echo "ERROR - LUKS volume not using sha salt (script tampered with?)"
                                        haserror=1
                                fi
                        else
                                errcheck check-back-door-key-detected
                        fi
                else
                        errcheck check-cannot-luks-dump
                fi

                echo $keybuffer | sudo cryptsetup luksOpen $cldevice $mapper
                errcheck armorfile-load

                echo -n "File system check, "

                # check for reiser (backward compatability)
                if [ -n "$(sudo head -c 66000 /dev/mapper/$mapper | grep "ReIsEr2Fs")" ]; then
                        echo "ReiserFS:"
                        if [ "$(which fsck.reiserfs)" == "" ]; then
                                echo "Volume is a ReiserFS file system, which I can't check."
                                fsckresults="Can't check ReiserFS"
                        else
                                fsckresults="$(sudo fsck.reiserfs -y /dev/mapper/$mapper 2>&1)"
                        fi
                else
                        filesystemstatus="$(sudo tune2fs -l /dev/mapper/$mapper)"
                        if [ -n "$(echo "$filesystemstatus" | grep "Filesystem features" | grep "huge_file")" ]; then
                                        echo "EXT4:"
                                        fsckresults="$(sudo fsck.ext4 -y /dev/mapper/$mapper 2>&1)"
                        else
                                        echo "EXT3:"
                                        fsckresults="$(sudo fsck.ext4 -y /dev/mapper/$mapper 2>&1)"
                        fi
                fi
                if [ -n "$(echo "$fsckresults" | grep -i "no corruptions found")" ] || \
                        [ -n "$(echo "$fsckresults" | grep "clean")" ] || \
                        [ -n "$(echo "$fsckresults" | grep "ReiserFS")" ]; then
                        echo "  no filesystem corruptions detected."
                else
                        echo "Filesystem errors detected.  It's very risky to auto-repair, this is best done manually."
                        echo " it's best to load as best you can and back everything up before you try.  If backups"
                        echo " Are successful, it's best to nuke this volume, re-create and then restore backups!"
                        echo "test results were: '$fsckresults'"
                        haserror=1
                        errcheck fsckresults
                fi

                loopclean
                if [ $haserror -eq 0 ]; then
                        echo "Check successful, volume unmounted - no errors found."
                else
                        echo "*** Errors were detected, volume unmounted - please review above data."
                fi
        ;;
        rekey)
                testperm

                if [ -z $4 ]; then
                        help
                        exit 1
                else
                        filename=$2
                        filekey=$3
                        newkey=$4
                fi

                fileordev

                if [ $isdevice -eq 0 ]; then
                        sudo losetup $cldevice $filename
                fi

                # GPG pw only due to LUKS keyslot and command parameter difficulties - passwords are easy, keyfiles not so much.
                # while possible with Dump examination, you have to use --key-file which means the key would hit the hard drive
                # at some point - not acceptable.  Better to create a whole new one as necessary and move between cryptovolumes.
                echo "This routine will render your old keyfile ('$filekey') useless and issue a new key ('$newkey')."
                echo "  The old keyfile will be wiped after the new one is created and verified."
                echo "  NOTE - this only changes the GPG password, not the LUKS 2000+ character password!"
                echo "    In order to do that, it's best to generate a completely new LUKS volume and copy data from A to B, because"
                echo "    changing a password in LUKS doesn't actually change the master key, only the keyslot contents."
                echo -n "Press ENTER to proceed or CNTL-C to exit."
                read proceed

                echo -n "First, enter the password to your old key when prompted (press ENTER) "
                read proceed

                keybuffer="$(gpg --no-secmem-warning --quiet --decrypt $filekey)"

                echo -n "Second, enter the password for the new key when prompted (press ENTER) "
                read proceed

                echo $keybuffer | sudo gpg --no-secmem-warning --no-random-seed-file --cipher-algo $gpgcipher \
                        --digest-algo $gpgdigest --compress-algo $gpgcompress --symmetric --force-mdc -a > $newkey
                errcheck rekey-gennewkey

                mapper=""
                echo "Cleaning up.."
                loopclean
                sudo shred -u -n 10 $filekey
                echo "Task Complete."
        ;;
        runcheck)
                echo "This script was designed on OpenSuSE and BASH (later on Ubuntu) - this routine will help verify compatibility with"
                echo "  your particular Linux environment.  Make sure you have reviewed the filesystem and blocksize preferences in "
                echo "  the script prior to running."
                haserror=0
                if [ "$(whoami)" = "root" ]; then
                        echo "running as 'root' - you need to runcheck as a user."
                        echo "  (You'll need to run 'lukstool make' as root, however)  Exiting."
                        exit 0
                else
                        echo "You need to run 'lukstool make' as root - make sure you can do so.  Proceeding.."

                        echo -n "testing for randomness augmentation.."
                        checkrand
                        if [ $hasrand -lt $numrandhelper ]; then
                                echo "WARNING - random number entropy not improved by randomness improvement software!"
                                echo "  this will result in your cryptofile being tough, but not as tough as it should be."
                                echo "  Please review www.death-zone.org - Projects - Military Grade Cryptofile - Real Randomness Comes First!"
                                echo .
                                haserror=1
                        fi
                        echo -n "sudoers access.."
                        sudo touch /root/testfile
                        if [ $? -ne 0 ]; then
                                echo "* error - you need to be able to use 'sudo' without a password."
                                echo "  check your /etc/sudoers and make sure you're in the 'wheel' group."
                                haserror=1
                        else
                                sudo rm /root/testfile
                        fi
                        echo -n "cryptsetup.."
                        if [ "$(which cryptsetup)" = "" ]; then
                                echo "* error - cryptsetup not found.  Is LUKS installed?"
                                echo "  check for RPM / packages cryptsetup and dm-crypt, or your path as a user / non-root."
                                haserror=1
                        fi
                        echo -n "..filesystem support.."

                        # reiser=4, ext4=2, ext3=1 (chmod summing method)
                        filesystems=0
                        if [ -n "$(which mkfs.reiserfs)" ]; then
                                filesystems=$((filesystems+4))
                        fi
                        if [ -n "$(which mkfs.ext4)" ]; then
                                filesystems=$((filesystems+2))
                        fi
                        if [ -n "$(which mkfs.ext3)" ]; then
                                filesystems=$((filesystems+1))
                        fi
                        case $filesystems in
                                7)
                                        echo -n "..All file systems supported.."
                                ;;
                                6)
                                        case $filesys in
                                                ext3)
                                                        echo "ext3 configured but not supported!"
                                                        haserror=1
                                                ;;
                                                ext4)
                                                        echo -n "..ext4 configured and supported.."
                                                ;;
                                                reiserfs)
                                                        echo -n "..ReiserFS configured and supported.."
                                                ;;
                                        esac
                                ;;
                                5)
                                        case $filesys in
                                                ext3)
                                                        echo -n "...ext3 configured and supported.."
                                                ;;
                                                ext4)
                                                        echo "ext4 configured but not supported!"
                                                        haserror=1
                                                ;;
                                                reiserfs)
                                                        echo -n "..ReiserFS configured and supported.."
                                                ;;
                                        esac
                                ;;
                                4)
                                        echo "ReiserFS is the only supported file system detected..?"
                                        case $filesys in
                                                ext3)
                                                        echo "...ext3 configured but not supported!"
                                                        haserror=1
                                                ;;
                                                ext4)
                                                        echo "...ext4 configured but not supported!."
                                                        haserror=1
                                                ;;
                                        esac
                                ;;
                                3)
                                        echo "Warning : ReiserFS support depricated on this host, may be unable to open old volumes."
                                        case $filesys in
                                                ext3)
                                                        echo -n "...ext3 configured and supported.."
                                                ;;
                                                ext4)
                                                        echo -n "...ext4 configured and supported.."
                                                ;;
                                        esac
                                ;;
                                2)
                                        echo "Warning : ReiserFS support depricated on this host, may be unable to open old volumes."
                                        case $filesys in
                                                ext3)
                                                        echo "ext3 not supported by this system but that's what's configured for use!"
                                                        haserror=1
                                                ;;
                                                ext4)
                                                        echo -n "..ext4 configured and supported.."
                                                ;;
                                        esac
                                ;;
                                1)
                                        echo "Warning : ReiserFS support depricated on this host, may be unable to open old volumes."
                                        case $filesys in
                                                ext3)
                                                        echo -n "...ext3 configured and supported.."
                                                ;;
                                                ext4)
                                                        echo "ext4 not supported by this system but that's what's configured!"
                                                        haserror=1
                                                ;;
                                        esac
                                ;;
                                0)
                                        echo "Error - no file systems supported! (WTF?)  Check system integrity!"
                                        haserror=1
                                ;;
                        esac

                        echo -n "losetup.."
                        if [ "$(which losetup)" = "" ]; then
                                echo "* error - 'losetup' not found.  Are you able to use loopback devices?"
                                echo "  or, check also your path as a user / non-root."
                                haserror=1
                        fi
                        echo -n "lsof.."
                        if [ "$(which lsof)" = "" ]; then
                                echo "* error - 'lsof' not found. (or, check also your path as a user / non-root.)"
                                haserror=1
                        fi
                        echo -n "tr.."
                        if [ "$(which tr)" = "" ]; then
                                echo "* error - 'tr' not found, which is used for password generation."
                                haserror=1
                        fi
                        echo -n "gpg.."
                        if [ "$(which gpg)" = "" ]; then
                                echo "* error - 'gpg' not found."
                                echo "  this script requires GnuPG - hit www.gnupg.org, download and install it."
                                haserror=1
                        fi
                        echo -n "dcfldd.."
                        if [ "$(which dcfldd)" = "" ]; then
                                echo "* error - 'dcfldd' not found."
                                echo "  this script requires dcfldd, which is an enhanced version of dd."
                                echo "  'apt-get install dcfldd' or get it here - http://dcfldd.sourceforge.net/"
                                haserror=1
                        fi
                        echo -n "sha512sum.."
                        if [ "$(which sha512sum)" = "" ]; then
                                echo "* error - 'sha512sum' not found."
                                echo "  this script requires sha512sum."
                                haserror=1
                        fi
                        echo -n "tune2fs.."
                        if [ "$(which tune2fs)" = "" ]; then
                                echo "* error - 'tune2fs' not found."
                                haserror=1
                        fi
                        echo -n "bc.."
                        if [ "$(which bc)" = "" ]; then
                                echo "* error - 'bc' not found.  This is a precision calculator program that is needed."
                                haserror=1
                        fi
                        echo -n "confirming RANDOM.."
                        if [ "$(echo $RANDOM)" = "" ]; then
                                echo "* error - problem with the RANDOM number generation, which could impact other parts of your machine as well..!."
                                haserror=1
                        fi

                        gpgver="$(gpg --version)"
                        echo -n "gpg compatibility.."
                        if [ -z  "$(echo $gpgver | grep "Cipher" | grep -i $gpgcipher)" ]; then
                                echo "* error - GPG cipher $gpgcipher is not supported on your system"
                                echo "  you could change the cipher setting, but you really need to review why your GPG implementation"
                                echo "  supports what it does, which is:"
                                echo $gpgver
                                haserror=1
                        fi

                        if [ -z  "$(echo $gpgver | grep "Hash" | grep $gpgdigest)" ]; then
                                echo "* error - GPG digest $gpgdigest is not supported on your system"
                                echo "  you could change the digest setting, but you really need to review why your GPG implementation"
                                echo "  supports only what it does, which is:"
                                echo $gpgver
                                haserror=1
                        fi
                        echo -n "shred.."
                        if [ "$(which shred)" = "" ]; then
                                echo "* error - 'shred' not found."
                                echo "  this script requires shred, a linux utility to eliminate files."
                                haserror=1
                        fi
                        echo -n "dm_crypt.."
                        if [ -z "$(lsmod | grep "dm_crypt")" ]; then
                                echo "* error - dm_crypt module not loaded"
                                echo "  try 'sudo modprobe dm_crypt'"
                                haserror=1
                        fi
                        echo -n "sha512 module.."
                        if [ -z "$(lsmod | grep "sha512")" ]; then
                                echo "* error - sha512 module not loaded"
                                echo "  try 'sudo modprobe sha512', and edit /etc/modules to auto-load at next boot"
                                haserror=1
                        fi

                        if [ $obscount -gt 6 ]; then
                                echo "* error - obscount has an illegal value (cannot exceed 6)"
                                haserror=1
                        fi

                        if [ $haserror = 0 ]; then
                                echo "."
                                echo "Testing complete, looks good.  You should be able to use this script without grief."
                        else
                                echo "Errors were found - please review the above prior to using this script!"
                        fi
                fi
        ;;
        cleanup)
                echo "Cleaning up any stranded obscuring volumes.."
                obscurevols="$(ls /dev/mapper | grep obscurevol)"
                if [ -n "$obscurevols" ]; then
                        echo "Cleaning up obscuring volumes.."
                        for obsvolume in $(ls /dev/mapper | grep obscurevol); do
                                sudo cryptsetup luksClose /dev/mapper/"$obsvolume"
                                errcheck obscure-luksclose
                                sudo losetup -d "$(sudo losetup -a | grep "$obsvolume" | cut -d ":" -f1)"
                                errcheck obscure-losetupclose
                                rm /tmp/"$obsvolume".dat
                                errcheck obscure-rmobsvolume
                        done
                else
                        echo "No obscuring volumes found."
                fi
                for mapper in $(ls /dev/mapper); do
                        if [ -z "$(mount | grep "$mapper")" ] && [ "$mapper" != "control" ]; then
                                echo "Cleaning $mapper"
                                loop=$(echo $mapper | cut -d '-' -f1)
                                cldevice=/dev/$loop
                                loopclean
                        fi
                done
        ;;
        *)
                help
        ;;
esac

Share.

Leave A Reply

Secured By miniOrange