From a2ba0ca55c0bccf3695f9fdfacfbd991a2a73cf1 Mon Sep 17 00:00:00 2001 From: Andrey Rys Date: Sat, 27 Nov 2021 14:24:04 +0100 Subject: [PATCH] -u: like -m, but decrypt to verify MAC, see if it's valid then decrypt to dst. Also adds "written" counter to status line to track actually written bytes to dst. --- VERSION | 2 +- tfc_error.c | 6 +++++- tfc_misc.c | 2 +- tfc_signal.c | 7 +++++-- tfc_vars.c | 2 +- tfcrypt.c | 39 ++++++++++++++++++++++++++++++++++++--- tfcrypt.h | 4 ++-- 7 files changed, 51 insertions(+), 11 deletions(-) diff --git a/VERSION b/VERSION index e522732..a272009 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -38 +39 diff --git a/tfc_error.c b/tfc_error.c index 17efe74..2108dc5 100644 --- a/tfc_error.c +++ b/tfc_error.c @@ -269,7 +269,11 @@ void usage(void) tfc_say(" -: read a detached MAC signature from stdin,"); tfc_say(" drop: do not verify attached MAC, if any, and drop it from output."); tfc_say(" -m: just verify MAC provided with -M. Do not write output file."); - tfc_say(" This option must be specified after -M."); + tfc_say(" -u: almost same as -m, but turns on MAC pre-test mode, when verified"); + tfc_say(" signature enables writing output file. It is useful when decrypting small texts."); + tfc_say(" The source must be a seekable file, otherwise this mode will be disabled."); + tfc_say(" In this mode, decryption is done twice and verification done once."); + tfc_say(" Both -m and -u options must be specified after -M."); tfc_say(" -E how: how to behave on I/O errors (both src or dst):"); tfc_say(" exit: print error if not quiet, then exit,"); tfc_say(" cont: print error if not quiet, then continue,"); diff --git a/tfc_misc.c b/tfc_misc.c index 06c1a65..57e6b2f 100644 --- a/tfc_misc.c +++ b/tfc_misc.c @@ -135,7 +135,7 @@ tfc_fsize tfc_fdgetpos(int fd) off_t t; t = lseek(fd, 0L, SEEK_CUR); - if (t == -1) return NOFSIZE; + if (t == (off_t)-1) return NOFSIZE; return (tfc_fsize)t; } diff --git a/tfc_signal.c b/tfc_signal.c index 659e938..09c7047 100644 --- a/tfc_signal.c +++ b/tfc_signal.c @@ -36,8 +36,8 @@ void exit_sigterm(int signal) void print_crypt_status(int signal) { tfc_fsize wr_speed; - double seconds, human_totalproc_src, human_totalproc_dst, human_wr_speed; - int src_scale_idx, dst_scale_idx, wr_speed_scale; + double seconds, human_totalproc_src, human_totalproc_dst, human_totalwrit_dst, human_wr_speed; + int src_scale_idx, dst_scale_idx, wri_scale_idx, wr_speed_scale; const char *oper_mode, *inplace; static tfc_yesno last; @@ -64,6 +64,7 @@ void print_crypt_status(int signal) wr_speed = delta_processed / seconds; tfc_describescale(total_processed_src, &human_totalproc_src, &src_scale_idx); tfc_describescale(total_processed_dst, &human_totalproc_dst, &dst_scale_idx); + tfc_describescale(total_written_dst, &human_totalwrit_dst, &wri_scale_idx); tfc_describescale(wr_speed, &human_wr_speed, &wr_speed_scale); if (bench_timer) { @@ -102,11 +103,13 @@ void print_crypt_status(int signal) wr_speed, human_wr_speed, tfc_getscale(wr_speed_scale), tfc_format_time(total_time)); else tfc_nfsay(stderr, "%s%s: read: %llu (%.2f%s)," " %s %s %llu (%.2f%s) bytes," + " written %llu (%.2f%s) bytes," " (%llu (%.2f%s) B/s), time %s", inplace, progname, total_processed_src, human_totalproc_src, tfc_getscale(src_scale_idx), tfc_modename(ctr_mode), oper_mode, total_processed_dst, human_totalproc_dst, tfc_getscale(dst_scale_idx), + total_written_dst, human_totalwrit_dst, tfc_getscale(wri_scale_idx), wr_speed, human_wr_speed, tfc_getscale(wr_speed_scale), tfc_format_time(total_time)); } diff --git a/tfc_vars.c b/tfc_vars.c index 1a65ac3..359c7e1 100644 --- a/tfc_vars.c +++ b/tfc_vars.c @@ -42,7 +42,7 @@ tfc_byte tmpdata[TFC_TMPSIZE]; char *randsource = TFC_DEFAULT_RANDSOURCE; tfc_fsize iseek_blocks, iseek, oseek, maxlen = NOFSIZE, ftrunc_dfd = NOFSIZE; -tfc_fsize total_processed_src, total_processed_dst; +tfc_fsize total_processed_src, total_processed_dst, total_written_dst; tfc_fsize delta_processed; tfc_fsize genrandom_nr_bytes, genzero_nr_bytes; tfc_fsize rdpos = NOFSIZE; diff --git a/tfcrypt.c b/tfcrypt.c index 83f6c69..6ac7bdc 100644 --- a/tfcrypt.c +++ b/tfcrypt.c @@ -28,6 +28,8 @@ #include "tfcrypt.h" +static tfc_byte svctr[TF_BLOCK_SIZE]; + static int getps_filter(struct getpasswd_state *getps, char chr, size_t pos) { if (chr == '\x03') { @@ -113,6 +115,7 @@ int main(int argc, char **argv) double td; char *s, *d, *t, *stoi; size_t x, n; + tfc_fsize rwd; progname = basename(argv[0]); @@ -135,7 +138,7 @@ _baddfname: } opterr = 0; - while ((c = getopt(argc, argv, "L:s:aU:C:r:K:t:Pkzxc:l:qedn:vV:pwE:O:S:AmM:R:Z:WHD:")) != -1) { + while ((c = getopt(argc, argv, "L:s:aU:C:r:K:t:Pkzxc:l:qedn:vV:pwE:O:S:AmuM:R:Z:WHD:")) != -1) { switch (c) { case 'L': read_defaults(optarg, NO); @@ -501,9 +504,11 @@ _baddfname: do_mac_file = optarg; break; case 'm': + case 'u': if (do_mac != TFC_MAC_VRFY) xerror(NO, YES, YES, "signature source was not specified"); do_mac = TFC_MAC_JUST_VRFY; + if (c == 'u') do_mac = TFC_MAC_JUST_VRFY2; break; case 'R': case 'Z': @@ -1024,6 +1029,7 @@ _xts2genkey: if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerro tfc_data_to_words64(&iseek_blocks, sizeof(iseek_blocks)); tf_ctr_set(ctr, &iseek_blocks, sizeof(iseek_blocks)); + if (do_mac == TFC_MAC_JUST_VRFY2) memcpy(svctr, ctr, TF_BLOCK_SIZE); if (counter_opt == TFC_CTR_SHOW) { switch (do_outfmt) { @@ -1106,6 +1112,24 @@ _ctrwagain: lio = xwrite(dfd, pblk, lrem); if (ctr_mode == TFC_MODE_STREAM) tfe_init_iv(&tfe, key, ctr); + if (do_mac == TFC_MAC_JUST_VRFY2) { + rwd = tfc_fdgetpos(sfd); + if (rwd == NOFSIZE) { + tfc_esay("%s: WARNING: input is not seekable, disabling MAC testing mode", progname); + do_mac = TFC_MAC_VRFY; + } + goto _nodecrypt_again_vrfy2; + +_decrypt_again_vrfy2: + if (lseek(sfd, (off_t)rwd, SEEK_SET) == ((off_t)-1)) { + xerror(ignore_seek_errors, NO, YES, "MAC testing seek failed"); + } + total_processed_src = rwd; + memcpy(ctr, svctr, TF_BLOCK_SIZE); + memset(svctr, 0, TF_BLOCK_SIZE); + } + +_nodecrypt_again_vrfy2: errno = 0; do_stop = NO; while (1) { @@ -1175,7 +1199,7 @@ _ragain: lio = xread(sfd, pblk, lrem); if (do_mac >= TFC_MAC_VRFY && ctr_mode < TFC_MODE_OCB) skein_update(&sk, dstblk, ldone); - if (do_mac == TFC_MAC_JUST_VRFY) goto _nowrite; + if (do_mac >= TFC_MAC_JUST_VRFY) goto _nowrite; pblk = dstblk; lrem = ldone; @@ -1189,6 +1213,7 @@ _wagain: lio = xwrite(dfd, pblk, lrem); lrem -= lio; goto _wagain; } + total_written_dst += ldone; _nowrite: total_processed_dst += ldone; delta_processed += ldone; @@ -1270,10 +1295,18 @@ _macragain: lio = xread(sfd, pblk, lrem); else mehexdump(macresult, TF_FROM_BITS(macbits), TF_FROM_BITS(macbits), YES); } } + if (do_mac == TFC_MAC_JUST_VRFY2) { + if (verbose) tfc_esay("%s: -u: MAC signature is valid, proceeding with decrypting it again", progname); + do_mac = TFC_MAC_DROP; + goto _decrypt_again_vrfy2; + } } else { - if (quiet == NO) tfc_esay("%s: signature is BAD: " + if (quiet == NO) { + tfc_esay("%s: signature is BAD: " "wrong password, key, mode, or file is not signed", progname); + if (do_mac == TFC_MAC_JUST_VRFY2) tfc_esay("%s: -u: MAC signature is invalid, not decrypting it again", progname); + } exitcode = 1; } diff --git a/tfcrypt.h b/tfcrypt.h index db11b1d..90f5370 100644 --- a/tfcrypt.h +++ b/tfcrypt.h @@ -139,7 +139,7 @@ extern tfc_byte macvrfy[SKEIN_DIGEST_SIZE], macresult[SKEIN_DIGEST_SIZE]; extern tfc_byte tmpdata[TFC_TMPSIZE]; extern char *randsource; extern tfc_fsize iseek_blocks, iseek, oseek, maxlen, ftrunc_dfd; -extern tfc_fsize total_processed_src, total_processed_dst; +extern tfc_fsize total_processed_src, total_processed_dst, total_written_dst; extern tfc_fsize delta_processed; extern tfc_fsize genrandom_nr_bytes, genzero_nr_bytes; extern tfc_fsize rdpos; @@ -219,7 +219,7 @@ enum { NO, YES }; enum { TFC_ERRACT_EXIT, TFC_ERRACT_CONT, TFC_ERRACT_SYNC, TFC_ERRACT_LSYNC }; enum { TFC_DO_PLAIN, TFC_DO_ENCRYPT, TFC_DO_DECRYPT }; -enum { TFC_MAC_DROP = -1, TFC_MAC_SIGN = 1, TFC_MAC_VRFY, TFC_MAC_JUST_VRFY }; +enum { TFC_MAC_DROP = -1, TFC_MAC_SIGN = 1, TFC_MAC_VRFY, TFC_MAC_JUST_VRFY, TFC_MAC_JUST_VRFY2 }; enum { TFC_MACKEY_RAWKEY = 1, TFC_MACKEY_PASSWORD, TFC_MACKEY_FILE }; enum { TFC_RAWKEY_KEYFILE = 1, TFC_RAWKEY_ASKSTR, TFC_RAWKEY_ASKHEX }; enum { TFC_OUTFMT_HEX = 1, TFC_OUTFMT_B64, TFC_OUTFMT_RAW }; -- 2.31.1