tomb

the crypto undertaker
git clone git://parazyd.org/tomb.git
Log | Files | Refs | README | LICENSE

commit 84d438569603eb8448a3965bbe1fb7b54168a1fc
parent b9b7927e819556aae3881b98903b5fc5ccd8858c
Author: Jaromil <jaromil@dyne.org>
Date:   Fri, 22 Mar 2013 21:13:59 +0100

new creation system in 3 steps and some tips in documentation

Diffstat:
Adoc/Tomb_User_Manual.org | 25+++++++++++++++++++++++++
Msrc/tomb | 242++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 241 insertions(+), 26 deletions(-)

diff --git a/doc/Tomb_User_Manual.org b/doc/Tomb_User_Manual.org @@ -0,0 +1,25 @@ + + +when creating a tomb make sure the device mapper is loaded among kernel modules +or creation will fail and leave you in the dust. + +modprobe dm_mod +modprobe dm_crypt + +to create a tomb on a server (even VPS) is possible, but the problem becomes the little +available entropy. in order to fix this one can use EGD the Entropy Gathering Daemon. + +on Debian, do: + +sudo aptitude install libdigest-sha1-perl +sudo aptitude install ekeyd-egd-linux + +/etc/default/ekeyd-egd-linux + +wget http://egd.sourceforge.net/ + +perl ./egd.pl + +/etc/init.d/ekeyd-egd-linux start + + diff --git a/src/tomb b/src/tomb @@ -640,10 +640,12 @@ exec_safe_post_hooks() { create_tomb() { _message "Commanded to create tomb $1" - # running as root, remembering the uid:gid + # we run as root, but remember the original uid:gid to drop + # privileges when not needed anymore if option_is_set -U; then _uid="`option_value -U`"; fi if option_is_set -G; then _gid="`option_value -G`"; fi + # if swap is on, we remind the user about possible data leaks to disk if ! option_is_set -f && ! option_is_set --ignore-swap; then check_swap; fi if ! [ $1 ]; then @@ -651,10 +653,11 @@ create_tomb() { return 1 fi - if ! [ $2 ]; then - create_cipher=aes-cbc-essiv + # the encryption cipher for a tomb can be set at creation using -o + if ! option_is_set -o; then + create_cipher="`option_value -o`" else - create_cipher=${2} + create_cipher=aes-cbc-essiv:sha256 fi tombfile=`basename $1` @@ -662,7 +665,10 @@ create_tomb() { # make sure the file has a .tomb extension tombname=${tombfile%%\.*} tombfile=${tombname}.tomb - tombsize=$opts[-s] + + + # require the specification of the size of the tomb (-s) in MB + tombsize="`option_value -s`" [ $tombsize ] || die "Size argument missing, use --size" @@ -674,20 +680,26 @@ create_tomb() { return 1 fi + # check if the key is set manually then use the one existing if option_is_set -k; then - tombkey="`option_value -k`.tomb.key" - else - tombkey="${tombdir}/${tombfile}.key" - fi + tombkey="`option_value -k`" + if [ -e "${tombkey}" ]; then + _message "Use an existing key to lock the new tomb:" + ls -lh ${tombkey} + fi - if [ -e "${tombkey}" ]; then - _warning "tomb key already exists. Quitting." - ls -lh ${tombkey} - return 1 + # this does a check on the file header, virtuosism by hellekin + # [[ `file =(awk '/^-+BEGIN/,0' $1) -bi` =~ application/pgp ]] + if ! is_valid_key ${tombkey}; then + _warning "The key seems invalid, the application/pgp header is missing" + die "Operation aborted." + fi + else + tombkey="new" # generate it new later fi - + _success "Creating a new tomb in ${tombdir}/${tombfile}" - + if [ -z $tombsize ]; then _message "No size specified, summoning the Tomb Undertaker to guide us in the creation." "$TOMBOPENEXEC" & @@ -751,14 +763,18 @@ create_tomb() { fi _success "Setup your secret key file ${tombkey}" - touch ${tombkey} - chown ${_uid}:${_gid} ${tombkey} - chmod 0600 ${tombkey} - gen_key ${keytmp}/tomb.tmp > ${tombkey} + if [ "$tombkey" = "new" ]; then + tombkey="${tombdir}/${tombfile}.key" + touch ${tombkey} + chown ${_uid}:${_gid} ${tombkey} + chmod 0600 ${tombkey} + gen_key ${keytmp}/tomb.tmp > ${tombkey} + fi 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} @@ -772,7 +788,7 @@ create_tomb() { # for security, performance and compatibility # XXX: More for compatibility then, because xts-plain is better nowadays. cryptsetup --batch-mode \ - --cipher ${create_cipher}:sha256 --key-size 256 \ + --cipher ${create_cipher} --key-size 256 \ luksFormat ${nstloop} ${keytmp}/tomb.tmp if ! [ $? = 0 ]; then @@ -807,6 +823,162 @@ create_tomb() { _success "Your tomb is ready in ${tombdir}/${tombfile} and secured with key ${tombkey}" } +# This is a new way to create tombs which dissects the whole create_tomb() into 3 clear steps: +# - dig a .tomb (the large file) using /dev/random (takes some minutes at least) +# - forge a .key (the small file) using /dev/urandom (good entropy needed) +# - lock the .tomb file with the key, binding the key to the tomb (requires dm_crypt format) + +forge_key() { + _message "Commanded to forge key $1" + + # we run as root, but remember the original uid:gid + # to set the permissions as readable for the calling user + if option_is_set -U; then _uid="`option_value -U`"; fi + if option_is_set -G; then _gid="`option_value -G`"; fi + + if ! [ $1 ]; then + _warning "no key name specified for creation" + return 1 + fi + + # if swap is on, we remind the user about possible data leaks to disk + if ! option_is_set -f && ! option_is_set --ignore-swap; then check_swap; fi + + # the encryption cipher for a tomb can be set at creation using -o + if ! option_is_set -o; then + create_cipher="`option_value -o`" + else + create_cipher=aes-cbc-essiv:sha256 + fi + + + # create the keyfile in tmpfs so that we leave less traces in RAM + keytmp=`safe_dir tomb` + (( $? )) && die "error creating temp dir" + xxx "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}" + die "operation aborted." + fi + + tombkey="$1" + + _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 + random_source=/dev/random + if option_is_set --use-urandom; then + random_source=/dev/urandom + fi + + if [[ $DD = "dcfldd" ]]; then + $DD bs=1 count=256 if=$random_source of=${keytmp}/tomb.tmp statusinterval=1 + else + $DD bs=1 count=256 if=$random_source of=${keytmp}/tomb.tmp + fi + if ! [ -r ${keytmp}/tomb.tmp ]; then + _warning "cannot generate encryption key" + umount ${keytmp} + rm -r $keytmp + die "operation aborted." + fi + + _success "Choose the password of your key: ${tombkey}" + _message "(you can also change it later using 'tomb passwd')" + touch ${tombkey} + chown ${_uid}:${_gid} ${tombkey} + chmod 0600 ${tombkey} + + tombname="$tombkey" + # the gen_key() function takes care of the new key's encryption + gen_key ${keytmp}/tomb.tmp > ${tombkey} + + # this does a check on the file header, virtuosism by hellekin + # [[ `file =(awk '/^-+BEGIN/,0' $1) -bi` =~ application/pgp ]] + if ! is_valid_key ${tombkey}; then + _warning "The key does not seem to be valid" + _warning "Dumping contents to screen:" + cat ${tombkey} + _warning "--" + umount ${keytmp} + rm -r $keytmp + die "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" + _success "Your key is ready:" + ls -lh ${tombkey} +} + +# dig a tomb +dig_tomb() { + _message "Commanded to dig tomb $1" + + # if swap is on, we remind the user about possible data leaks to disk + if ! option_is_set -f && ! option_is_set --ignore-swap; then check_swap; fi + + if ! [ $1 ]; then + _warning "no tomb name specified for creation" + return 1 + fi + + + tombfile=`basename $1` + tombdir=`dirname $1` + # make sure the file has a .tomb extension + tombname=${tombfile%%\.*} + tombfile=${tombname}.tomb + + + # require the specification of the size of the tomb (-s) in MB + tombsize="`option_value -s`" + + [ $tombsize ] || die "Size argument missing, use --size" + + [[ $tombsize != <-> ]] && die "Size argument is not an integer" + + if [ -e ${tombdir}/${tombfile} ]; then + _warning "A tomb exists already. I'm not digging here:" + _warning " `ls -lh ${tombdir}/${tombfile}`" + return 1 + fi + + _success "Creating a new tomb in ${tombdir}/${tombfile}" + + + tombsize_4k=`expr $tombsize \* 1024 / 4` + _message "Generating ${tombfile} of ${tombsize}Mb (${tombsize_4k} blocks of 4Kb)" + # we will first touch the file and set permissions: this way, even if interrupted, permissions are right + touch ${tombdir}/${tombfile} + chmod 0600 "${tombdir}/${tombfile}" + $DD if=/dev/urandom bs=4k count=${tombsize_4k} of=${tombdir}/${tombfile} + + if [ $? = 0 -a -e ${tombdir}/${tombfile} ]; then + _message " `ls -lh ${tombdir}/${tombfile}`" + else + die "Error creating the tomb ${tombdir}/${tombfile}, operation aborted." + fi + + _success "Done digging $tombname" + _message "your tomb is not yet ready, you need to forge a key and lock it:" + _message "tomb forge ${tombname}.tomb.key" + _message "tomb lock ${tombname}.tomb ${tombname}.tomb.key" +} + + #internal use #$1 is the keyfile we are checking is_valid_key() { @@ -844,9 +1016,9 @@ get_lukskey() { return $ret } -#internal use -#$1 the lukskey to encrypt -#it respects --kdf and --tomb-pwd +# internal use +# $1 the lukskey to encrypt +# honored options: --kdf --tomb-pwd gen_key() { local lukskey=$1 # here user is prompted for key password @@ -879,7 +1051,8 @@ gen_key() { fi - + # 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 @@ -887,7 +1060,7 @@ gen_key() { 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 + # --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 @@ -897,7 +1070,9 @@ gen_key() { _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!) + # 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) @@ -1758,7 +1933,12 @@ main() { subcommands_opts[__default]="" 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[forge]="f -ignore-swap -kdf: -use-urandom U: -uid=U G: -gid=G" + subcommands_opts[dig]="f -ignore-swap s: -size=s" + subcommands_opts[passwd]="f -ignore-swap -kdf: -tomb-old-pwd: -tomb-pwd: " subcommands_opts[close]="-sudo-pwd: U: -uid=U G: -gid=G" subcommands_opts[help]="" @@ -1864,6 +2044,16 @@ main() { check_priv create_tomb ${=PARAM} ;; + + # new creation in three steps + forge) + check_priv + forge_key ${=PARAM} + ;; + dig) + dig_tomb ${=PARAM} + ;; + mount|open) check_priv mount_tomb $PARAM[1] $PARAM[2]