commit 1d815a1f7e3c9d7a33a973a75e0fa22e015508d2
parent f794b78795e762aede6f204f2c6d30119ae354e9
Author: Jaromil <jaromil@dyne.org>
Date: Mon, 25 Aug 2014 21:01:50 +0200
More refactoring of how keys, passwords and secrets are stored
includes a working loopback and tempfile cleanup in endgame()
and several changes in order to avoid saving anything on disk
WIP addressing #124 and #126
Diffstat:
M | tomb | | | 661 | ++++++++++++++++++++++++++++++++++++++----------------------------------------- |
1 file changed, 321 insertions(+), 340 deletions(-)
diff --git a/tomb b/tomb
@@ -50,12 +50,14 @@ WIPE="rm -f"
MKFS="mkfs.ext3 -q -F -j -L"
KDF=1
STEGHIDE=1
-MKTEMP=1
RESIZER=1
SWISH=1
QRENCODE=1
MOUNTOPTS="rw,noatime,nodev"
+# prefix for temporary files
+TMPPREFIX="/dev/shm/$$.$RANDOM."
+
typeset -A global_opts
typeset -A opts
typeset -h username
@@ -64,7 +66,15 @@ typeset -h _uid
typeset -h _gid
typeset -h _tty
-typeset -H tomb_secret
+typeset -gH tomb_file
+
+typeset -gH tomb_key
+typeset -gH tomb_key_file
+typeset -gH tomb_secret
+typeset -gH tomb_password
+
+typeset -ah tomb_tempfiles
+typeset -ah tomb_loopdevs
# Make sure sbin is in PATH
PATH+=:/sbin:/usr/sbin
@@ -78,8 +88,20 @@ export TEXTDOMAIN=tomb
endgame() {
# here clear all temp files and flush all pipes
- _verbose "Signal trap: $1"
unset tomb_secret
+ unset tomb_password
+
+ for d in $tomb_tempdirs; do
+ rm -f "$d/*"; rmdir "$d"; done
+ unset tomb_tempdirs
+
+ for f in $tomb_tempfiles; do
+ rm -f "$f"; done
+ unset tomb_tempfiles
+
+ for l in $tomb_loopdevs; do
+ losetup -d "$l"; done
+ unset tomb_loopdevs
}
# trap functions for the endgame event
@@ -93,61 +115,51 @@ TRAPPIPE() { endgame PIPE }
TRAPTERM() { endgame TERM }
TRAPSTOP() { endgame STOP }
-_have_shm() {
- # Check availability of 1MB of SHM
- _verbose "_have_shm 0 We need only 1 MB of RAM."
- [[ -k /dev/shm ]] || return 1
-
- local -i SHM RAM
-
- SHM=$(df -k -B 4K -a -t tmpfs /dev/shm | awk '/\/dev\/shm/ { print $4; }')
- (( $? )) && return 1
- _verbose "_have_shm 1 SHM $SHM KB are available."
+check_shm() {
+ # TODO: configure which tmp dir to use from a cli flag
+ SHMPREFIX=/dev/shm
- RAM=$(awk '/MemFree/ { print $2 }' /proc/meminfo)
- _verbose "_have_shm 2 RAM $RAM KB are free."
- (( $RAM >= 1024 )) && return 0
+ [[ -k /dev/shm ]] || [[ -k /run/shm ]] && { SHMPREFIX=/run/shm } \
+ || {
+ # mount the tmpfs if the SO doesn't already
+ mkdir /run/shm
+ [[ $? = 0 ]] || {
+ fatal "Fatal error creating a directory for temporary files"
+ return 1 }
+ mount -t tmpfs tmpfs /run/shm \
+ -o nosuid,noexec,nodev,mode=0600,uid="$_uid",gid="$_gid"
+ [[ $? = 0 ]] || {
+ fatal "Fatal error mounting tmpfs in /run/shm for temporary files"
+ return 1 }
- _verbose "_have_shm 3 RAM $RAM KB left only :("
- # Now we have more RAM than affected to SHM, so we can expect some for our little needs.
- # Does that work when SHM is disabled from kernel config?
- return 1
-}
+ SHMPREFIX=/run/shm
+ }
-# Create temporary directories with caution
-safe_dir() {
- # Try and create our temporary directory in RAM
- # Note that there's no warranty the underlying FS won't swap
- # every 5 seconds (e.g., ext3)
- local -i tries
- while (( $tries < 3 )) ; do
- tries+=1
- if _have_shm; then
- _verbose "safe_dir creating $1 dir in RAM."
- if (( $MKTEMP )); then
- mktemp -d /dev/shm/tomb.$1.$$.XXXXXXX
- else
- dir="/dev/shm/tomb.$1.$$.$RANDOM$RANDOM"
- mkdir -m 0700 -p "$dir"
- print "$dir"
- fi
- return 0
- else
- _warning "WARNING: we cannot ensure we're running in RAM."
- _verbose "Wait a bit before retrying... (attempt $tries)."
- sync && sleep 0.5
- fi
- done
- _warning "WARNING: no RAM available for me to run safely."
- return 1
+ # setup a special env var for zsh to create temp files that will
+ # then be deleted at the exit of each function using them.
+ TMPPREFIX="$SHMPREFIX/$$.$RANDOM."
+ return 0
}
# Provide a random filename in shared memory
-safe_filename() {
- _have_shm || _failure "No access to shared memory on this system, sorry."
- (( $MKTEMP )) && \
- mktemp -u /dev/shm/tomb.$1.$$.XXXXXXX || \
- print "/dev/shm/tomb.$1.$$.$RANDOM$RANDOM"
+tmp_create() {
+ local tfile="${TMPPREFIX}${RANDOM}"
+ touch "$tfile"
+ [[ $? = 0 ]] || {
+ fatal "Fatal error creating a temporary file: $tfile"
+ return 1 }
+ chown "$_uid":"$_gid" "$tfile"
+ chmod 0600 "$tfile"
+ [[ $? = 0 ]] || {
+ fatal "Fatal error setting permissions on temporary file: $tfile"
+ return 1 }
+ _verbose "created tempfile: $tfile"
+ tomb_tempfiles+=($tfile)
+ return 0
+}
+tmp_new() {
+ # print out the latest tempfile
+ print "${tomb_tempfiles[${#tomb_tempfiles}]}"
}
# Check if swap is activated
@@ -287,7 +299,7 @@ EOF
fi # are we root already
# check if we have support for loop mounting
- losetup -f >-
+ losetup -f >& -
{ test "$?" = "0" } || {
_warning "Loop mount of volumes is not supported on this machine, this error"
_warning "often occurs on VPS and kernels that don't provide the loop module."
@@ -296,8 +308,8 @@ EOF
}
# make sure necessary kernel modules are loaded
- modprobe dm_mod 2>-
- modprobe dm_crypt 2>-
+ modprobe dm_mod
+ modprobe dm_crypt
return 0
}
@@ -314,19 +326,63 @@ is_valid_tomb() {
{ test -f "$1" } || {
_warning "Tomb file is not a regular file: $1"; return 1 }
# check file type (if its a Luks fs)
- file "$1" | grep -i 'luks encrypted file' >-
- { test $? = 0 } || {
- _warning "File is not a valid tomb: $1"; return 1 }
+
+ file "$1" | grep -i "luks encrypted file" > /dev/null || {
+ _warning "File is not yet a tomb: $1" }
+
# check if its already open
tombfile=`basename $1`
tombname=${tombfile%%\.*}
- mount -l | grep "${tombfile}.*\[$tombname\]$" >-
+ mount -l | grep "${tombfile}.*\[$tombname\]$" > /dev/null
{ test $? = 0 } && {
_warning "Tomb is currently in use: $tombname"; return 1 }
_message "Valid tomb file found: $1"
return 0
}
+# $1 is the tomb file to be lomounted
+lo_mount() {
+ tpath="$1"
+ is_valid_tomb "$tpath" || {
+ _failure "Loopback mount called on invalid tomb: $tpath" }
+
+ losetup -f >& -
+ [[ $? = 0 ]] || {
+ # if [ $? = 255 ]; then
+ # _failure "Too many tombs open. Please close any of them to open another tomb."
+ # fi
+ _failure "Loopback device not available" }
+
+ _nstloop=`losetup -f` # get the number for next loopback device
+
+ losetup -f "$tpath" >& - # allocates the next loopback for our file
+
+ tomb_loopdevs+=("$_nstloop") # add to array of lodevs used
+
+ return 0
+}
+
+# print out latest loopback mounted
+lo_new() { print "${tomb_loopdevs[${#tomb_loopdevs}]}" }
+
+# $1 is the path to the lodev to be preserved after quit
+lo_preserve() {
+ _verbose "lo_preserve on $1"
+ # remove the lodev from the tomb_lodevs array
+ tomb_loopdevs=("${(@)tomb_loopdevs:#$1}")
+}
+
+# used for debugging
+dump_secrets() {
+ _verbose "tomb_file: $tomb_file"
+ _verbose "tomb_key: ${#tomb_key} chars long"
+ _verbose "tomb_key_file: $tomb_key_file"
+ _verbose "tomb_secret: ${#tomb_secret} chars long"
+ _verbose "tomb_password: $tomb_password"
+
+ _verbose "tomb_tempfiles: ${(@)tomb_tempfiles}"
+ _verbose "tomb_loopdevs: ${(@)tomb_loopdevs}"
+}
# }}}
# {{{ Commandline interaction
@@ -425,7 +481,7 @@ option_is_set() {
# Get an option value
option_value() {
# First argument, the commandline flag (i.e. "-s").
- <<< ${opts[$1]}
+ print -n "${opts[$1]}"
}
# Messaging function with pretty coloring
@@ -523,35 +579,33 @@ progress() {
check_bin() {
# check for required programs
for req in cryptsetup pinentry sudo gpg; do
- command -v $req >- || _failure "Cannot find $req. It's a requirement to use Tomb, please install it." 1
+ command -v $req >& - || _failure "Cannot find $req. It's a requirement to use Tomb, please install it." 1
done
export PATH=/sbin:/usr/sbin:$PATH
# which dd command to use
- command -v dcfldd >-
+ command -v dcfldd >& -
{ test $? = 0 } && { DD="dcfldd statusinterval=1" }
# which wipe command to use
- command -v wipe >- && WIPE="wipe -f -s" || WIPE="rm -f"
+ command -v wipe >& - && WIPE="wipe -f -s" || WIPE="rm -f"
# check for filesystem creation progs
- command -v mkfs.ext4 >- && \
+ command -v mkfs.ext4 >& - && \
MKFS="mkfs.ext4 -q -F -j -L" || \
MKFS="mkfs.ext3 -q -F -j -L"
- # check for mktemp
- command -v mktemp >- || MKTEMP=0
# check for steghide
- command -v steghide >- || STEGHIDE=0
+ command -v steghide >& - || STEGHIDE=0
# check for resize
- command -v e2fsck resize2fs >- || RESIZER=0
+ command -v e2fsck resize2fs >& - || RESIZER=0
# check for KDF auxiliary tools
- command -v tomb-kdb-pbkdf2 >- || KDF=0
+ command -v tomb-kdb-pbkdf2 >& - || KDF=0
# check for Swish-E file content indexer
- command -v swish-e >- || SWISH=0
+ command -v swish-e >& - || SWISH=0
# check for QREncode for paper backups of keys
- command -v qrencode >- || QRENCODE=0
+ command -v qrencode >& - || QRENCODE=0
}
# }}} - Commandline interaction
@@ -571,48 +625,48 @@ load_key() {
_failure "This operation requires a key file to be specified using the -k option."
return 1 }
- local keyopt
keyopt="`option_value -k`"
if [[ "$keyopt" == "-" ]]; then
_verbose "load_key reading from stdin."
# take key from stdin
- tombkeydir=`safe_dir load_key_stdin`
- # tombkeydir is a global used to check if key from stdin
- _verbose "tempdir is $tombkeydir"
- act "Waiting for the key to be piped from stdin... "
- cat > ${tombkeydir}/stdin.tmp.key
- print ok >&2
- tombdir=${tombkeydir}
- tombfile=stdin.tmp.key
- tombname="stdin"
+ _message "Waiting for the key to be piped from stdin... "
+ tomb_key_file=stdin
+ tomb_key=`cat`
+# print ok >&2
elif [[ "$keyopt" != "" ]]; then
_verbose "load_key argument: `option_value -k`"
# take key from a file
- tombkey=`option_value -k`
- tombdir=`dirname $tombkey`
- tombfile=`basename $tombkey`
+ tomb_key_file="$keyopt"
+ { test -r "${tomb_key_file}" } || {
+ _warning "Key not found, specify one using -k."
+ return 1}
+ tomb_key=`cat $tomb_key_file`
fi
- tombkey=${tombdir}/${tombfile}
-
- _verbose "load_key: ${tombkey}"
- { test -r "${tombkey}" } || {
- _warning "Key not found, specify one using -k."
- drop_key
- return 1 }
+ _verbose "load_key: ${tomb_key_file}"
# TODO: move this condition for JPEG steg into is_valid_key
- [[ `file "$tombkey"` =~ "JP.G" ]] || {
+ [[ `file "$tomb_key_file"` =~ "JP.G" ]] || {
# if the key file is an image don't check file header
- if ! is_valid_key ${tombkey}; then
+ is_valid_key "${tomb_key}" || {
_warning "The key seems invalid or its format is not known by this version of Tomb."
- drop_key
- return 1
- fi
+
+ # if no BEGIN header found then we try to recover it
+ _warning "Attempting recovery."
+ _key="$tomb_key"
+ tomb_key=""
+ [[ "$_key" =~ "_KDF_" ]] && {
+ tomb_key+=`print $_key | $head -n 1` }
+ tomb_key+="-----BEGIN PGP MESSAGE-----"
+ tomb_key+="$_key"
+ tomb_key+="-----END PGP MESSAGE-----"
+ }
}
- print "$tombkey"
+ tomb_key="$tomb_key"
+ tomb_key_file="$tomb_key_file"
+ dump_secrets
return 0
}
@@ -622,33 +676,32 @@ load_key() {
gpg_decrypt() {
# fix for gpg 1.4.11 where the --status-* options don't work ;^/
gpgver=`gpg --version --no-permission-warning | awk '/^gpg/ {print $3}'`
- local lukspass="$1"
- local keyfile="$2"
+ gpgpass="$tomb_password\n$tomb_key"
if [ "$gpgver" = "1.4.11" ]; then
_verbose "GnuPG is version 1.4.11 - adopting status fix."
- tomb_secret=`print "$lukspass" | \
- gpg --batch --passphrase-fd 0 --no-tty --no-options \
- -d "${keyfile}"`
+ tomb_secret=`print "$gpgpass" | \
+ gpg --batch --passphrase-fd 0 --no-tty --no-options"`
ret=$?
unset lukspass
else # using status-file in gpg != 1.4.11
- res=`safe_filename lukskey`
- [[ $? = 0 ]] || {
- unset lukspass;
- _failure "Fatal error creating temp file." }
+ tmp_create
+ _status=`tmp_new`
+ # [[ $? = 0 ]] || {
+ # unset gpgpass;
+ # _failure "Fatal error creating temp file." }
- tomb_secret=`print "$lukspass" | \
+ tomb_secret=`print "$gpgpass" | \
gpg --batch --passphrase-fd 0 --no-tty --no-options \
--status-fd 2 --no-mdc-warning --no-permission-warning \
- --no-secmem-warning -d "${keyfile}" 2> $res`
+ --no-secmem-warning 2> $_status`
- unset lukspass
- grep 'DECRYPTION_OKAY' $res >-
- ret=$?; rm -f $res
+ unset gpgpass
+ grep 'DECRYPTION_OKAY' $_status > /dev/null
+ ret=$?
fi
return $ret
@@ -660,13 +713,17 @@ gpg_decrypt() {
# be used directly by Luks as a cryptographic key
get_lukskey() {
# $1 is the password, $2 is the keyfile
+ _verbose "get_lukskey"
+
+ [[ "$tomb_key" = "" ]] && {
+ _warning "There is no key loaded"
+ return 1 }
+
+ _password="$1"
- local lukspass="$1"
- local keyfile="$2"
- local exhumedkey
+ exhumedkey=""
- firstline=`head -n1 $keyfile`
- _verbose "get_lukskey XXX $keyfile"
+ firstline=`awk '{print $0; exit}' <<< "$tomb_key"`
# key is KDF encoded
if [[ $firstline =~ '^_KDF_' ]]; then
@@ -674,31 +731,33 @@ get_lukskey() {
case `cut -d_ -f 3 <<<$firstline` in
pbkdf2sha1)
pbkdf2_param=`cut -d_ -f 4- <<<$firstline | tr '_' ' '`
- lukspass=$(tomb-kdb-pbkdf2 ${=pbkdf2_param} 2>- <<<$lukspass)
+ _password=$(tomb-kdb-pbkdf2 ${=pbkdf2_param} 2>- <<<$_password)
;;
*)
_failure "No suitable program for KDF `cut -f 3 <<<$firstline`."
- unset lukspass
+ unset _password
return 1
;;
esac
# key needs to be exhumed from an image
- elif [[ `file "$keyfile"` =~ "JP.G" ]]; then
- exhumedkey="`safe_filename exhumedkey`"
- exhume_key "$keyfile" "$lukspass" "$exhumedkey"
- keyfile="$exhumedkey"
+ elif [[ "$tomb_key_file" =~ "JP.G" ]]; then
+ tmp_create
+ exhumedkey=`tmp_new`
+ exhume_key "$tomb_key_file" "$_password" "$exhumedkey"
+ tomb_key_file="$exhumedkey"
+ tomb_key=`cat $exhumedkey`
fi
# check validity, eventually repair adding headers
- is_valid_key "$keyfile" || {
- _failure "This key is unusable: $keyfile" }
+ is_valid_key || {
+ _failure "This key is unusable: $tomb_key_file" }
- # saves decrypted content into $tomb_secret
- gpg_decrypt "$lukspass" "$keyfile"
- ret="$?"
+ tomb_password="$_password"
+
+ gpg_decrypt # saves decrypted content into $tomb_secret
- { test "$exhumedkey" = "" } || { ${=WIPE} "$exhumedkey" }
+ ret="$?"
_verbose "get_lukskey returns $ret"
return $ret
@@ -708,11 +767,11 @@ get_lukskey() {
# it against the return code of gpg on success returns 0 and prints
# the password (be careful about where you save it!)
ask_key_password() {
- local tombkey="$1"
- local keyname=`basename $tombkey`
+ dump_secrets # QUAA
+ keyname="$tomb_key_file"
_message "A password is required to use key ${keyname}"
- local passok=0
- local tombpass=""
+ passok=0
+ tombpass=""
if [ "$2" = "" ]; then
for c in 1 2 3; do
if [ $c = 1 ]; then
@@ -725,7 +784,7 @@ ask_key_password() {
return 1
fi
- get_lukskey "$tombpass" "$tombkey"
+ get_lukskey "$tombpass"
if [ $? = 0 ]; then
passok=1; _message "Password OK."
@@ -745,9 +804,9 @@ ask_key_password() {
fi
# print the password out in case caller needs to know it
- print "$tombpass"
- unset tombpass
{ test "$passok" = "1" } || { return 1 }
+
+ tomb_password="$tombpass"
return 0
}
@@ -756,12 +815,13 @@ change_passwd() {
_message "Commanded to change password for tomb key $1"
_check_swap
- keyfile="`load_key`"
+ load_key
+ keyfile="$tomb_key_file"
local tmpnewkey lukskey c tombpass tombpasstmp
- tmpnewkey=`safe_filename passnew`
- lukskey=`safe_filename passold`
+ tmp_create
+ tmpnewkey=`tmp_new`
_success "Changing password for $keyfile"
@@ -769,9 +829,9 @@ change_passwd() {
if option_is_set --tomb-old-pwd; then
tomb_old_pwd="`option_value --tomb-old-pwd`"
_verbose "--tomb-old-pwd = $tomb_old_pwd"
- ask_key_password "$keyfile" "$tomb_old_pwd" >-
+ ask_key_password "$keyfile" "$tomb_old_pwd" >& -
else
- ask_key_password "$keyfile" >-
+ ask_key_password "$keyfile" >& -
fi
{ test $? = 0 } || {
@@ -779,21 +839,15 @@ change_passwd() {
# danger zone in which the key is written in clear
- print "$tomb_secret"> "$lukskey"
-
- drop_key
-
if option_is_set --tomb-pwd; then
tomb_new_pwd="`option_value --tomb-pwd`"
_verbose "--tomb-pwd = $tomb_new_pwd"
- gen_key "$lukskey" "$tomb_new_pwd" > "$tmpnewkey"
+ gen_key "$tomb_new_pwd" >> "$tmpnewkey"
else
- gen_key "$lukskey" > "$tmpnewkey"
+ gen_key >> "$tmpnewkey"
fi
- ${=WIPE} "$lukskey"
-
- if ! is_valid_key "$tmpnewkey"; then
+ if ! is_valid_key "`cat $tmpnewkey`"; then
_failure "Error: the newly generated keyfile does not seem valid."
else
# copy the new key as the original keyfile name
@@ -811,54 +865,27 @@ change_passwd() {
# To be called after load_key()
drop_key() {
_verbose "drop_key $tombkey"
- # delete key if temp stored from stdin
- if [[ "$tombkey" =~ "/dev/shm/tomb.load_key_stdin" ]]; then
- { test -r ${tombkey} } && {
- _message "Removing key temporarily stored from stdin"
- ${=WIPE} ${tombkey}; rmdir `dirname ${tombkey}` }
- fi
+# # delete key if temp stored from stdin
+# if [[ "$tombkey" =~ "/dev/shm/tomb.load_key_stdin" ]]; then
+# { test -r ${tombkey} } && {
+# _message "Removing key temporarily stored from stdin"
+# # ${=WIPE} ${tombkey}; rmdir `dirname ${tombkey}` }
+# fi
}
-#$1 is the keyfile we are checking
+# $1 is the encrypted key contents we are checking
is_valid_key() {
- _verbose "is_valid_key $1"
+ _verbose "is_valid_key"
+ _key="$1"
# argument check
- { test "$1" = "" } && {
- _warning "Key file is missing from arguments."; return 1 }
- # file checks
- { test -r "$1" } || {
- _warning "Key file not found: $1"; return 1 }
- { test -f "$1" } || {
- _warning "Key file is not a regular file: $1"; return 1 }
- # this header validity check is a virtuosism by Hellekin
- [[ `file =(awk '/^-+BEGIN/,0' $1)` =~ PGP ]] && {
- if [ "$tombkeydir" = "" ]; then _message "Valid key file found: $1"
- else _message "Valid key file passed from stdin"; fi
+ { test "$_key" = "" } && { _key="$tomb_key" }
+ { test "$_key" = "" } && {
+ _warning "is_valid_key() called without argument."; return 1 }
+
+ [[ "$_key" =~ "BEGIN PGP" ]] && {
+ _message "Key is valid"
return 0 }
- # if no BEGIN header found then we try to recover it
- [[ `file $1 -bi` =~ text/plain ]] && {
- _warning "Key data found with missing headers, attempting recovery."
- local tmp_keyfix=`safe_filename keyfix`
- touch $tmp_keyfix
- # make sure KDF header comes first
- local header=`grep '^_KDF_' $1`
- print "$header" >> $tmp_keyfix
- cat $1 | awk '
-BEGIN {
-print "-----BEGIN PGP MESSAGE-----"
-print
-}
-/^_KDF_/ { next }
-{ print $0 }
-END {
-print "-----END PGP MESSAGE-----"
-}' >> ${tmp_keyfix}
- mv $tmp_keyfix $1
- chown ${_uid}:${_gid} ${1}
- chmod 0600 ${1}
- return 0
- }
- _warning "Invalid key format: $1"
+
return 1
}
@@ -866,18 +893,17 @@ print "-----END PGP MESSAGE-----"
# takes care to encrypt a key
-# honored options: --kdf --tomb-pwd
+# honored options: --kdf --tomb-pwd -o
gen_key() {
-# $1 the lukskey to encrypt
-# $2 is the --cipher-algo to use (string taken by GnuPG)
- local lukskey="$1"
+# $1 the password to use, if not set then ask user
+# -o is the --cipher-algo to use (string taken by GnuPG)
local algopt="`option_value -o`"
local algo="${algopt:-AES256}"
# here user is prompted for key password
- local tombpass=""
- local tombpasstmp=""
- local tombpassarg="$2"
- if [ "$tombpassarg" = "" ]; then
+ tombpass=""
+ tombpasstmp=""
+
+ if [ "$1" = "" ]; then
while true; do
# 3 tries to write two times a matching password
tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password to secure your key"`
@@ -900,7 +926,7 @@ gen_key() {
unset tombpass
done
else
- tombpass="$tombpassarg"
+ tombpass="$1"
_verbose "gen_key takes tombpass from CLI argument: $tombpass"
fi
@@ -935,10 +961,16 @@ gen_key() {
print -n $header
- print "${tombpass}" \
- | gpg --openpgp --force-mdc --cipher-algo ${algo} \
+ cat <<EOF | gpg --openpgp --force-mdc --cipher-algo ${algo} \
--batch --no-options --no-tty --passphrase-fd 0 --status-fd 2 \
- -o - -c -a ${lukskey}
+ -o - -c -a
+${tombpass}
+${tomb_secret}
+EOF
+ # print -n "${tombpass}" \
+ # | gpg --openpgp --force-mdc --cipher-algo ${algo} \
+ # --batch --no-options --no-tty --passphrase-fd 0 --status-fd 2 \
+ # -o - -c -a ${lukskey}
unset tombpass
unset tombpasstmp
@@ -947,7 +979,7 @@ gen_key() {
# prints an array of ciphers available in gnupg (to encrypt keys)
list_gnupg_ciphers() {
# prints an error if GnuPG is not found
- which gpg >- || _failure "gpg (GnuPG) is not found, Tomb cannot function without it."
+ which gpg >& - || _failure "gpg (GnuPG) is not found, Tomb cannot function without it."
ciphers=(`gpg --version | awk '
BEGIN { ciphers=0 }
@@ -962,13 +994,14 @@ BEGIN { ciphers=0 }
# Steganographic function to bury a key inside an image.
# Requires steghide(1) to be installed
bury_key() {
- tombkey="`load_key`"
+ load_key
+ tombkey="$tomb_key_file"
{ test "$tombkey" = "" } && {
_failure "Bury failed: invalid key $tombkey" }
imagefile=$1
- file $imagefile | grep -i JPEG >-
+ file $imagefile | grep -i JPEG > /dev/null
if [ $? != 0 ]; then
_warning "Encode failed: $imagefile is not a jpeg image."
return 1
@@ -1091,7 +1124,8 @@ exhume_key() {
# backuped on paper and hidden in books etc.
engrave_key() {
# load key from options
- tombkey="`load_key`"
+ load_key
+ tombkey="$tomb_key_file"
{ test $? = 0 } || { _failure "No key specified." }
keyname=`basename $tombkey`
pngname="$keyname.qr.png"
@@ -1125,7 +1159,7 @@ engrave_key() {
forge_key() {
# can be specified both as simple argument or using -k
- local destkey="$1"
+ destkey="$1"
{ option_is_set -k } && { destkey="`option_value -k`" }
{ test "$destkey" = "" } && {
@@ -1145,66 +1179,52 @@ forge_key() {
_warning "Forging this key would overwrite an existing file. Operation aborted."
_failure "`ls -lh $destkey`" }
- # create the keyfile in tmpfs so that we leave less traces in RAM
- local keytmp=`safe_dir forge`
- (( $? )) && _failure "Error creating temp dir."
- _verbose "safe_dir at $keytmp"
-
- mount tmpfs "${keytmp}" -t tmpfs -o size=1m
- if [ $? != 0 ]; then
- _warning "Cannot mount tmpfs filesystem in volatile memory."
- rm -r "${keytmp}"
- _failure "Operation aborted."
- fi
-
- local algo
{ option_is_set -o } && { algopt="`option_value -o`" }
algo=${algopt:-AES256}
_message "Commanded to forge key $destkey with cipher algorithm $algo"
- local tombkey="$destkey"
+ tomb_key_file="$destkey"
_message "This operation takes time, keep using this computer on other tasks,"
_message "once done you will be asked to choose a password for your tomb."
_message "To make it faster you can move the mouse around."
_message "If you are on a server, you can use an Entropy Generation Daemon."
- touch ${keytmp}/tomb.tmp
- chmod 0600 ${keytmp}/tomb.tmp
local random_source=/dev/random
if option_is_set --use-urandom; then
random_source=/dev/urandom
fi
_verbose "Data dump using ${DD[1]} from $random_source"
- ${=DD} bs=1 count=256 if=$random_source of=${keytmp}/tomb.tmp
-
- if ! [ -r ${keytmp}/tomb.tmp ]; then
+ tomb_secret=`${=DD} bs=1 count=256 if=$random_source`
+ { test $? = 0 } || {
_warning "Cannot generate encryption key."
- umount ${keytmp}
- rm -r $keytmp
- _failure "Operation aborted."
- fi
+ _failure "Operation aborted." }
- _success "Choose the password of your key: ${tombkey}"
+ # here the global var tomb_secret contains the nude secret
+
+ _success "Choose the password of your key: ${tomb_key_file}"
_message "(You can also change it later using 'tomb passwd'.)"
- touch ${tombkey}
- chown ${_uid}:${_gid} ${tombkey}
- chmod 0600 ${tombkey}
+ touch ${tomb_key_file}
+ chown ${_uid}:${_gid} ${tomb_key_file}
+ chmod 0600 ${tomb_key_file}
- tombname="$tombkey"
+ tombname="$tomb_key_file"
# the gen_key() function takes care of the new key's encryption
if option_is_set --tomb-pwd; then
tomb_new_pwd="`option_value --tomb-pwd`"
_verbose "--tomb-pwd = $tomb_new_pwd"
- gen_key "${keytmp}/tomb.tmp" "$tomb_new_pwd" > "$tombkey"
+ gen_key "$tomb_new_pwd" >> "$tomb_key_file"
else
- gen_key "${keytmp}/tomb.tmp" > "$tombkey"
+ gen_key >> "$tomb_key_file"
fi
+ # load the key contents
+ tomb_key=`cat "$tomb_key_file"`
+
# this does a check on the file header
- if ! is_valid_key ${tombkey}; then
+ is_valid_key "${tomb_key}" || {
_warning "The key does not seem to be valid."
_warning "Dumping contents to screen:"
cat ${tombkey}
@@ -1212,17 +1232,11 @@ forge_key() {
umount ${keytmp}
rm -r $keytmp
_failure "Operation aborted."
- fi
-
- ${=WIPE} ${keytmp}/tomb.tmp # no need really, but anyway
- umount ${keytmp}
- rm -r ${keytmp}
-
- chown ${_uid}:${_gid} ${tombkey}
+ }
- _message "Done forging $tombkey"
+ _message "Done forging $tomb_key_file"
_success "Your key is ready:"
- ls -lh ${tombkey}
+ ls -lh ${tomb_key_file}
}
# Dig a tomb, means that it will create an empty file to be formatted
@@ -1306,8 +1320,8 @@ lock_tomb_with_key() {
_verbose "Tomb found: ${tombdir}/${tombfile}"
- nstloop=`losetup -f` # get the number for next loopback device
- losetup -f ${tombdir}/${tombfile} # allocates the next loopback for our file
+ lo_mount "${tombdir}/${tombfile}"
+ nstloop=`lo_new`
_verbose "Loop mounted on ${nstloop}"
@@ -1316,19 +1330,20 @@ lock_tomb_with_key() {
if [ $? = 0 ]; then
# is it a LUKS encrypted nest? then bail out and avoid reformatting it
_warning "The tomb was already locked with another key."
- losetup -d ${nstloop}
_failure "Operation aborted. I cannot lock an already locked tomb. Go dig a new one."
else
_message "Fine, this tomb seems empty."
fi
# load key from options or file
- tombkey=`load_key`
+ load_key
+
{ test $? = 0 } || {
- losetup -d $nstloop
_failure "Aborting operations: error loading key." }
# make sure to call drop_key later
+ dump_secrets
+
# the encryption cipher for a tomb can be set when locking using -o
if option_is_set -o; then
cipher="`option_value -o`"
@@ -1343,39 +1358,33 @@ lock_tomb_with_key() {
if option_is_set --tomb-pwd; then
tomb_pwd="`option_value --tomb-pwd`"
_verbose "--tomb-pwd = $tomb_pwd"
- ask_key_password "$tombkey" "$tomb_pwd" >-
+ ask_key_password "$tombkey" "$tomb_pwd" >& -
else
- ask_key_password "$tombkey" >-
+ ask_key_password "$tombkey" >& -
fi
{ test $? = 0 } || {
- losetup -d ${nstloop}
_failure "No valid password supplied." }
_success "Locking ${tombfile} with ${tombkey}"
_message "Formatting Luks mapped device."
- print "$tomb_secret" | \
+ print -n "$tomb_secret" | \
cryptsetup --key-file - --batch-mode \
--cipher ${cipher} --key-size 256 --key-slot 0 \
luksFormat ${nstloop}
if ! [ $? = 0 ]; then
_warning "cryptsetup luksFormat returned an error."
- losetup -d $nstloop
_failure "Operation aborted."
fi
- print "$tomb_secret" | \
+ print -n "$tomb_secret" | \
cryptsetup --key-file - \
--cipher ${cipher} luksOpen ${nstloop} tomb.tmp
if ! [ $? = 0 ]; then
_warning "cryptsetup luksOpen returned an error."
- losetup -d $nstloop
_failure "Operation aborted."
fi
- # cleanup tombs
- drop_key # make sure all temp files are out
-
_message "Formatting your Tomb with Ext3/Ext4 filesystem."
${=MKFS} ${tombname} /dev/mapper/tomb.tmp
@@ -1384,11 +1393,9 @@ lock_tomb_with_key() {
_warning "Your tomb ${tombfile} may be corrupted."
fi
- sync
+ # sync
cryptsetup luksClose tomb.tmp
- losetup -d ${nstloop}
-
_message "Done locking $tombname using Luks dm-crypt ${create_cipher}"
_success "Your tomb is ready in ${tombdir}/${tombfile} and secured with key ${tombkey}"
@@ -1400,25 +1407,24 @@ change_tomb_key() {
_message "Commanded to reset key for tomb $2"
_check_swap
- newkey="`load_key`"
+ load_key
+ newkey="$tomb_key_file"
{ test $? = 0 } || {
_failure "Aborting operations: error loading new key from -k" }
oldkey="$1"
- { is_valid_key "$oldkey" } || {
+ { is_valid_key "`cat $oldkey`" } || {
_failure "Old key invalid. 1st argument of setkey must be a valid key file." }
{ is_valid_tomb "$2" } || {
_failure "Tomb invalid. 2nd argument of setkey must be a valid tomb file." }
- nstloop=`losetup -f`
- { test $? = 255 } && {
- _failure "Too many tombs are open. Please close any of them to proceed." }
- losetup -f "$2"
+ lo_mount "$2"
+ nstloop=`lo_new`
+
cryptsetup isLuks ${nstloop}
# is it a LUKS encrypted nest? we check one more timesee cryptsetup(1)
{ test $? = 0 } || {
- losetup -d "$nstloop"
_failure "Not a valid LUKS encrypted volume: $2" }
# we have everything, prepare to mount
@@ -1434,50 +1440,46 @@ change_tomb_key() {
if option_is_set --tomb-pwd; then
tomb_new_pwd="`option_value --tomb-pwd`"
_verbose "--tomb-pwd = $tomb_new_pwd"
- ask_key_password "$newkey" "$tomb_new_pwd" >-
+ ask_key_password "$newkey" "$tomb_new_pwd" >& -
else
- ask_key_password "$newkey" >-
+ ask_key_password "$newkey" >& -
fi
{ test $? = 0 } || {
_failure "No valid password supplied for the new key." }
- newkeyfile="`safe_filename newkey`"
- print "$tomb_secret" > $newkeyfile
+
+ tmp_create
+ newkeyfile=`tmp_new`
+ print -n "$tomb_secret" > $newkeyfile
# load the old key
if option_is_set --tomb-old-pwd; then
tomb_old_pwd="`option_value --tomb-old-pwd`"
_verbose "--tomb-old-pwd = $tomb_old_pwd"
- ask_key_password "$oldkey" "$tomb_old_pwd" >-
+ ask_key_password "$oldkey" "$tomb_old_pwd" >& -
else
- ask_key_password "$oldkey" >-
+ ask_key_password "$oldkey" >& -
fi
{ test $? = 0 } || {
_failure "No valid password supplied for the old key." }
# luksOpen the tomb (not really mounting, just on the loopback)
- print "$tomb_secret" | \
+ print -n "$tomb_secret" | \
cryptsetup --key-file - luksOpen ${nstloop} ${mapper}
{ test $? = 0 } || {
- losetup -d "$nstloop"
_failure "Unexpected error in luksOpen." }
- print "$tomb_secret"| \
+ print -n "$tomb_secret"| \
cryptsetup --key-file - luksChangeKey "$nstloop" "$newkeyfile"
{ test $? = 0 } || {
- losetup -d "$nstloop"
_failure "Unexpected error in luksChangeKey." }
${=WIPE} "$newkeyfile"
cryptsetup luksClose "${mapper}"
{ test $? = 0 } || {
- losetup -d "$nstloop"
_failure "Unexpected error in luksClose." }
- drop_key
- losetup -d ${nstloop}
-
_success "Succesfully changed key for tomb: $2"
_message "The new key is: $newkey"
@@ -1534,15 +1536,11 @@ mount_tomb() {
# set up variables to be used
# the full path is made with $tombdir/$tombfile
- local tombkey
- local tombfile
- local tombdir
- local tombname
- local tombpass
tombfile=`basename ${1}`
tombdir=`dirname ${1}`
# check file type (if its a Luks fs)
- file ${tombdir}/${tombfile} | grep -i 'luks encrypted file' 2>&1 >-
+ file ${tombdir}/${tombfile} | \
+ grep -i 'luks encrypted file' 2>&1 > /dev/null
if [ $? != 0 ]; then
_warning "$1 is not a valid tomb file, operation aborted."
return 1
@@ -1551,7 +1549,9 @@ mount_tomb() {
_verbose "Tomb found: ${tombdir}/${tombfile}"
# load_key called here
- tombkey=`load_key`
+ load_key
+ tombkey="$tomb_key_file"
+
{ test $? = 0 } || {
_failure "Aborting operations: error loading key $tombkey" }
@@ -1563,7 +1563,7 @@ mount_tomb() {
fi
# check if its already open
- mount -l | grep "${tombfile}.*\[$tombname\]$" 2>&1 >-
+ mount -l | grep "${tombfile}.*\[$tombname\]$" 2>&1 > /dev/null
if [ $? = 0 ]; then
_warning "$tombname is already open."
_message "Here below its status is reported:"
@@ -1573,19 +1573,13 @@ mount_tomb() {
_success "Opening $tombfile on $tombmount"
-
- nstloop=`losetup -f`
- if [ $? = 255 ]; then
- _failure "Too many tombs open. Please close any of them to open another tomb."
- fi
- _verbose "Next free loop device: $nstloop"
- losetup -f ${tombdir}/${tombfile}
+ lo_mount "${tombdir}/${tombfile}"
+ nstloop=`lo_new`
cryptsetup isLuks ${nstloop}
if [ $? != 0 ]; then
# is it a LUKS encrypted nest? see cryptsetup(1)
_warning "$tombfile is not a valid Luks encrypted storage file."
- losetup -d ${nstloop}
return 1
fi
_message "This tomb is a valid LUKS encrypted device."
@@ -1612,31 +1606,28 @@ mount_tomb() {
_verbose "Tomb key: $tombkey"
# take the name only, strip extensions
- keyname=${tombkey%%.*}
- _verbose "Tomb name: $keyname (to be engraved)"
+ _verbose "Tomb name: $tombname (to be engraved)"
if option_is_set --tomb-pwd; then
tomb_pwd="`option_value --tomb-pwd`"
_verbose "--tomb-pwd = $tomb_pwd"
- ask_key_password "$tombkey" "$tomb_pwd" >-
+ ask_key_password "$tombkey" "$tomb_pwd" >& -
else
- ask_key_password "$tombkey" >-
+ ask_key_password "$tombkey" >& -
fi
{ test $? = 0 } || {
- losetup -d ${nstloop}
_failure "No valid password supplied." }
print -n "$tomb_secret" | \
cryptsetup --key-file - luksOpen ${nstloop} ${mapper}
- # key dropped here
- drop_key
-
if ! [ -r /dev/mapper/${mapper} ]; then
- losetup -d ${nstloop}
_failure "Failure mounting the encrypted file."
fi
+ # preserve the loopdev after exit
+ lo_preserve "$nstloop"
+
# array: [ cipher, keysize, loopdevice ]
tombstat=(`cryptsetup status ${mapper} | awk '
/cipher:/ {print $2}
@@ -1648,7 +1639,7 @@ mount_tomb() {
_message "Checking filesystem via $tombstat[3]"
fsck -p -C0 /dev/mapper/${mapper}
_verbose "Tomb engraved as $tombname"
- tune2fs -L ${tombname} /dev/mapper/${mapper} >-
+ tune2fs -L ${tombname} /dev/mapper/${mapper} > /dev/null
# we need root from here on
mkdir -p $tombmount
@@ -1927,7 +1918,7 @@ BEGIN { main="" }
# index files in all tombs for search
# $1 is optional, to specify a tomb
index_tombs() {
- { command -v updatedb >- } || {
+ { command -v updatedb >& - } || {
_failure "Cannot index tombs on this system: updatedb (mlocate) not installed." }
updatedbver=`updatedb --version | grep '^updatedb'`
@@ -1949,7 +1940,7 @@ index_tombs() {
_success "Creating and updating search indexes."
# start the LibreOffice document converter if installed
- { command -v unoconv >- } && {
+ { command -v unoconv >& - } && {
unoconv -l 2>- &
_verbose "unoconv listener launched."
sleep 1 }
@@ -1967,7 +1958,8 @@ index_tombs() {
# here we use swish to index file contents
{ test $SWISH = 1 } && {
_message "Indexing $tombname contents..."
- swishrc=`safe_filename swish`
+ tmp_create
+ swishrc=`tmp_new`
cat <<EOF > $swishrc
# index directives
@@ -2044,7 +2036,7 @@ EOF
done
}
search_tombs() {
- { command -v locate >- } || {
+ { command -v locate >& - } || {
_failure "Cannot index tombs on this system: updatedb (mlocate) not installed." }
updatedbver=`updatedb --version | grep '^updatedb'`
@@ -2111,7 +2103,8 @@ resize_tomb() {
tombname=${tombfile%%\.*}
# load key from options or file
- local tombkey="`load_key`"
+ load_key
+ tombkey="$tomb_key_file"
# make sure to call drop_key later
{ test -r "$tombkey" } || {
_failure "Aborting operations: key not found, use -k" }
@@ -2134,7 +2127,7 @@ resize_tomb() {
delta="$(( $newtombsize - $oldtombsize ))"
- act "Generating ${tombfile} of ${newtombsize}MiB"
+ _message "Generating ${tombfile} of ${newtombsize}MiB"
_verbose "Data dump using ${DD[1]} from /dev/urandom"
${=DD} if=/dev/urandom bs=1048576 count=${delta} >> ${tombdir}/${tombfile}
@@ -2145,48 +2138,38 @@ resize_tomb() {
if option_is_set --tomb-pwd; then
tomb_pwd="`option_value --tomb-pwd`"
_verbose "--tomb-pwd = $tomb_pwd"
- ask_key_password "$tombkey" "$tomb_pwd" >-
+ ask_key_password "$tombkey" "$tomb_pwd" >& -
else
- ask_key_password "$tombkey" >-
+ ask_key_password "$tombkey" >& -
fi
{ test $? = 0 } || {
_failure "No valid password supplied." }
- local nstloop=`losetup -f`
- if [ $? = 255 ]; then
- _failure "Too many tombs opened. Please close any of them to open another tomb."
- fi
-
- losetup -f ${tombdir}/${tombfile}
+ lo_mount "${tombdir}/${tombfile}"
+ nstloop=`lo_new`
- local mapdate=`date +%s`
- local mapper="tomb.${tombname}.${mapdate}.`basename $nstloop`"
+ mapdate=`date +%s`
+ mapper="tomb.${tombname}.${mapdate}.`basename $nstloop`"
- print "$tomb_secret" | \
+ print -n "$tomb_secret" | \
cryptsetup --key-file - luksOpen ${nstloop} ${mapper}
- drop_key # cleanup after load_key
-
if ! [ -r /dev/mapper/${mapper} ]; then
- losetup -d ${nstloop}
_failure "Failure mounting the encrypted file."
fi
cryptsetup resize "${mapper}"
if [ $? != 0 ]; then
- losetup -d ${nstloop}
_failure "cryptsetup failed to resize $mapper"
fi
e2fsck -p -f /dev/mapper/${mapper}
if [ $? != 0 ]; then
- losetup -d ${nstloop}
_failure "e2fsck failed to check $mapper"
fi
resize2fs /dev/mapper/${mapper}
if [ $? != 0 ]; then
- losetup -d ${nstloop}
_failure "resize2fs failed to resize $mapper"
fi
@@ -2194,7 +2177,6 @@ resize_tomb() {
# close and free the loop device
cryptsetup luksClose "${mapper}"
- losetup -d ${nstloop}
return 0
}
@@ -2382,7 +2364,6 @@ main() {
# subcommands_opts[recompose]=""
# subcommands_opts[install]=""
subcommands_opts[askpass]=""
- subcommands_opts[mktemp]=""
subcommands_opts[source]=""
subcommands_opts[resize]="f -force -ignore-swap s: -size=s k: -key=k -tomb-pwd: "
subcommands_opts[check]="-ignore-swap "
@@ -2554,7 +2535,6 @@ main() {
# internal commands useful to developers
'source') return 0 ;;
askpass) ask_password $PARAM[1] $PARAM[2] ;;
- mktemp) safe_dir $PARAM[1] ;;
__default)
cat <<EOF
@@ -2597,6 +2577,7 @@ EOF
# {{{ Run
check_bin
+check_shm
main $@
ret=$?