KDF support for argon2 memory intensive algorithm (#432)

* KDF support for argon2 memory intensive algorithm

following many requests, here is support for argon2 KDF to be switched
on using --kdftype argon2 (--kdf iterations --kdfmem memory)

effective memory required is 2^memory KiB, defaults to 18 (262 MiB)
number of iterations are still specified as --kdf argument

requires the argon2 reference C implementation from P-H-C
also requires tomb-kdb-pbkdf2-gensalt in extras/kdf-keys

example usage:
tomb forge -k argon.key --kdf 10 --kdftype argon2

* manual updates for argon2
This commit is contained in:
Jaromil 2022-02-20 22:05:01 +01:00 committed by GitHub
parent 03c93ef976
commit 8ceeca8769
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 43 deletions

View File

@ -39,19 +39,17 @@ with random data, decreasing the tomb's security.
.B .B
.IP "forge" .IP "forge"
Creates a new \fIkey\fR and prompts the user for a \fIpassword\fR to Creates a new \fIkey\fR and prompts the user for a \fIpassword\fR to protect
protect its usage using symmetric encryption. This operation uses its usage using symmetric encryption. This operation uses random data from a
random data from a non-blocking source (/dev/urandom) and it may take non-blocking source (/dev/urandom) and it may take long only in some cases; to
long only in some cases; to switch using a blocking source the switch using a blocking source the \fI--use-random\fR flag can be used. The
\fI--use-random\fR flag can be used. The \fI-g\fR option switches on \fI-g\fR option switches on the use of a GPG key instead of a password
the use of a GPG key instead of a password (asymmetric encryption), (asymmetric encryption), then the \fI-r\fR option indicates the recipient key;
then the \fI-r\fR option indicates the recipient key; more recipient more recipient GPG ids can be indicated (comma separated). The default cipher
GPG ids can be indicated (comma separated). The default cipher to to protect the key is AES256, a custom one can be specified using the \fI-o\fR
protect the key is AES256, a custom one can be specified using the option, for a list of supported ciphers use \fI-v\fR. For additional protection
\fI-o\fR option, for a list of supported ciphers use \fI-v\fR. For against dictionary attacks on keys, the \fI--kdf\fR option can be used when
additional protection against dictionary attacks on keys, the forging a key, making sure that the binaries in \fIextras/kdf\fR were compiled
\fI--kdf\fR option can be used when forging a key, making sure that
the \fItomb-kdb-pbkdf2\fR binaries in \fIextras/kdf\fR were compiled
and installed on the system. and installed on the system.
.B .B
@ -269,11 +267,22 @@ can be one or more GPG key ID, comma separated. All GPG keys must be
trusted keys in GPG. trusted keys in GPG.
.B .B
.IP "--kdf \fI<itertime>\fR" .IP "--kdf \fI<itertime>\fR"
Activate the KDF feature against dictionary attacks when creating a Activate the KDF feature against dictionary attacks when creating a key: forces
key: forces a delay of \fI<itertime>\fR times every time this key is a delay of \fI<itertime>\fR times every time this key is used. The actual time
used. The actual time to wait depends on the CPU speed of the to wait depends on the CPU speed (default) or the RAM size (argon2) of the
computer where the key is used. Using 5 or 10 is a sane amount for computer where the key is used. Using 5 or 10 is a sane amount for modern
modern computers, the value is multiplied by 1 million. computers, the value is multiplied by 1 million.
.B
.IP "--kdftype \fIargon2 | pbkdf2\fR"
Adopt the \fIargon2\fR algorithm for KDF, stressing the RAM capacity rather
than the CPU speed of the computer decrypting the tomb. Requires the
\fIargon2\fR binary by P-H-C to be installed, as packaged by most distros.
Default is \fIpbkdf2\fR.
.B
.IP "--kdfmem \fI<memory>\fR"
In case of \fIargon2\fR KDF algorithm, this value specifies the size of RAM
used: it consists of a number which is the elevated power of two in bytes.
Default is 18 which is 262 MiB (2^18 bytes).
.B .B
.IP "--sudo \fI<executable>\fR" .IP "--sudo \fI<executable>\fR"
Select a different tool than sudo for privilege escalation. Select a different tool than sudo for privilege escalation.

82
tomb
View File

@ -889,7 +889,7 @@ function _print() {
_list_optional_tools() { _list_optional_tools() {
typeset -a _deps typeset -a _deps
_deps=(gettext dcfldd shred steghide) _deps=(gettext dcfldd shred steghide)
_deps+=(resize2fs tomb-kdb-pbkdf2 qrencode swish-e unoconv lsof) _deps+=(resize2fs tomb-kdb-pbkdf2 argon2 qrencode swish-e unoconv lsof)
for d in $_deps; do for d in $_deps; do
_print "`which $d`" _print "`which $d`"
done done
@ -945,6 +945,8 @@ _ensure_dependencies() {
command -v resize2fs 1>/dev/null 2>/dev/null || RESIZER=0 command -v resize2fs 1>/dev/null 2>/dev/null || RESIZER=0
# Check for KDF auxiliary tools # Check for KDF auxiliary tools
command -v tomb-kdb-pbkdf2 1>/dev/null 2>/dev/null || KDF=0 command -v tomb-kdb-pbkdf2 1>/dev/null 2>/dev/null || KDF=0
# Check for ARGON2 KDF auxiliary tools
command -v argon2 1>/dev/null 2>/dev/null || ARGON2=0
# Check for Swish-E file content indexer # Check for Swish-E file content indexer
command -v swish-e 1>/dev/null 2>/dev/null || SWISH=0 command -v swish-e 1>/dev/null 2>/dev/null || SWISH=0
# Check for QREncode for paper backups of keys # Check for QREncode for paper backups of keys
@ -1203,6 +1205,18 @@ get_lukskey() {
_verbose "KDF len: $kdf_len" _verbose "KDF len: $kdf_len"
_password=$(tomb-kdb-pbkdf2 $kdf_salt $kdf_ic $kdf_len 2>/dev/null <<<$_password) _password=$(tomb-kdb-pbkdf2 $kdf_salt $kdf_ic $kdf_len 2>/dev/null <<<$_password)
;; ;;
"argon2")
kdf_salt="${firstline[(ws:_:)3]}"
kdf_ic="${firstline[(ws:_:)4]}"
kdf_mem="${firstline[(ws:_:)5]}"
_message "Unlocking KDF key protection (::1 kdf::)" $kdf_hash
_verbose "KDF salt: $kdf_salt"
_verbose "KDF ic: $kdf_ic"
_verbose "KDF mem: $kdf_mem"
_password=$(argon2 $kdf_salt -m $kdf_mem -t $kdf_ic -l 64 -r 2>/dev/null <<<$_password)
;;
*) *)
_failure "No suitable program for KDF ::1 program::." $pbkdf_hash _failure "No suitable program for KDF ::1 program::." $pbkdf_hash
unset _password unset _password
@ -1478,26 +1492,44 @@ gen_key() {
# see: https://github.com/dyne/Tomb/issues/82 # see: https://github.com/dyne/Tomb/issues/82
itertime="`option_value --kdf`" itertime="`option_value --kdf`"
# removing support of floating points because they can't be type checked well # removing support of floating points because they can't be type checked well
if [[ "$itertime" != <-> ]]; then # if [[ "$itertime" != <-> ]]; then
unset tombpass # unset tombpass
unset tombpasstmp # unset tombpasstmp
_warning "Wrong argument for --kdf: must be an integer number (iteration seconds)." # _warning "Wrong argument for --kdf: must be an integer number (iteration seconds)."
_failure "Depending on the speed of machines using this tomb, use 1 to 10, or more" # _failure "Depending on the speed of machines using this tomb, use 1 to 10, or more"
return 1 # return 1
fi # fi
# --kdf takes one parameter: iter time (on present machine) in seconds # # --kdf takes one parameter: iter time (on present machine) in seconds
local -i microseconds
microseconds=$(( itertime * 1000000 ))
_success "Using KDF, iteration time: ::1 microseconds::" $microseconds
_message "generating salt"
pbkdf2_salt=`tomb-kdb-pbkdf2-gensalt`
_message "calculating iterations"
pbkdf2_iter=`tomb-kdb-pbkdf2-getiter $microseconds`
_message "encoding the password"
# We use a length of 64bytes = 512bits (more than needed!?)
tombpass=`tomb-kdb-pbkdf2 $pbkdf2_salt $pbkdf2_iter 64 <<<"${tombpass}"`
header="_KDF_pbkdf2sha1_${pbkdf2_salt}_${pbkdf2_iter}_64\n" kdftype="`option_value --kdftype`"
kdftype=${kdftype:-pbkdf2}
case ${kdftype} in
pbkdf2)
local -i microseconds
microseconds=$(( itertime * 1000000 ))
_success "Using KDF, iteration time: ::1 microseconds::" $microseconds
_message "generating salt"
pbkdf2_salt=`tomb-kdb-pbkdf2-gensalt`
_message "calculating iterations"
pbkdf2_iter=`tomb-kdb-pbkdf2-getiter $microseconds`
_message "encoding the password"
# We use a length of 64bytes = 512bits (more than needed!?)
tombpass=`tomb-kdb-pbkdf2 $pbkdf2_salt $pbkdf2_iter 64 <<<"${tombpass}"`
header="_KDF_pbkdf2sha1_${pbkdf2_salt}_${pbkdf2_iter}_64\n"
;;
argon2)
_success "Using KDF Argon2"
kdfmem="`option_value --kdfmem`"
kdfmem=${kdfmem:-18}
_message "memory used: 2^::1 kdfmemory::" $kdfmem
kdfsalt=`tomb-kdb-pbkdf2-gensalt`
_message "kdf salt: ::1 kdfsalt::" $kdfsalt
_message "kdf iterations: ::1 kdfiterations::" $itertime
tombpass=`argon2 $kdfsalt -m $kdfmem -t $itertime -l 64 -r <<<"${tombpass}"`
header="_KDF_argon2_${kdfsalt}_${itertime}_${kdfmem}_64\n"
;;
esac
} }
} }
print $header >> "$1" print $header >> "$1"
@ -3176,19 +3208,19 @@ main() {
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:) 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:)
subcommands_opts[__default]="" subcommands_opts[__default]=""
# -o in open and mount is used to pass alternate mount options # -o in open and mount is used to pass alternate mount options
subcommands_opts[open]="n -nohook=n k: -kdf: o: -ignore-swap -tomb-pwd: r: R: -sphx-host: -sphx-user: p -preserve-ownership=p" 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"
subcommands_opts[mount]=${subcommands_opts[open]} subcommands_opts[mount]=${subcommands_opts[open]}
subcommands_opts[create]="" # deprecated, will issue warning subcommands_opts[create]="" # deprecated, will issue warning
# -o in forge and lock is used to pass an alternate cipher. # -o in forge and lock is used to pass an alternate cipher.
subcommands_opts[forge]="-ignore-swap k: -kdf: o: -tomb-pwd: -use-random r: R: -sphx-host: -sphx-user: " subcommands_opts[forge]="-ignore-swap k: -kdf: -kdftype: -kdfmem: o: -tomb-pwd: -use-random r: R: -sphx-host: -sphx-user: "
subcommands_opts[dig]="-ignore-swap s: -size=s " subcommands_opts[dig]="-ignore-swap s: -size=s "
subcommands_opts[lock]="-ignore-swap k: -kdf: o: -tomb-pwd: r: R: -sphx-host: -sphx-user: -filesystem: " subcommands_opts[lock]="-ignore-swap k: -kdf: -kdftype: -kdfmem: o: -tomb-pwd: r: R: -sphx-host: -sphx-user: -filesystem: "
subcommands_opts[setkey]="k: -ignore-swap -kdf: -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: " subcommands_opts[setkey]="k: -ignore-swap -kdf: -kdftype: -kdfmem: -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: "
subcommands_opts[engrave]="k: " subcommands_opts[engrave]="k: "
subcommands_opts[passwd]="k: -ignore-swap -kdf: -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: " subcommands_opts[passwd]="k: -ignore-swap -kdf: -kdftype: -kdfmem: -tomb-old-pwd: -tomb-pwd: r: R: -sphx-host: -sphx-user: "
subcommands_opts[close]="" subcommands_opts[close]=""
subcommands_opts[help]="" subcommands_opts[help]=""
subcommands_opts[slam]="" subcommands_opts[slam]=""