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.
#!/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