tKDF: modularize code to support kdf everywhere - tomb - the crypto undertaker HTML git clone git://parazyd.org/tomb.git DIR Log DIR Files DIR Refs DIR README DIR LICENSE --- DIR commit 6003623fe587d49bc3dcf5c3856bb4b7b4577c21 DIR parent 25512c5864ed3a8d09dc8b98a5e548c93b709c1b HTML Author: boyska <piuttosto@logorroici.org> Date: Wed, 5 Sep 2012 17:47:00 +0200 KDF: modularize code to support kdf everywhere Diffstat: M src/tomb | 319 +++++++++++++++---------------- 1 file changed, 158 insertions(+), 161 deletions(-) --- DIR diff --git a/src/tomb b/src/tomb t@@ -24,7 +24,7 @@ # }}} # {{{ GLOBAL VARIABLES VERSION=1.3 -DATE=Nov/2012 +DATE="Nov/2012" TOMBEXEC=$0 TOMBOPENEXEC="${TOMBEXEC}-open" typeset -a OLDARGS t@@ -174,6 +174,8 @@ check_bin() { 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 t@@ -270,15 +272,19 @@ ask_password() { title="Insert tomb password" if [ $2 ]; then title="$2"; fi - cat <<EOF | GTK2_RC_FILES=${GTK2_RC} pinentry 2>/dev/null | awk '/^D / { sub(/^D /, ""); print }' + output=`cat <<EOF | GTK2_RC_FILES=${GTK2_RC} pinentry 2>/dev/null | tail -n +7 OPTION ttyname=$TTY OPTION lc-ctype=$LANG SETTITLE $title SETDESC $1 SETPROMPT Password: GETPIN -EOF - +EOF` + if [[ `tail -n1 <<<$output` =~ ERR ]]; then + return 1 + fi + head -n1 <<<$output | awk '/^D / { sub(/^D /, ""); print }' + return 0 } # }}} # {{{ - Drop privileges t@@ -301,7 +307,7 @@ check_priv() { xxx "Using sudo for root execution of 'tomb ${(f)OLDARGS}'" # check if sudo has a timestamp active sudok=false - sudo -n ${TOMBEXEC} &> /dev/null +# sudo -n ${TOMBEXEC} &> /dev/null if ! option_is_set --sudo-pwd; then if [ $? != 0 ]; then # if not then ask a password cat <<EOF | pinentry 2>/dev/null | awk '/^D / { sub(/^D /, ""); print }' | sudo -S -v t@@ -745,68 +751,14 @@ create_tomb() { fi _success "Setup your secret key file ${tombkey}" - - # here user is prompted for key password - if ! option_is_set --tomb-pwd; then - for c in 1 2 3; do - # 3 tries to write two times a matching password - tombpass=`exec_as_user ${TOMBEXEC} askpass "Secure key for ${tombname}"` - tombpasstmp=$tombpass - tombpass=`exec_as_user ${TOMBEXEC} askpass "Secure key for ${tombname} (again)"` - if [ "$tombpasstmp" = "$tombpass" ]; then - break; - fi - unset tombpasstmp - unset tombpass - done - else - tombpass=`option_value --tomb-pwd` - fi - - if [ -z $tombpass ]; then - umount ${keytmp} - losetup -d $nstloop - rm -r $keytmp - die "passwords don't match, aborting operation" - fi - - - _verbose "KDF method chosen is: '`option_value --kdf`'" - kdf_method=$(cut -d: -f1 <<<`option_value --kdf` ) - case $kdf_method in - pbkdf2) -#one parameter: iter time 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` - tombpass=`${KDF_PBKDF2} $pbkdf2_salt $pbkdf2_iter 64 <<<${tombpass}` #64bytes=512bits is the key length (huge!) - header="_KDF_pbkdf2sha1_${pbkdf2_salt}_${pbkdf2_iter}_64\n" - ;; - ""|null) - - header="" - ;; - *) - _warning "KDF method non recognized" - return 1 - header="" - ;; - esac - touch $tombkey + touch ${tombkey} chown ${_uid}:${_gid} ${tombkey} chmod 0600 ${tombkey} - ( echo -n $header; gpg \ - --openpgp --batch --no-options --no-tty --passphrase-fd 0 2>/dev/null \ - -o - -c -a ${keytmp}/tomb.tmp <<< ${tombpass} ) > $tombkey - - unset tombpass + gen_key ${keytmp}/tomb.tmp > ${tombkey} + if ! is_valid_key ${tombkey}; then + _warning "The key does not seem to be valid" + fi # if [ $? != 0 ]; then # _warning "setting password failed: gnupg returns 2" # umount ${keytmp} t@@ -853,7 +805,116 @@ create_tomb() { _message "done creating $tombname encrypted storage (using Luks dm-crypt ${create_cipher}:sha256)" _success "Your tomb is ready in ${tombdir}/${tombfile} and secured with key ${tombkey}" +} + +#internal use +#$1 is the keyfile we are checking +is_valid_key() { + [[ `file =(awk '/^-+BEGIN/,0' $1) -bi` =~ application/pgp ]] + return $? +} +#internal use +#$1 is the password, $2 is the keyfile +#will output the lukskey +get_lukskey() { + local tombpass=$1 + keyfile=$2 + firstline=`head -n1 $keyfile` + if [[ $firstline =~ '^_KDF_' ]]; then + _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) + ;; + *) + _failure "No suitable program for KDF `cut -f 3 <<<$firstline`" + unset tombpass + return 1 + ;; + esac + fi + gpg --batch --passphrase-fd 0 --no-tty --no-options \ + -d "${keyfile}" 2> /dev/null <<< ${tombpass} + ret=$? + unset tombpass + return $ret +} + +#internal use +#$1 the lukskey to encrypt +#it respects --kdf and --tomb-pwd +gen_key() { + local lukskey=$1 + # here user is prompted for key password + local tombpass="" + local tombpasstmp="" + if ! option_is_set --tomb-pwd; then + while true; do + # 3 tries to write two times a matching password + tombpass=`exec_as_user ${TOMBEXEC} askpass "Secure key for ${tombname}"` + if [[ $? != 0 ]]; then + die "User aborted" + fi + if [ -z $tombpass ]; then + _warning "you set empty password, which is not possible" + continue + fi + tombpasstmp=$tombpass + tombpass=`exec_as_user ${TOMBEXEC} askpass "Secure key for ${tombname} (again)"` + if [[ $? != 0 ]]; then + die "User aborted" + fi + if [ "$tombpasstmp" = "$tombpass" ]; then + break; + fi + unset tombpasstmp + unset tombpass + done + else + tombpass=`option_value --tomb-pwd` + fi + + + + _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 +#one parameter: iter time 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` + tombpass=`${KDF_PBKDF2} $pbkdf2_salt $pbkdf2_iter 64 <<<"${tombpass}"` #64bytes=512bits is the key length (huge!) + header="_KDF_pbkdf2sha1_${pbkdf2_salt}_${pbkdf2_iter}_64\n" + ;; + ""|null) + + header="" + ;; + *) + _warning "KDF method non recognized" + return 1 + header="" + ;; + esac + echo -n $header + gpg --openpgp --batch --no-options --no-tty --passphrase-fd 0 2>/dev/null \ + -o - -c -a ${lukskey} <<< "${tombpass}" + unset tombpass } # }}} t@@ -969,33 +1030,20 @@ mount_tomb() { _warning "Password is required for key ${keyname}" for c in 1 2 3; do if ! option_is_set --tomb-pwd; then - if [ $c = 1 ]; then - tombpass=`exec_as_user ${TOMBEXEC} askpass "Open tomb ${keyname}"` - else - tombpass=`exec_as_user ${TOMBEXEC} askpass "Open tomb $keyname (retry $c)"` + tombpass=`exec_as_user ${TOMBEXEC} askpass "Open tomb ${keyname}"` + if [[ $? != 0 ]]; then + die "User aborted" fi else tombpass=`option_value --tomb-pwd` fi -#TODO: read the first line: if it looks like a KDF, do KDF - firstline=`head -n1 < $tombkey` - if [[ $firstline =~ '^_KDF_' ]]; then - _verbose "KDF: `cut -d_ -f 3 <<<$firstline`" - case `cut -d_ -f 3 <<<$firstline` in - pbkdf2sha1) - pbkdf2_param=`cut -d_ -f 4- <<<$firstline | tr '_' ' '` - tombpass=$(${KDF_PBKDF2} ${=pbkdf2_param} 2> /dev/null <<<$tombpass) - ;; - *) - _failure "No suitable program for KDF `cut -f 3 <<<$firstline`" - return 1 - ;; - esac - fi - (gpg --batch --passphrase-fd 0 --no-tty --no-options \ - -d "${tombkey}" 2> /dev/null <<< ${tombpass} ) \ - | cryptsetup --key-file - luksOpen ${nstloop} ${mapper} + get_lukskey "${tombpass}" ${tombkey} | \ + cryptsetup --key-file - luksOpen ${nstloop} ${mapper} + local ret=$? unset tombpass + if [[ $ret != 0 ]]; then + continue + fi # if key was from stdin delete temp file and dir if [ $tombkeydir ]; then t@@ -1232,93 +1280,44 @@ change_passwd() { # check the keyfile if ! [ -r $keyfile ]; then - _warning "key not found: $keyfile" - return 1 + _warning "key not found: $keyfile" + return 1 fi - file $keyfile | grep PGP > /dev/null - if [ $? != 0 ]; then - _warning "file doesn't seems to be a tomb key: $keyfile" - _warning "operation aborted." - return 1 + if ! is_valid_key $keyfile ; then + _warning "file doesn't seems to be a tomb key: $keyfile" + _warning "operation aborted." + return 1 fi - local tmpnewkey tmpoldkey c tombpass tombpasstmp + local tmpnewkey lukskey c tombpass tombpasstmp tmpnewkey=`safe_filename tomb` - tmpoldkey=`safe_filename tomb` + lukskey=`safe_filename tomb` _success "Changing password for $keyfile" keyname=`basename $keyfile` - for c in 1 2 3; do - if [ $c = 1 ]; then - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type old password for ${keyname}" "Change tomb key password"` - else - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type old password for ${keyname} (retry $c)" "Change tomb key password"` - fi - gpg --batch --no-options --no-tty --passphrase-fd 0 -o "${tmpoldkey}" -d $keyfile <<< "$tombpass" &> /dev/null - if [ $? = 0 ]; then - tombpass="ok" + while true; do + tombpass=`exec_as_user ${TOMBEXEC} askpass "Type old password for ${keyname}" "Change tomb key password"` + if [[ $? == 1 ]]; then + die "User aborted" + fi + if get_lukskey "${tombpass}" ${keyfile} > ${lukskey}; then break fi done - if [ "$tombpass" != "ok" ]; then - _warning "You typed an Invalid old password. Operation aborted." - # /dev/null because the file may not exist - ${=WIPE} "${tmpnewkey}" 2> /dev/null - ${=WIPE} "${tmpoldkey}" 2> /dev/null - return 1 - fi + gen_key $lukskey > $tmpnewkey - for c in 1 2 3; do - # 3 tries to write two times a matching password - if [ $c = 1 ]; then - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password for ${keyname}" "Change tomb key password"` - else - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password for ${keyname} (retry $c)" "Change tomb key password"` - fi - tombpasstmp=$tombpass - tombpass=`exec_as_user ${TOMBEXEC} askpass "Type the new password again" "Change tomb key password"` - if [ "$tombpasstmp" = "$tombpass" ]; then - break; - fi - unset tombpasstmp - unset tombpass - done - - if [ -z $tombpass ]; then - _warning "You mistyped the new password. Operation aborted." - # /dev/null because the file cannot exists - ${=WIPE} "${tmpnewkey}" 2> /dev/null - ${=WIPE} "${tmpoldkey}" 2> /dev/null - return 1 + if ! is_valid_key $tmpnewkey; then + # wipe all temp file + ${=WIPE} "${tmpnewkey}" + ${=WIPE} "${lukskey}" + die "Error: the newly generated keyfile does not seem valid" fi - gpg \ - --openpgp --batch --no-options --no-tty --passphrase-fd 0 \ - -o "${tmpnewkey}" -c -a ${tmpoldkey} <<< ${tombpass} - - unset tombpass - - if [ $? != 0 ]; then - _warning "Cannot change your key passphrase" - # /dev/null because the file cannot exists - ${=WIPE} "${tmpnewkey}" 2> /dev/null - ${=WIPE} "${tmpoldkey}" 2> /dev/null - return 1 - fi - - # wipe the previous, original, key - ${=WIPE} "${keyfile}" # copy the new key as the original keyfile name cp "${tmpnewkey}" "${keyfile}" - - _message "Cleaning environment" - # wipe all temp file - ${=WIPE} "${tmpnewkey}" - ${=WIPE} "${tmpoldkey}" - _success "Your passphrase was successfully updated." return 0 t@@ -1417,9 +1416,8 @@ resize_tomb() { else tombpass=`exec_as_user ${TOMBEXEC} askpass "$keyname (retry $c)"` fi - (gpg --batch --passphrase-fd 0 --no-tty --no-options \ - -d "${tombkey}" 2> /dev/null <<< ${tombpass} ) \ - | cryptsetup --key-file - luksOpen ${nstloop} ${mapper} + get_lukskey "${tombpass}" ${tombkey} | \ + cryptsetup --key-file - luksOpen ${nstloop} ${mapper} unset tombpass t@@ -1747,7 +1745,7 @@ main() { subcommands_opts[open]="f n -nohook=n k: -key=k U: -uid=U G: -gid=G o: -mount-options=o -ignore-swap -sudo-pwd: -tomb-pwd:" subcommands_opts[mount]=${subcommands_opts[open]} subcommands_opts[create]="f s: -size=s -force k: -key=k U: -uid=U G: -gid=G -ignore-swap -kdf: -sudo-pwd: -tomb-pwd: -use-urandom" - subcommands_opts[passwd]="f -ignore-swap" + subcommands_opts[passwd]="f -ignore-swap -kdf: " subcommands_opts[close]="-sudo-pwd: U: -uid=U G: -gid=G" subcommands_opts[help]="" subcommands_opts[slam]="" t@@ -1762,7 +1760,7 @@ main() { subcommands_opts[mktemp]="" subcommands_opts[source]="" subcommands_opts[status]="" - subcommands_opts[resize]="s: -size=s k: -key=k" + subcommands_opts[resize]="s: -size=s k: -key=k U: -uid=U G: -gid=G" subcommands_opts[check]="-ignore-swap" # subcommands_opts[translate]="" t@@ -1862,7 +1860,6 @@ main() { umount_tomb $PARAM[1] ;; passwd) - check_priv change_passwd $PARAM[1] ;; list)