Skip to content

Commit 79b73d3

Browse files
committed
Improve argon2 handling and KDF in general
Previously it wasn't possible to use argon2 as KDF function without the tomb tools from extras/kdf-keys being available. To change that behaviour introduce checks on the ARGON2 variable. Additionally add a fallback function to create a salt that is compatible to tomb-kdb-pbkdf2-gensalt. Options specific for the different supported KDF algorithm are reorganized. Some options align between the various KDF and some are unique to them. The output of -h is enhanced with the various --kdf options and depends on the available optional tools. argon2 specific cli arguments won't be displayed if argon2 is not available. Add case for results beside argon2 and pbkdf2. Key creation won't be stopped, just a warning is issued that the resulting key won't be protected via KDF. Regarding the cli options. The argument for the suboption --kdf is made optional. In that regard one needs to make sure, that if --kdf is the last option before an argument one needs to use - to separate or use -k. Example: tomb forge --kdf - testkey.tomb Example: tomb forge --kdf -k testkey.tomb Example: tomb forge -k testkey.tomb --kdf Additonally the kdf options are reorganized, which is a possible breaking change for scripts or GUI helpers. * --kdftype is changed to --kdf * --kdfiter is introduced as replacement the for previous --kdf definition * --kdfpar is introduced to support the parallelism option of argon2 Only --kdf is mandatory to get a key which is protected with KDF. For every other option safe defaults are set and can be optionally adjusted. KDF related subcommand options are removed where they don't come into play. gen_key() is only called in forge and passwd. Closes #526
1 parent 857895a commit 79b73d3

File tree

1 file changed

+58
-31
lines changed

1 file changed

+58
-31
lines changed

tomb

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ typeset -i SPHINX=1
6565
typeset -i RESIZER=1
6666
typeset -i RECOLL=1
6767
typeset -i QRENCODE=1
68+
typeset -i ARGON2=1
6869

6970
# Default mount options
7071
typeset MOUNTOPTS="rw,noatime,nodev"
@@ -840,8 +841,13 @@ usage() {
840841
_print " --sphx-host host associated with the key (for use with pitchforkedsphinx)"
841842
}
842843

843-
[[ $KDF == 1 ]] && {
844-
_print " --kdf forge keys armored against dictionary attacks"
844+
[[ $KDF == 1 ]] || [[ $ARGON2 == 1 ]] && {
845+
_print " --kdf forge keys armored against dictionary attacks (pbkdf2 (default), argon2)"
846+
_print " --kdfiter Number of iterations (meaning depending on KDF algorithm) (pbkdf2, argon2)"
847+
}
848+
[[ $ARGON2 == 1 ]] && {
849+
_print " --kdfmem memory to be used (argon2)"
850+
_print " --kdfpar number of threads (argon2)"
845851
}
846852

847853
echo
@@ -1313,11 +1319,14 @@ get_lukskey() {
13131319
kdf_salt="${firstline[(ws:_:)3]}"
13141320
kdf_ic="${firstline[(ws:_:)4]}"
13151321
kdf_mem="${firstline[(ws:_:)5]}"
1322+
kdf_par="${firstline[(ws:_:)6]}"
1323+
# ToDo also parse kdf_len?
13161324
_message "Unlocking KDF key protection (::1 kdf::)" $kdf_hash
13171325
_verbose "KDF salt: $kdf_salt"
13181326
_verbose "KDF ic: $kdf_ic"
13191327
_verbose "KDF mem: $kdf_mem"
1320-
_password=$(argon2 $kdf_salt -m $kdf_mem -t $kdf_ic -l 64 -r 2>/dev/null <<<$_password)
1328+
_verbose "KDF # threads: $kdf_par"
1329+
_password=$(argon2 $kdf_salt -m $kdf_mem -t $kdf_ic -p $kdf_par -l 64 -r 2>/dev/null <<<$_password)
13211330
;;
13221331

13231332
*)
@@ -1589,50 +1598,68 @@ gen_key() {
15891598
fi
15901599

15911600
header=""
1592-
[[ $KDF == 1 ]] && {
1601+
[[ $KDF == 1 ]] || [[ $ARGON2 == 1 ]] && {
15931602
{ option_is_set --kdf } && {
1594-
# KDF is a new key strenghtening technique against brute forcing
1603+
# KDF is a key strengthening technique against brute forcing
15951604
# see: https://github.com/dyne/Tomb/issues/82
1596-
itertime="`option_value --kdf`"
1605+
# Two algorithm currently supported:
1606+
# * pbkdf2 (covers against time)
1607+
# * argon2 (covers against time, memory and parallelismn)
1608+
1609+
# --kdfiter takes one parameter: time cost in seconds
1610+
# (argon2 has a default of 3 iterations;
1611+
# the resulting itertime with this default is considered safe enough for pbkdf2)
1612+
itertime="`option_value --kdfiter`"
1613+
itertime=${itertime:-3}
1614+
15971615
# removing support of floating points because they can't be type checked well
15981616
# if [[ "$itertime" != <-> ]]; then
15991617
# unset tombpass
16001618
# unset tombpasstmp
1601-
# _warning "Wrong argument for --kdf: must be an integer number (iteration seconds)."
1619+
# _warning "Wrong argument for --kdfiter: must be an integer number (iteration seconds)."
16021620
# _failure "Depending on the speed of machines using this tomb, use 1 to 10, or more"
16031621
# return 1
16041622
# fi
1605-
# # --kdf takes one parameter: iter time (on present machine) in seconds
16061623

1607-
kdftype="`option_value --kdftype`"
1624+
# Generating salt (either via tomb-kdb-pbkdf2 or a shell fallback)
1625+
if $(command -v tomb-kdb-pbkdf2-gensalt 1>/dev/null 2>/dev/null); then
1626+
kdfsalt=`tomb-kdb-pbkdf2-gensalt`
1627+
else
1628+
kdfsalt=$(LC_CTYPE=C tr -cd 'a-f0-9' < /dev/random | head -c 64)
1629+
fi
1630+
_message "kdf salt: ::1 kdfsalt::" $kdfsalt
1631+
1632+
# --kdf takes one optional parameter: what KDF
1633+
# (pbkdf being the default)
1634+
kdftype="`option_value --kdf`"
16081635
kdftype=${kdftype:-pbkdf2}
16091636
case ${kdftype} in
1610-
pbkdf2)
1637+
pbkdf2)
16111638
local -i microseconds
16121639
microseconds=$(( itertime * 1000000 ))
1613-
_success "Using KDF, iteration time: ::1 microseconds::" $microseconds
1614-
_message "generating salt"
1615-
pbkdf2_salt=`tomb-kdb-pbkdf2-gensalt`
1640+
_success "Using pbkdf2 as KDF, iteration time: ::1 microseconds::" $microseconds
16161641
_message "calculating iterations"
16171642
pbkdf2_iter=`tomb-kdb-pbkdf2-getiter $microseconds`
16181643
_message "encoding the password"
16191644
# We use a length of 64bytes = 512bits (more than needed!?)
1620-
tombpass=`tomb-kdb-pbkdf2 $pbkdf2_salt $pbkdf2_iter 64 <<<"${tombpass}"`
1621-
1622-
header="_KDF_pbkdf2sha1_${pbkdf2_salt}_${pbkdf2_iter}_64\n"
1645+
tombpass=`tomb-kdb-pbkdf2 $kdfsalt $pbkdf2_iter 64 <<<"${tombpass}"`
1646+
header="_KDF_pbkdf2sha1_${kdfsalt}_${pbkdf2_iter}_64\n"
16231647
;;
1624-
argon2)
1625-
_success "Using KDF Argon2"
1648+
argon2)
1649+
_success "Using Argon2 as KDF"
1650+
_message "iterations: ::1 kdfiterations::" $itertime
16261651
kdfmem="`option_value --kdfmem`"
16271652
kdfmem=${kdfmem:-18}
16281653
_message "memory used: 2^::1 kdfmemory::" $kdfmem
1629-
itertime="`option_value --kdf`"
1630-
itertime=${itertime:-3}
1631-
kdfsalt=`tomb-kdb-pbkdf2-gensalt`
1632-
_message "kdf salt: ::1 kdfsalt::" $kdfsalt
1633-
_message "kdf iterations: ::1 kdfiterations::" $itertime
1634-
tombpass=`argon2 $kdfsalt -m $kdfmem -t $itertime -l 64 -r <<<"${tombpass}"`
1635-
header="_KDF_argon2_${kdfsalt}_${itertime}_${kdfmem}_64\n"
1654+
kdfpar="`option_value --kdfpar`"
1655+
kdfpar=${kdfpar:-1}
1656+
_message "parallelismn: ::1 kdfparallel::" $kdfpar
1657+
tombpass=`argon2 $kdfsalt -m $kdfmem -t $itertime -p $kdfpar -l 64 -r <<<"${tombpass}"`
1658+
header="_KDF_argon2_${kdfsalt}_${itertime}_${kdfmem}_${kdfpar}_64\n"
1659+
;;
1660+
*)
1661+
_warning "unrecognized KDF ::1::" $kdftype
1662+
_warning "key won\'t be protected via a KDF implementation"
16361663
;;
16371664
esac
16381665
}
@@ -2095,7 +2122,7 @@ forge_key() {
20952122
$destkey $algo
20962123

20972124
[[ $KDF == 1 ]] && { ! option_is_set -g } && {
2098-
_message "Using KDF to protect the key password (`option_value --kdf` rounds)"
2125+
_message "Using KDF to protect the key password"
20992126
}
21002127

21012128
TOMBKEYFILE="$destkey" # Set global variable
@@ -3268,19 +3295,19 @@ main() {
32683295
main_opts=(q -quiet=q D -debug=D h -help=h v -version=v f -force=f -tmp: U: G: T: -no-color -unsafe g -gpgkey=g -sudo:)
32693296
subcommands_opts[__default]=""
32703297
# -o in open and mount is used to pass alternate mount options
3271-
subcommands_opts[open]="n -nohook=n k: -kdf: -kdftype: -kdfmem: o: -ignore-swap -tomb-pwd: r: R: -sphx-host: -sphx-user: p -preserve-ownership=p"
3298+
subcommands_opts[open]="n -nohook=n k: o: -ignore-swap -tomb-pwd: r: R: -sphx-host: -sphx-user: p -preserve-ownership=p"
32723299
subcommands_opts[mount]=${subcommands_opts[open]}
32733300

32743301
subcommands_opts[create]="" # deprecated, will issue warning
32753302

32763303
# -o in forge and lock is used to pass an alternate cipher.
3277-
subcommands_opts[forge]="-ignore-swap k: -kdf: -kdftype: -kdfmem: o: -tomb-pwd: -use-random r: R: -sphx-host: -sphx-user: "
3304+
subcommands_opts[forge]="-ignore-swap k: -kdf:: -kdfiter: -kdfmem: -kdfpar: o: -tomb-pwd: -use-random r: R: -sphx-host: -sphx-user: "
32783305
subcommands_opts[dig]="-ignore-swap s: -size=s "
3279-
subcommands_opts[lock]="-ignore-swap k: -kdf: -kdftype: -kdfmem: o: -tomb-pwd: r: R: -sphx-host: -sphx-user: -filesystem: "
3280-
subcommands_opts[setkey]="k: -ignore-swap -kdf: -kdftype: -kdfmem: -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: "
3306+
subcommands_opts[lock]="-ignore-swap k: o: -tomb-pwd: r: R: -sphx-host: -sphx-user: -filesystem: "
3307+
subcommands_opts[setkey]="k: -ignore-swap -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: "
32813308
subcommands_opts[engrave]="k: "
32823309

3283-
subcommands_opts[passwd]="k: -ignore-swap -kdf: -kdftype: -kdfmem: -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: "
3310+
subcommands_opts[passwd]="k: -ignore-swap -kdf:: -kdfiter: -kdfmem: -kdfpar: -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: "
32843311
subcommands_opts[close]=""
32853312
subcommands_opts[help]=""
32863313
subcommands_opts[slam]=""

0 commit comments

Comments
 (0)