Search Members Help

» Welcome Guest
[ Log In :: Register ]

Mini-ITX Boards Sale, Fanless BareBones Mini-ITX, Bootable 1G DSL USBs, 533MHz Fanless PC <-- SALE $200 each!
Get The Official Damn Small Linux Book. DSL Market , Great VPS hosting provided by Tektonic
 

[ Track this topic :: Email this topic :: Print this topic ]

reply to topic new topic new poll
Topic: Updated tripl script, loop-aes front end< Next Oldest | Next Newest >
WDef Offline





Group: Members
Posts: 798
Joined: Sep. 2005
Posted: Aug. 06 2008,21:39 QUOTE

For your orgastic overstimulation, here is the updated  version of the tripl script referred to here , since it doesn't have a home as yet.

If you tried the earlier version (in the loopaes extension), note the cli switches have changed. Type tripl -h

It tests for correct gnupg and losetup etc which will slow it down on very old machines; if anyone asks I will add a switch to disable these checks.

Code Sample

#!/bin/bash

# $Id: tripl,v0.56 4/23/2008 01:55:01 wdef Exp $

# tripl - single or multiple encryption with loop-aes-ciphers
# (c) 2006-2008 wdef v0.54 <email suppressed for forum post>

# Wrapper to manage single or multiple encrypted partitions using loop-aes v3.x (multikey).
# Automates gpg key generation, allocation and setup/pulldown of loops, layered embedding of keys,
# filesystem checking etc. Does not write to /etc/fstab. Note: multiple encryption can use a lot of
# cpu at times. Single or double encryption with a good password is sufficient (really!).
# Script skips loops that are already in use and only pulls down encrypted loops chained to device
# on umounting. Blowfish is not supported since it does not work with multiline keychains in loopaes
# and is not recommended for large amounts of data.
# Tries hard to prevent loop collisions if you are also using some loops for other things.

# This is free software. No warranty. Use AYOR.

#===========================================================

###  Changelog v.3
# Set example .config in ${HOME} on first run
# - modules settings and MAXLOOPS removed from config, now automatic.
# - improved loopfree function
# - explicit error messages on failed umount or loop pulldown, fixed exit values from pull_down.
# - added option for manually setting paths to utils.
# - should work on systems without /sbin in PATH.
# ## v0.4
# Added test function for increased iterations with gpg
# - Now only pulls down loops chained to device (function dechain_loops)
# ## v0.5
# Switches changed to use getopts: -f -muknrh
# Try very hard to prevent loop collisions:
# - fixed issue with wrong PREVIOUSLOOP when more than one encrypted device mounted.
# - fixed dechain_loops
# - loopfree now looks in any field of losetup output for loop numbers
# Checks that device is there..
# Allow 3 tries to get password right
# Clearer messages.
# VERBOSE setting.
# -f option allows pointing at alternate config file.
# ## v0.54
# Fixed loop pulldown after making new partition.
# Checks device free before allowing new setup
# Other stuff
# ## v0.55
# Gentle option for forced umount
# ## v0.56
# Added ext3

# To Do:
# add signal trap to pulldown loop if device overwrite interrupted


#===================// FUNCTIONS //============================


help(){
cat <<"EOF"
tripl - single or multiple encryption with loop-aes
(c) 2006-2008 wdef v0.56
Usage: tripl [-f <file> ] [-muknrh ]
Option:
-m = mount
-u = unmount
-k = make key
-n = set up encrypted partition (destroys data!)
-r = check, repair encrypted filesystem
-f = use <file> as triplrc instead of ~/.triplrc
-h = this
Set partition name, keys, order of ciphers, mountpoint and MODE
(1,2,3 for single,double,triple encryption) in triplrc
EOF
}


set_example_config(){
cat <<EOF

# Make these settings in $HOME/.triplrc, where $HOME is root's home dir.

DEVICE=/dev/your_device_here
MOUNTPT=/mnt/your_mountpoint_here

#MODE=3 # Triple encryption
MODE=2 # Double encryption
#MODE=1 # Single encryption

# You can rearrange the order of ciphers, but only for a new setup:
#- you'll have to destroy data by runnning tripl -n again if you change this (so back up data first).

CIPHER[1]=serpent128
CIPHER[2]=twofish128
CIPHER[3]=AES128

# Run tripl -k to make a key, then set it here:

key[1]=/path_to_your_key1
key[2]=/path_to_your_key2
key[3]=/path_to_your_key3

FS=ext2 # Filesystem: ext2, ext3
#FS=ext3


#EMBED=no
EMBED=yes # If enabled, the user only need specify one external gpg-encrypted key (key[1]) in user settings.
# Other keys will be automatically generated for each encryption layer by tripl -n (prompts user
# for passwords) and successively embedded in the encryption layer previous to that being set up.
# This also means an attacker has to crack the first encryption layer just to get the
# encrypted key for the second, and so on. No effect if MODE=1

# If disabled, a seperate external (detached) key should be created with tripl -k for each
# encryption layer and set in this config file prior to running tripl -n

#FORCE=OFF # No attempt to interrupt processes to do umount
FORCE=GENTLE # Flush buffers and signal politely before resorting to sigkill
#FORCE=BRUTE # Only to enable an emergency rapid umount.

VERBOSE=yes # Show what is being done.

GPGHOME="${HOME}/.gnupg"

DISABLE_NEW=yes # Disable new encrypted paritition switch as a double failsafe measure to prevent partition destruction
# Enable when you're sure you need it.


# If non-standard /path/to/utils, set here:
# losetup=
# mount=
# umount=
# fsck=
# modprobe=
# fdisk=
EOF
}


check_losetup(){
if $(which strings &>/dev/null); then
strings $losetup | grep -q -s multi-key-v3
return $?
elif grep --version | grep -q 'GNU grep' 2>/dev/null; then
grep -q -a -s multi-key-v3 $losetup
return $?
else
echo "Error: can't check losetup compatibility"
echo "Install strings or GNU grep before proceeding."
exit 1
fi
}


run_checks(){
if [ $EUID -ne 0 ]; then echo "You're not root."; exit 1; fi
if [ $# -eq 0 ]; then help; exit 1; fi
if ! which gpg &>/dev/null; then echo "Can't find GnuPG"; exit 1; fi
if [ $MAXLOOPS -eq 0 ]; then echo "Can't find any loop devices"; exit 1;fi
}


set_modules(){
# Set modules to match ciphers
for p in $(seq 1 $MODE); do
case ${CIPHER[p]} in
aes128|AES128) MODULE[$p]=loop;;
serpent128|SERPENT128) MODULE[$p]=loop_serpent;;
twofish128|TWOFISH128) MODULE[$p]=loop_twofish;;
*) echo "Error: unsupported cipher ${CIPHER[p]}"; exit 1;;
esac
done
}

check_device_free(){
if $losetup -a | grep -wq ${DEVICE} || grep -wq ${DEVICE} /proc/mounts; then
echo "Error: ${DEVICE} is in use."
exit 1
fi
}


conf_checks(){

if [ "$CLI_CONFIG" != yes ]; then
if [ -f "${HOME}/.triplrc" ]; then
. ${HOME}/.triplrc
else
set_example_config >${HOME}/.triplrc
echo "Edit ${HOME}/.triplrc for your desired setup"
echo "Then run tripl again."
exit 0
fi
fi

# Default utils locations if not set or in  PATH
losetup=${losetup:=/sbin/losetup}
mount=${mount:=/bin/mount}
umount=${umount:=/bin/umount}
fsck=${fsck:=/sbin/fsck}
modprobe=${modprobe:=/sbin/modprobe}
fdisk=${fdisk:=/sbin/fdisk}

# Do some basic checks
if [ -z "${DEVICE}" ]; then "DEVICE is unset"; exit 1; fi
if [ -z "${MOUNTPT}" ]; then "MOUNTPT is unset"; exit 1; fi
if [ ! -d "${MOUNTPT}" ]; then echo "${MOUNTPT} does not exist."; exit 1;fi
if [ ! -b "${DEVICE}" ]; then echo "$DEVICE is not a valid block device"; exit 1; fi
if ! $fdisk -l | awk '/^\/dev/{print $1}'| grep -wq ${DEVICE}; then
echo "Can't find device ${DEVICE}.  Is it connected?"
exit 1
fi
case $FS in
ext2|ext3);;
*) echo "Invalid filesystem setting \"$FS\""; exit 1;;
esac

if ! check_losetup; then
echo "Error: your $losetup is incompatible with loop-aes v3.x"
echo "See the loop-aes README for details."
exit 1
fi

set_modules
}



loopfree(){

# Could(?) replace this whole fn with:
# perl -e 'map($t[$_]=1, map(/loop(\d)/,`losetup -a`)); $i=0; $i++ until !$t[$i]; ($i==8 and exit 1) || print $i'

# Safest - just get all the used loop numbers, regardless of what field they appear in
# This should prevent evil from somehow managing something silly like absent loop on one
# loop of chain, leaving next loop in chain orphaned, and loopfree would then report the first (busy)
# loop as free =>  overwrite encrypted loop (it  happened).

A=$($losetup -a | perl -lane 'while (/\/dev\/loop(\d)/g) { print $1 }' | sort | uniq)

if [ -z "$A" ]; then
# Loop 0 is free
NEXTLP=0
return 0
fi
Y=0
for i in $A; do
if [ $i -eq $Y ]; then
(( Y = i + 1 ))
continue
else
# Loop $Y is free
NEXTLP=$Y
return 0
fi
done
if [ $Y -eq $MAXLOOPS ]; then
# No free loops
return 1
else
# loop $Y is free
NEXTLP=$Y
return 0
fi
}


dechain_loops(){
# Outputs encrypted loop devices chained to device $1
export A=$1
NUMLOOPS=0
until [ -z "${A}" ]; do
LOOP=$($losetup -a | awk -F: '$3 ~ ENVIRON["A"] {print $1}')
if [ -n "${LOOP}" ]; then
echo "${LOOP}"  # important: output includes newline
(( NUMLOOPS++ ))
fi
export A=${LOOP}
done
}


pull_down(){
X=$1
if grep -wq "${MOUNTPT}" /proc/mounts; then
case $FORCE in

BRUTE)  # just kill 'em.  Could damage filesystem and/or lose some data
fuser -m -k ${MOUNTPT};;

GENTLE) # Be gentle with me
s[0]=-SIGHUP; s[1]=-SIGTERM; s[2]=-SIGKILL
sync; sync
q=0
for SIG in ${s[*]}; do
fuser -m -k $SIG ${MOUNTPT}
sleep 1
if fuser -ms ${MOUNTPT}; then
echo -n "$SIG failed, "
if [ $q -eq 2 ]; then
echo "Error: processes still running on ${MOUNTPT}"
exit
fi
echo "trying ${s[q+1]} .."
else
break
fi
(( q = q + 1 ))
done;;
OFF);;

*) echo "Error: unrecognized FORCE configuration \"$FORCE\"";;

esac

$umount ${MOUNTPT}
grep -wq "${MOUNTPT}" /proc/mounts && echo "Error: umount failed!"
else
[ "$VERBOSE" = yes ] && echo "${MOUNTPT} is not in use"
fi

# Pull down our encrypted loops chained on top of device

dechain_loops ${DEVICE} | sort -r | while read D; do
[ "$VERBOSE" = yes ] && echo "Pulling down ${D} .."
$losetup -d $D
X=$?
if [ $X -ne 0 ]; then
echo "Error: free up ${D} and try again."
exit $X
fi
done && exit $X
}



ask_user(){
while true; do
echo -n "$1? (y/N) "
read
case $REPLY in
y|Y|y*|Y*) if [ "$1" = Abort ]; then exit 1; fi;;
n|N|n*|N*) if [ "$1" = Abort ]; then break; fi;;
*) echo "Invalid response";;
esac
done
}



check_gpg_iterations(){
echo
echo x | gpg --no-tty --passphrase-fd 3 3< <(echo whatever) --symmetric >${gpgtest}
TESTSTR=$(gpg --no-tty --passphrase-fd 3 3< <(echo whatever)  --decrypt -v -v <${gpgtest} 2>&1 | grep -E "salt.+count")
ITERFLAG=${TESTSTR##*[ ]}
rm -f ${gpgtest}
case $ITERFLAG in
# newer gnupg versions put () around iteration flag
208|\(208\)) echo "Good, GnuPG is using increased iterations flag = $ITERFLAG";;
96|\(96\)) echo "GnuPG is using only standard iterations flag = $ITERFLAG"
echo "See loop-aes README for details."
ask_user Abort;;
*) echo "WTF?? unknown gpg iteration counts flag $ITERFLAG"; exit 1;;
esac
}


makekey(){
check_gpg_iterations &>/dev/tty
head -c 2925 /dev/random | uuencode -m - | head -n 66 | tail -n 65 \
| gpg --symmetric -a
return
}


checkloops(){
NUMBUSY=$($losetup -a|wc -l)
(( NUMFREELOOPS = MAXLOOPS - NUMBUSY ))
if [ $NUMFREELOOPS -lt $MODE ]; then
echo "Insufficient loops free ($NUMFREELOOPS)"
echo "Require $MODE free loop device(s)."
exit 1
fi
}


overwrite_partition(){
checkloops
loopfree || pull_down 1
LP=/dev/loop$NEXTLP
head -c 15 /dev/urandom | uuencode -m - | head -n 2 | tail -n 1 | losetup -p 0 -e AES128 $LP ${DEVICE}
dd if=/dev/zero of=$LP bs=4k conv=notrunc 2>/dev/null
losetup -d $LP
}


setup_loops(){
[ "${1}" != new ] && check_device_free # for new setup, this has already been checked
checkloops
echo
if [ $EMBED = yes ]; then
if [ ! -e "${key[1]}" ]; then
echo "Error: Can't find key ${key[1]} - need one external key for embedded mode."
exit 1
fi
if [ "${1}" = new ]; then
[ "$VERBOSE" = yes ] && echo ">>>>>> Using key ${key[1]} for loop1 <<<<<<"
else
echo "Enter $MODE password(s):"
fi
else
echo "Enter $MODE password(s):"
fi


for k in $(seq 1 $MODE); do

$modprobe ${MODULE[k]} || pull_down 1
loopfree || pull_down 1
TOPLOOP="/dev/loop$NEXTLP"

if [ $k -gt 1 ]; then
# Sanity check:
PL=$(dechain_loops ${DEVICE}| tail -n 1)
if [ ${PREVIOUSLOOP} != ${PL} ]; then
echo "[$k] Error! dechain_loops says previous loop is ${PL}"
echo "But here previousloop = ${PREVIOUSLOOP}"
exit 1
fi
fi

if [ $EMBED = yes ]; then
if [ $k -eq 1 ]; then
# No offset key on first loop
[ "$VERBOSE" = yes ] && echo "[$k] Setting up ${TOPLOOP} on ${DEVICE} .."
p=0
while ! $losetup -e ${CIPHER[1]} -K ${key[1]} -G ${GPGHOME} ${TOPLOOP} ${DEVICE}; do
(( p++ ))
if [ $p -eq 3 ]; then echo "3rd failed attempt, exiting .."; pull_down 1; fi
echo "Try again ($p) .."
done
else
if [ "${1}" = new ]; then
echo
echo ">>>>>> [$k] Making embedded key on ${PREVIOUSLOOP}  <<<<<<"
echo "Enter new password at three prompts .."
yes "" | dd of=${PREVIOUSLOOP} bs=512 count=16
makekey | dd of=${PREVIOUSLOOP} conv=notrunc
fi
[ "$VERBOSE" = yes ] && echo "[$k] Setting up ${TOPLOOP} on ${PREVIOUSLOOP} .."
p=0
while ! $losetup -e ${CIPHER[k]} -K ${PREVIOUSLOOP} -o 8192 -G ${GPGHOME} ${TOPLOOP} ${PREVIOUSLOOP}; do
(( p++ ))
if [ $p -eq 3 ]; then echo "3rd failed attempt, exiting .."; pull_down 1; fi
echo "Try again ($p) .."
done

fi
else
if [ ! -e "${key[k]}" ]; then
echo "[$k] Error: Can't find key ${key[k]}"
pull_down 1
fi
[ $k -eq 1 ] && PREVIOUSLOOP=${DEVICE}
[ "$VERBOSE" = yes ] && echo "[$k] Setting up ${TOPLOOP} on ${PREVIOUSLOOP} .."
p=0
while ! $losetup -e ${CIPHER[k]} -K ${key[k]} -G ${GPGHOME} ${TOPLOOP} ${PREVIOUSLOOP}; do
(( p++ ))
if [ $p -eq 3 ]; then echo "3rd failed attempt, exiting .."; pull_down 1; fi
echo "Try again ($p) .."
done
fi
PREVIOUSLOOP=${TOPLOOP}
done

}

#=====================// MAIN //==================================


gpgtest=/tmp/gpgtest.$RANDOM.$$

MAXLOOPS=$(ls /dev/loop* | wc -l)

run_checks $*

# Parse cli options

ARGS="$@"

# Catch malformed options not having 2 chars
for P in $ARGS; do
case $P in
-*) if [ ${#P} -ne 2 ]; then
echo "Unknown option $P. Try tripl -h"; exit 1
     fi;;
esac
done

if echo $ARGS | grep -q 'f'; then
case $ARGS in
-f*):;;
*f*) echo "Error: -f option must be first"
exit 1;;
esac
fi

CLI_CONFIG=""


while getopts ":f:nmukrh" Option; do

case $Option in

f) . ${OPTARG} || exit 1
[ "$VERBOSE" = yes ] && echo "Using config file ${OPTARG} .."
CLI_CONFIG=yes;;

n)
conf_checks
if [ $DISABLE_NEW = yes ]; then
echo "New partition switch disabled in user settings"
exit 0
fi
check_device_free
echo
echo "WARNING: this will destroy all data on $DEVICE !"
echo "~~~~~~~"

while true; do
echo -n "Last chance to exit. Are you sure you want to proceed? (YeS/n) "
read
case $REPLY in
YeS) break;;
n|N|n*|N*) exit 0;;
y|y*|Y|Yes|YE*) echo "You must type YeS to proceed.";;
*) echo "Invalid response.";;
esac
done


echo "Preparing device ${DEVICE} .. pls wait .."
overwrite_partition

setup_loops new
echo
echo ">>>>>> Making filesystem on ${TOPLOOP} <<<<<<"
mkfs -t $FS ${TOPLOOP}
pull_down 0;;


m)
conf_checks
if grep -wq "${MOUNTPT}" /proc/mounts; then echo "${MOUNTPT} in use."; exit 1; fi
setup_loops
$mount -t $FS ${TOPLOOP} ${MOUNTPT}
if grep -wq "${TOPLOOP}" /proc/mounts; then echo "OK"; else pull_down 1; fi;;

u)
conf_checks
pull_down 0;;

k)
conf_checks
while true; do
echo -n "Enter path and filename of new key (CNTRL-C = quit): "
read
DIR=$(dirname ${REPLY})
if [ -e "${REPLY}" ]; then
echo "File $REPLY already exists."; continue
fi
if [ ! -d "${DIR}" ]; then
echo "Invalid path ${DIR}"; continue
fi
if [ ! -w "${DIR}" ]; then
echo "${DIR} not writeable"; continue
fi
break
done
echo "Making key ${REPLY} .."
makekey >${REPLY}
if [ $? -eq 0 ]; then
echo "Done."
echo "Set your new key location at top of the script."
else
rm -f ${REPLY} # gpg will provide error messages if it fails.
exit 1
fi;;


r)
conf_checks
if grep -wq "${MOUNTPT}" /proc/mounts; then echo "${MOUNTPT} in use."; exit 1; fi
echo "Repairing encrypted filesystem on ${DEVICE} .."
setup_loops
$fsck -t $FS -C -f -y ${TOPLOOP}
echo "Done."
pull_down 0;;


h) help; exit 0;;

*)
A=( echo "$@" )
BADOPT=${A[OPTIND-1]}
echo "Unknown option $BADOPT. Try tripl -h"; exit 1;;

esac
done

shift $(($OPTIND - 1))
Back to top
Profile PM 
0 replies since Aug. 06 2008,21:39 < Next Oldest | Next Newest >

[ Track this topic :: Email this topic :: Print this topic ]

 
reply to topic new topic new poll
Quick Reply: Updated tripl script

Do you wish to enable your signature for this post?
Do you wish to enable emoticons for this post?
Track this topic
View All Emoticons
View iB Code