URI:
       tMajor fixes to KDF and steganography - tomb - the crypto undertaker
  HTML git clone git://parazyd.org/tomb.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 8e9fc7e8030a8bf9305f7ca92e18fb3bb41c90ef
   DIR parent 4d6c0bf5cc0502357bfe59c7282a73662909a172
  HTML Author: Jaromil <jaromil@dyne.org>
       Date:   Wed, 12 Jun 2013 13:33:54 +0200
       
       Major fixes to KDF and steganography
       
       With the advent of a proper test suite many bugs were found and
       squashed both in the way KDF and steghide were used.
       
       Key validation func is_valid_key() now attempts recovery for keys
       tthat have broken headers or are naked text (back-compat to old exhume).
       
       KDF and steg now work correctly.
       
       Diffstat:
         M tomb                                |     286 ++++++++++++++-----------------
       
       1 file changed, 132 insertions(+), 154 deletions(-)
       ---
   DIR diff --git a/tomb b/tomb
       t@@ -48,6 +48,7 @@ for arg in ${argv}; do OLDARGS+=($arg); done
        DD="dd"
        WIPE="rm -f"
        MKFS="mkfs.ext3 -q -F -j -L"
       +KDF=1
        STEGHIDE=1
        MKTEMP=1
        RESIZER=1
       t@@ -65,8 +66,8 @@ typeset -h _gid
        typeset -h _tty
        
        # Set a sensible PATH
       -PATH=/sbin:/bin:/usr/sbin:/usr/bin
       -[[ "$TOMBEXEC" =~ "^/usr/local" ]] && PATH="/usr/local/bin:/usr/local/sbin:$PATH"
       +# PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
       +
        
        # }}}
        
       t@@ -104,9 +105,9 @@ safe_dir() {
                if _have_shm; then
                    xxx "safe_dir creating $1 dir in RAM"
                    if (( $MKTEMP )); then
       -                mktemp -d /dev/shm/$1.$$.XXXXXXX
       +                mktemp -d /dev/shm/tomb.$1.$$.XXXXXXX
                    else
       -                dir="/dev/shm/$1.$$.$RANDOM$RANDOM"
       +                dir="/dev/shm/tomb.$1.$$.$RANDOM$RANDOM"
                        mkdir -m 0700 -p "$dir"
                        print "$dir"
                    fi
       t@@ -125,8 +126,8 @@ safe_dir() {
        safe_filename() {
            _have_shm || die "No access to shared memory on this system, sorry."
            (( $MKTEMP )) && \
       -        mktemp -u /dev/shm/$1.$$.XXXXXXX || \
       -        print "/dev/shm/$1.$$.$RANDOM$RANDOM"
       +        mktemp -u /dev/shm/tomb.$1.$$.XXXXXXX || \
       +        print "/dev/shm/tomb.$1.$$.$RANDOM$RANDOM"
        }
        
        # Check if swap is activated
       t@@ -267,6 +268,14 @@ Options:
         -n     don't process the hooks found in tomb
         -o     mount options used to open (default: rw,noatime,nodev)
         -f     force operation (i.e. even if swap is active)
       +EOF
       +    { test "$KDF" = 1 } && {
       +        cat <<EOF
       + --kdf  seconds generate passwords against dictionary attacks
       +EOF
       +    }
       +    
       +cat <<EOF
        
         -h     print this help
         -v     print version, license and list of available ciphers
       t@@ -419,17 +428,8 @@ check_bin() {
            # check for resize
            command -v e2fsck resize2fs > /dev/null || RESIZER=0
        
       -    if which tomb-kdf-pbkdf2 &> /dev/null; then
       -        KDF_PBKDF2="tomb-kdf-pbkdf2"
       -    else
       -        local our_pbkdf2
       -        our_pbkdf2="$(dirname $(readlink -f $TOMBEXEC))/kdf/tomb-kdf-pbkdf2"
       -        if which $our_pbkdf2 &> /dev/null; then
       -            KDF_PBKDF2=$our_pbkdf2
       -        else
       -            KDF_PBKDF2=
       -        fi
       -    fi
       +    # check for KDF auxiliary tools
       +    command -v tomb-kdb-pbkdf2 > /dev/null || KDF=0
        
        }
        
       t@@ -451,7 +451,7 @@ load_key() {
                if [[ "`option_value -k`" == "-" ]]; then
                    xxx "load_key reading from stdin"
                    # take key from stdin
       -            tombkeydir=`safe_dir tomb`
       +            tombkeydir=`safe_dir load_key`
                    xxx "tempdir is $tombkeydir"
                    cat > ${tombkeydir}/stdin.tmp
                    tombdir=${tombkeydir}
       t@@ -551,8 +551,8 @@ change_passwd() {
        
            local tmpnewkey lukskey c tombpass tombpasstmp
        
       -    tmpnewkey=`safe_filename tombnew`
       -    lukskey=`safe_filename tombluks`
       +    tmpnewkey=`safe_filename passnew`
       +    lukskey=`safe_filename passold`
        
            _success "Changing password for $keyfile"
        
       t@@ -594,9 +594,34 @@ drop_key() {
        #$1 is the keyfile we are checking
        is_valid_key() {
            # this header validity check is a virtuosism by Hellekin
       -    [[ `file =(awk '/^-+BEGIN/,0' $1) -bi` =~ application/pgp ]]
       -    return $?
       +    [[ `file =(awk '/^-+BEGIN/,0' $1)` =~ PGP ]] && 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
       +}
       +
        
        # Gets a key file and a password, prints out the decoded contents to
        # be used directly by Luks as a cryptographic key
       t@@ -611,11 +636,8 @@ get_lukskey() {
                _verbose "KDF: `cut -d_ -f 3 <<<$firstline`"
                case `cut -d_ -f 3 <<<$firstline` in
                    pbkdf2sha1)
       -                if [[ -z $KDF_PBKDF2 ]]; then
       -                    die "The tomb use kdf method 'pbkdf2', which is unsupported on your system"
       -                fi
                        pbkdf2_param=`cut -d_ -f 4- <<<$firstline | tr '_' ' '`
       -                tombpass=$(${KDF_PBKDF2} ${=pbkdf2_param} 2> /dev/null <<<$tombpass)
       +                tombpass=$(tomb-kdb-pbkdf2 ${=pbkdf2_param} 2> /dev/null <<<$tombpass)
                        ;;
                    *)
                        _failure "No suitable program for KDF `cut -f 3 <<<$firstline`"
       t@@ -628,26 +650,26 @@ get_lukskey() {
            # fix for gpg 1.4.11 where the --status-* options don't work ;^/
            gpgver=`gpg --version | awk '/^gpg/ {print $3}'`
            if [ "$gpgver" = "1.4.11" ]; then
       -    xxx "GnuPG is version 1.4.11 - adopting status fix"
       -
       -    print ${tombpass} | \
       -        gpg --batch --passphrase-fd 0 --no-tty --no-options -d "${keyfile}"
       -    unset tombpass
       -    ret=$?
       -
       +        xxx "GnuPG is version 1.4.11 - adopting status fix"
       +        
       +        print ${tombpass} | \
       +            gpg --batch --passphrase-fd 0 --no-tty --no-options -d "${keyfile}"
       +        ret=$?
       +        unset tombpass
       +        
            else # using status-file in gpg != 1.4.12
        
       -    res=`safe_filename tomb.open`
       -    { test $? = 0 } || { unset tombpass; die "Fatal error creating temp file." }
       -
       -    print ${tombpass} | \
       -        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
       -    unset tombpass
       -    grep 'DECRYPTION_OKAY' $res
       -    ret=$?; rm -f $res
       -
       +        res=`safe_filename lukskey`
       +        { test $? = 0 } || { unset tombpass; die "Fatal error creating temp file." }
       +        
       +        print ${tombpass} | \
       +            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
       +        unset tombpass
       +        grep 'DECRYPTION_OKAY' $res
       +        ret=$?; rm -f $res
       +        
            fi
            xxx "get_lukskey returns $ret"
            return $ret
       t@@ -689,42 +711,25 @@ gen_key() {
                xxx "gen_key takes tombpass from CLI argument: $tombpass"
            fi
        
       -
       +    header=""
       +    { option_is_set --kdf } && {
            # KDF is a new key strenghtening technique against brute forcing
            # see: https://github.com/dyne/Tomb/issues/82
       -    _verbose "KDF method chosen is: '`option_value --kdf`'"
       -    kdf_method=$(cut -d: -f1 <<<`option_value --kdf` )
       -    case $kdf_method in
       -        pbkdf2)
       -            if [[ -z $KDF_PBKDF2 ]]; then
       -                die "The tomb use kdf method 'pbkdf2', which is unsupported on your system"
       -            fi
       +        itertime="`option_value --kdf`"
       +        _verbose "KDF itertime chosen: $itertime"
                    # --kdf takes one parameter: iter time (on present machine) in seconds
       -            seconds=$(cut -d: -f2 -s <<<`option_value --kdf`)
       -            if [[ -z $seconds ]]; then
       -                seconds=1
       -            fi
       -            local -i microseconds
       -            microseconds=$((seconds*1000000))
       -            _verbose "Microseconds: $microseconds"
       -            pbkdf2_salt=`${KDF_PBKDF2}-gensalt`
       -            pbkdf2_iter=`${KDF_PBKDF2}-getiter $microseconds`
       +        local -i microseconds
       +        microseconds=$((itertime*1000000))
       +        _verbose "Microseconds: $microseconds"
       +        pbkdf2_salt=`tomb-kdb-pbkdf2-gensalt`
       +        pbkdf2_iter=`tomb-kdb-pbkdf2-getiter $microseconds`
                    # We use a length of 64bytes = 512bits (more than needed!?)
       -            tombpass=`${KDF_PBKDF2} $pbkdf2_salt $pbkdf2_iter 64 <<<"${tombpass}"`
       -
       -            header="_KDF_pbkdf2sha1_${pbkdf2_salt}_${pbkdf2_iter}_64\n"
       -            ;;
       -        ""|null)
       +        tombpass=`tomb-kdb-pbkdf2 $pbkdf2_salt $pbkdf2_iter 64 <<<"${tombpass}"`
       +        
       +        header="_KDF_pbkdf2sha1_${pbkdf2_salt}_${pbkdf2_iter}_64\n"
       +    }
        
       -            header=""
       -            ;;
       -        *)
       -            _warning "KDF method non recognized"
       -            return 1
       -            header=""
       -            ;;
       -    esac
       -    echo -n $header
       +    print -n $header
        
            print "${tombpass}" \
                | gpg --openpgp --batch --no-options --no-tty --passphrase-fd 0 2>/dev/null \
       t@@ -749,15 +754,14 @@ BEGIN { ciphers=0 }
        }
        
        # Steganographic function to bury a key inside an image.
       +# Requires steghide(1) to be installed
        bury_key() {
       -    tombkey=$1
       -    imagefile=$2
       +    tombkey="`option_value -k`"
       +    imagefile=$1
       +
       +    { is_valid_key ${tombkey} } || {
       +        die "Bury failed: not a tomb key $tombkey" }
        
       -    file $tombkey | grep PGP > /dev/null
       -    if [ $? != 0 ]; then
       -        _warning "encode failed: $tombkey is not a tomb key"
       -        return 1
       -    fi
            file $imagefile | grep JPEG > /dev/null
            if [ $? != 0 ]; then
                _warning "encode failed: $imagefile is not a jpeg image"
       t@@ -765,27 +769,16 @@ bury_key() {
            fi
        
            _success "Encoding key $tombkey inside image $imagefile"
       -    _message "please choose a password for the encoding"
       -
       -    # here user is prompted for key password
       -    for c in 1 2 3; do
       -        # 3 tries to write two times a matching password
       -        tombpass=`exec_as_user ${TOMBEXEC} askpass "Steg password for ${tombkey}"`
       -        tombpasstmp=$tombpass
       -        tombpass=`exec_as_user ${TOMBEXEC} askpass "Steg password for ${tombkey} (again)"`
       -        if [ "$tombpasstmp" = "$tombpass" ]; then
       -            break;
       -        fi
       -        unset tombpasstmp
       -        unset tombpass
       -    done
       +    _message "please confirm the key password for the encoding"
       +    tombpass=`ask_key_password $tombkey`
       +    { test $? = 0 } || {
       +        _warning "Wrong password supplied."
       +        die "You shall not bury a key whose password is unknown to you."
       +    }
        
       -    if [ -z $tombpass ]; then
       -        _warning "passwords don't match, aborting operation."
       -        return 1
       -    fi
       +    # we omit armor strings since having them as constants can give
       +    # ground to effective attacks on steganography
        
       -# Requires steghide to be installed
            awk '
        /^-----/ {next}
        /^Version/ {next}
       t@@ -806,8 +799,8 @@ bury_key() {
        }
        # Steganographic function to exhume a key buries into an image
        exhume_key() {
       -    tombname=$1
       -    imagefile=$2
       +    tombkey="`option_value -k`"
       +    imagefile=$1
            res=1
        
            file $imagefile | grep JPEG > /dev/null
       t@@ -816,44 +809,35 @@ exhume_key() {
                return 1
            fi
        
       -    keyfile=${tombname%%\.*}.tomb.key
       -    if [[ -e "$keyfile" ]]; then
       -        _warning "Key file $keyfile already exist."
       -        return 1
       +    if [[ -e "$tombkey" ]]; then
       +        _warning "File exists: $tombkey"
       +        { option_is_set -f } || {
       +            _warning "Make explicit use of --force to overwrite"
       +            die "Refusing to overwrite file. Operation aborted." }
       +        _warning "Use of --force selected: overwriting."
       +        rm -f ${tombkey}
            fi
       -    _message "Trying to exhume a key out of image $imagefile"
       -    for c in 1 2 3; do
       -        if [ $c = 1 ]; then
       -            tombpass=`exec_as_user ${TOMBEXEC} askpass "Steg password for ${keyfile}"`
       -        else
       -            tombpass=`exec_as_user ${TOMBEXEC} askpass "Steg password for $keyfile (retry $c)"`
       -        fi
        
       +    _message "Trying to exhume a key out of image $imagefile"
       +    if option_is_set --tomb-pwd; then
       +            tombpass=`option_value --tomb-pwd`
       +            xxx "ask_key_password takes tombpass from CLI argument: $tombpass"
       +    else
       +        tombpass=`exec_as_user ${TOMBEXEC} askpass "Steg password for ${tombkey}"`
       +    fi
                # always steghide required
       -        steghide extract -sf ${imagefile} -p ${tombpass} -xf - \
       -            | awk '
       -BEGIN {
       -print "-----BEGIN PGP MESSAGE-----"
       -}
       -{ print $0 }
       -END {
       -print "-----END PGP MESSAGE-----"
       -}' > ${keyfile}
       -
       -        if [ "`cat ${keyfile} | wc -l`" != "3" ]; then
       -            _success "${keyfile} succesfully decoded"
       -            res=0
       -            break;
       -        fi
       -    done
       +    steghide extract -sf ${imagefile} -p ${tombpass} -xf ${tombkey}
       +    res=$?
        
            unset tombpass
       -
       -    if [ $res != 0 ]; then
       -        _warning "nothing found."
       +    
       +    if [ $res = 0 ]; then
       +        _success "${tombkey} succesfully decoded"
       +        return 0
            fi
        
       -    return $res
       +    _warning "nothing found in $imagefile"
       +    return 1
        }
        
        # }}} - Key handling
       t@@ -885,7 +869,7 @@ forge_key() {
        
        
            # create the keyfile in tmpfs so that we leave less traces in RAM
       -    keytmp=`safe_dir tomb`
       +    keytmp=`safe_dir forge`
            (( $? )) && die "error creating temp dir"
            xxx "safe_dir at $keytmp"
        
       t@@ -1646,7 +1630,7 @@ resize_tomb() {
                die "Aborting operations: error loading key $tombkey" }
            # make sure to call drop_key later
        
       -    local tmp_resize=`safe_filename tmbrsz`
       +    local tmp_resize=`safe_filename resize`
            local newtombsize=$opts[-s]
            local oldtombsize=$(( `stat -c %s "$1" 2>/dev/null` / 1048576 ))
            local mounted_tomb=`mount -l |
       t@@ -1892,10 +1876,10 @@ main() {
            subcommands_opts[open]="f n -nohook=n k: -key=k o: -mount-options=o -ignore-swap -sudo-pwd: -tomb-pwd:"
            subcommands_opts[mount]=${subcommands_opts[open]}
        
       -    subcommands_opts[create]="f -force -ignore-swap s: -size=s k: -key=k -kdf: -sudo-pwd: -tomb-pwd: -use-urandom"
       +    subcommands_opts[create]="" # deprecated, will issue warning
        
            subcommands_opts[forge]="f -force -ignore-swap k: -key=k -kdf: -tomb-pwd: -use-urandom"
       -    subcommands_opts[dig]="f -forge -ignore-swap s: -size=s"
       +    subcommands_opts[dig]="f -force -ignore-swap s: -size=s"
            subcommands_opts[lock]="f -force -ignore-swap s: -size=s k: -key=k -sudo-pwd: -tomb-pwd:"
        
            subcommands_opts[passwd]="f -ignore-swap -kdf: -tomb-old-pwd: -tomb-pwd: "
       t@@ -1908,8 +1892,8 @@ main() {
            subcommands_opts[search]=""
        
            subcommands_opts[help]=""
       -    subcommands_opts[bury]=""
       -    subcommands_opts[exhume]=""
       +    subcommands_opts[bury]="f -force k: -key=k -tomb-pwd:"
       +    subcommands_opts[exhume]="f -force k: -key=k -tomb-pwd:"
            subcommands_opts[decompose]=""
            subcommands_opts[recompose]=""
            subcommands_opts[install]=""
       t@@ -2055,24 +2039,18 @@ main() {
                    usage
                    ;;
                bury)
       -            if [ "$STEGHIDE" = 0 ]; then
       -                _warning "steghide not installed. Cannot bury your key"
       -                return 1
       -            fi
       -            bury_key $PARAM[1] $PARAM[2]
       +            { test "$STEGHIDE" = 0 } && {
       +                die "Steghide not installed: cannot bury keys into images." }
       +            bury_key $PARAM[1]
                    ;;
                exhume)
       -            if [ "$STEGHIDE" = 0 ]; then
       -                _warning "steghide not installed. Cannot exhume your key"
       -                return 1
       -            fi
       -            exhume_key $PARAM[1] $PARAM[2]
       +            { test "$STEGHIDE" = 0 } && {
       +                die "Steghide not installed: cannot exhume keys from images." }
       +            exhume_key $PARAM[1]
                    ;;
                resize)
       -            if [ "$RESIZER" = 0 ]; then
       -                _warning "resize2fs not installed. Cannot resize your tomb."
       -                return 1
       -            fi
       +            { test "$RESIZER" = 0 } && {
       +                die "Resize2fs not installed: cannot resize tombs." }
                    check_priv
                    resize_tomb $PARAM[1]
                    ;;