X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=tfcrypt.c;h=590cb33d2fa4ea2ae104a371ce862c4c8fde716a;hb=HEAD;hp=125e5c9c3743e56c0ad01b6ef15a6bf931070730;hpb=4666ae1134223898de8012eca176625cc63a281f;p=tfcrypt.git diff --git a/tfcrypt.c b/tfcrypt.c index 125e5c9..590cb33 100644 --- a/tfcrypt.c +++ b/tfcrypt.c @@ -2,7 +2,7 @@ * tfcrypt -- high security Threefish encryption tool. * * tfcrypt is copyrighted: - * Copyright (C) 2012-2018 Andrey Rys. All rights reserved. + * Copyright (C) 2012-2019 Andrey Rys. All rights reserved. * * tfcrypt is licensed to you under the terms of std. MIT/X11 license: * @@ -28,6 +28,27 @@ #include "tfcrypt.h" +static tfc_byte svctr[TF_BLOCK_SIZE]; +static tfc_fsize rwd, do_read_loops, loopcnt; +static tfc_yesno unbuffered; + +static void open_log(const char *logfile) +{ + int fd; + tfc_yesno ro; + + if (!strcmp(logfile, "-")) return; + + ro = read_only; + read_only = NO; + fd = xopen(logfile, O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC); + read_only = ro; + xclose(2); + if (dup2(fd, 2) == -1) xexit(2); + xclose(fd); + do_statline_dynamic = NO; +} + static int getps_filter(struct getpasswd_state *getps, char chr, size_t pos) { if (chr == '\x03') { @@ -83,13 +104,39 @@ static int getps_plain_hex_filter(struct getpasswd_state *getps, char chr, size_ return 1; } +static void make_hint(void *hint, size_t szhint, const void *data, size_t szdata) +{ + char t[TF_FROM_BITS(TF_MAX_BITS)]; + + skein(t, TF_MAX_BITS, NULL, data, szdata); + xor_shrink(hint, szhint, t, sizeof(t)); + memset(t, 0, sizeof(t)); +} + +static void raw_say_hint(void *hint, size_t szhint, const void *data, size_t szdata, const char *prompt) +{ + make_hint(hint, szhint, data, szdata); + if (prompt) tfc_nfsay(stderr, "%s: ", prompt); + mehexdump(hint, szhint, szhint, 1); + memset(hint, 0, szhint); +} + +static void say_hint(const void *data, size_t szdata, const char *prompt) +{ + char t[TF_SIZE_UNIT]; + raw_say_hint(t, TF_SIZE_UNIT, data, szdata, prompt); + /* t[] is erased (automatically) */ +} + int main(int argc, char **argv) { + tfc_yesno flipfd; int c; double td; char *s, *d, *t, *stoi; size_t x, n; + progpid = getpid(); progname = basename(argv[0]); if (!isatty(2)) do_statline_dynamic = NO; @@ -104,8 +151,20 @@ int main(int argc, char **argv) _baddfname: memset(s, 0, n); + if (!strcmp(progname, "iotool")) { + do_edcrypt = TFC_DO_PLAIN; + ctr_mode = TFC_MODE_PLAIN; + } + + if (!strcmp(progname, "xor")) { + do_edcrypt = TFC_DO_PLAIN; + ctr_mode = TFC_MODE_XOR; + /* xor: default to stdin if invoked without args */ + kfd = 0; + } + 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:PXkzxc:l:qedn:vV:pwE:o:O:S:AmuM:R:Z:WHD:gj")) != -1) { switch (c) { case 'L': read_defaults(optarg, NO); @@ -116,6 +175,14 @@ _baddfname: case 'r': randsource = optarg; break; + case 'j': + case 'g': + if (c == 'j') ctr_mode = TFC_MODE_CTR; + else if (c == 'g') ctr_mode = TFC_MODE_STREAM; + if (do_edcrypt == TFC_DO_DECRYPT) counter_opt = TFC_CTR_HEAD; + else if (do_edcrypt == TFC_DO_ENCRYPT) counter_opt = TFC_CTR_RAND; + else xerror(NO, YES, YES, "plain mode was selected with -%c, cannot continue", c); + break; case 'c': if (!strcasecmp(optarg, "show")) counter_opt = TFC_CTR_SHOW; @@ -125,6 +192,29 @@ _baddfname: counter_opt = TFC_CTR_RAND; else if (!strcasecmp(optarg, "zero")) counter_opt = TFC_CTR_ZERO; + else if (strchr(optarg, ':')) { + char *ss, chr; + + counter_opt = TFC_CTR_SSET; + n = sizeof(ctr); + + s = d = optarg; t = NULL; + while ((s = strtok_r(d, ",", &t))) { + if (d) d = NULL; + + if (n == 0) break; + ss = strchr(s, ':'); + if (!ss) continue; + *ss = 0; ss++; + chr = (char)strtoul(s, &stoi, 16); + if (!str_empty(stoi)) continue; + x = (size_t)strtoul(ss, &stoi, 10); + if (!str_empty(stoi)) continue; + if (x > n) x = n; + memset(ctr+(sizeof(ctr)-n), (int)chr, x); + n -= x; + } + } else counter_file = sksum_hashlist_file = optarg; break; case 'C': @@ -134,24 +224,29 @@ _baddfname: ctr_mode = TFC_MODE_STREAM; else if (!strcasecmp(optarg, "cbc")) ctr_mode = TFC_MODE_CBC; + else if (!strcasecmp(optarg, "pcbc")) + ctr_mode = TFC_MODE_PCBC; else if (!strcasecmp(optarg, "ecb")) ctr_mode = TFC_MODE_ECB; else if (!strcasecmp(optarg, "xts")) ctr_mode = TFC_MODE_XTS; - else if (!strcasecmp(optarg, "ocb")) - ctr_mode = TFC_MODE_OCB; else xerror(NO, YES, YES, "%s: invalid mode of operation", optarg); break; case 'P': + case 'X': do_edcrypt = TFC_DO_PLAIN; - password = YES; - ctr_mode = TFC_MODE_PLAIN; + if (c == 'X') { + ctr_mode = TFC_MODE_XOR; + /* xor: default to stdin if invoked without args */ + kfd = 0; + } + else ctr_mode = TFC_MODE_PLAIN; break; case 'e': - do_edcrypt = TFC_DO_ENCRYPT; + if (do_edcrypt != TFC_DO_PLAIN) do_edcrypt = TFC_DO_ENCRYPT; break; case 'd': - do_edcrypt = TFC_DO_DECRYPT; + if (do_edcrypt != TFC_DO_PLAIN) do_edcrypt = TFC_DO_DECRYPT; break; case 'D': macbits = strtoul(optarg, &stoi, 10); @@ -229,6 +324,9 @@ _baddfname: error_action = TFC_ERRACT_LSYNC; else xerror(NO, YES, YES, "invalid error action %s specified", optarg); break; + case 'o': + open_log(optarg); + break; case 'O': s = d = optarg; t = NULL; while ((s = strtok_r(d, ",", &t))) { @@ -237,10 +335,16 @@ _baddfname: write_flags |= O_SYNC; else if (!strcmp(s, "trunc")) write_flags |= O_TRUNC; + else if (!strcmp(s, "append")) + write_flags |= O_APPEND; else if (!strcmp(s, "fsync")) do_fsync = YES; else if (!strcmp(s, "pad")) do_pad = YES; + else if (!strcmp(s, "ro")) + read_only = YES; + else if (!strcmp(s, "rw")) + read_only = NO; else if (!strcmp(s, "xtime")) do_preserve_time = YES; else if (!strcmp(s, "gibsize")) @@ -261,6 +365,22 @@ _baddfname: do_full_key = YES; else if (!strcmp(s, "showsecrets")) show_secrets = YES; + else if (!strcmp(s, "finished")) + show_when_done = YES; + else if (!strcmp(s, "pid")) + show_pid = YES; + else if (!strcmp(s, "nobuf")) { + if (!tfc_is_freestream(ctr_mode)) xerror(NO, YES, YES, + "cannot activate unbuffered mode for non-stream cipher mode %s!", + tfc_modename(ctr_mode)); + else unbuffered = YES; + } + else if (!strncmp(s, "readloops", 9) && *(s+9) == '=') { + do_read_loops = tfc_humanfsize(s+10, &stoi); + if (!str_empty(stoi)) do_read_loops = NOSIZE; + } + else if (!strncmp(s, "logfile", 7) && *(s+7) == '=') + open_log(s+8); else if (!strncmp(s, "iobs", 4) && *(s+4) == '=') { s += 5; blksize = (size_t)tfc_humanfsize(s, &stoi); @@ -271,7 +391,7 @@ _baddfname: "%s: invalid block size value", s); } else blksize = (size_t)tfc_modifysize((tfc_fsize)blksize, strchr(s, ':')); - if (blksize < TF_BLOCK_SIZE) xerror(NO, YES, YES, + if (!tfc_is_freestream(ctr_mode) && blksize < TF_BLOCK_SIZE) xerror(NO, YES, YES, "%s: block size is lesser than TF_BLOCK_SIZE (%u bytes)", s, TFC_U(TF_BLOCK_SIZE)); if (blksize > TFC_BLKSIZE) xerror(NO, YES, YES, "%s: block size exceeds %u bytes", @@ -304,7 +424,7 @@ _baddfname: "%s: invalid iseek value", s); } else iseek = tfc_modifysize(iseek, strchr(s, ':')); - if (ctr_mode != TFC_MODE_PLAIN && iseek % TF_BLOCK_SIZE) + if (do_edcrypt != TFC_DO_PLAIN && iseek % TF_BLOCK_SIZE) xerror(NO, YES, YES, "%s: not round to TF block size " "of %u bytes", @@ -363,6 +483,33 @@ _baddfname: } else oseek = tfc_modifysize(oseek, strchr(s, ':')); } + else if (!strncmp(s, "ioseek", 6) && *(s+6) == '=') { + s += 7; + + iseek = tfc_humanfsize(s, &stoi); + if (!str_empty(stoi)) { + iseek = tfc_fnamesize(s, YES); + iseek = tfc_modifysize(iseek, strchr(s, ':')); + if (iseek == NOFSIZE) xerror(NO, YES, YES, + "%s: invalid iseek value", s); + } + else iseek = tfc_modifysize(iseek, strchr(s, ':')); + if (do_edcrypt != TFC_DO_PLAIN && iseek % TF_BLOCK_SIZE) + xerror(NO, YES, YES, + "%s: not round to TF block size " + "of %u bytes", + s, TFC_U(TF_BLOCK_SIZE)); + iseek_blocks = iseek / TF_BLOCK_SIZE; + + oseek = tfc_humanfsize(s, &stoi); + if (!str_empty(stoi)) { + oseek = tfc_fnamesize(s, YES); + oseek = tfc_modifysize(oseek, strchr(s, ':')); + if (oseek == NOFSIZE) xerror(NO, YES, YES, + "%s: invalid oseek value", s); + } + else oseek = tfc_modifysize(oseek, strchr(s, ':')); + } else if (!strncmp(s, "count", 5) && *(s+5) == '=') { s += 6; maxlen = tfc_humanfsize(s, &stoi); @@ -376,6 +523,24 @@ _baddfname: if (counter_opt == TFC_CTR_HEAD) maxlen += TF_BLOCK_SIZE; } + else if (!strncmp(s, "ftrunc", 6) && *(s+6) == '=') { + s += 7; + if (!strcmp(s, "tail")) { + do_ftrunc = TFC_FTRUNC_TAIL; + ftrunc_dfd = NOFSIZE; + } + else { + do_ftrunc = TFC_DO_FTRUNC; + ftrunc_dfd = tfc_humanfsize(s, &stoi); + if (!str_empty(stoi)) { + ftrunc_dfd = tfc_fnamesize(s, YES); + ftrunc_dfd = tfc_modifysize(ftrunc_dfd, strchr(s, ':')); + if (ftrunc_dfd == NOFSIZE) xerror(NO, YES, YES, + "%s: invalid ftrunc value", s); + } + else ftrunc_dfd = tfc_modifysize(ftrunc_dfd, strchr(s, ':')); + } + } else if (!strncmp(s, "xkey", 4) && *(s+4) == '=') { s += 5; maxkeylen = tfc_humanfsize(s, &stoi); @@ -430,9 +595,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': @@ -477,6 +644,7 @@ _baddfname: case 'q': quiet = YES; verbose = NO; + do_full_hexdump = NO; status_timer = 0; break; case 'v': @@ -526,9 +694,8 @@ _baddfname: xerror(NO, YES, YES, "Cannot encrypt and read CTR from source!"); if (overwrite_source && counter_opt == TFC_CTR_RAND) xerror(NO, YES, YES, "Cannot embed a CTR into file when overwriting it!"); - if (ctr_mode == TFC_MODE_PLAIN - && (do_edcrypt || do_mac || rawkey - || mackey_opt || counter_opt || counter_file)) + if (do_edcrypt == TFC_DO_PLAIN + && (do_mac || saltf || rawkey || mackey_opt || counter_opt || counter_file)) xerror(NO, YES, YES, "Encryption facility is disabled when in plain IO mode."); errno = 0; @@ -542,8 +709,7 @@ _baddfname: if (!strcasecmp(saltf, "disable")) goto _nosalt; if (!strcmp(saltf, "-")) saltfd = 0; - else saltfd = open(saltf, O_RDONLY | O_LARGEFILE); - if (saltfd == -1) xerror(NO, NO, YES, "%s", saltf); + else saltfd = xopen(saltf, O_RDONLY | O_LARGEFILE); lio = xread(saltfd, tfc_salt, TFC_MAX_SALT - TF_FROM_BITS(TFC_KEY_BITS)); if (lio == NOSIZE) xerror(NO, NO, YES, "%s", saltf); tfc_saltsz = lio; @@ -556,8 +722,7 @@ _nosalt: tfc_yesno do_stop; if (!strcmp(mackeyf, "-")) mkfd = 0; - else mkfd = open(mackeyf, O_RDONLY | O_LARGEFILE); - if (mkfd == -1) xerror(NO, NO, YES, "%s", mackeyf); + else mkfd = xopen(mackeyf, O_RDONLY | O_LARGEFILE); skein_init(&sk, TFC_KEY_BITS); @@ -569,7 +734,7 @@ _nosalt: lrem = lblock = sizeof(tmpdata); if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(mkfd); _mkragain: lio = xread(mkfd, pblk, lrem); - if (lio == 0) do_stop = YES; + if (lio == 0 && do_stop == NO) do_stop = YES; if (lio != NOSIZE) ldone += lio; else { if (errno != EIO && catch_all_errors != YES) @@ -612,14 +777,8 @@ _mkragain: lio = xread(mkfd, pblk, lrem); n = xgetpasswd(&getps); if (n == NOSIZE) xerror(NO, NO, YES, "getting MAC password"); if (n == ((size_t)-2)) xexit(1); + if (verbose) say_hint(pwdask, n, "MAC password hint"); skein(mackey, TF_MAX_BITS, NULL, pwdask, n); - if (verbose) { - skein(tmpdata, TF_MAX_BITS, NULL, mackey, TF_FROM_BITS(TF_MAX_BITS)); - xor_shrink(tmpdata+TF_FROM_BITS(TF_MAX_BITS), TF_SIZE_UNIT, tmpdata, TF_FROM_BITS(TF_MAX_BITS)); - tfc_nfsay(stderr, "MAC password hint: "); - mehexdump(tmpdata+TF_FROM_BITS(TF_MAX_BITS), TF_SIZE_UNIT, TF_SIZE_UNIT, 1); - memset(tmpdata, 0, sizeof(tmpdata)); - } } @@ -631,15 +790,22 @@ _mkragain: lio = xread(mkfd, pblk, lrem); || !memcmp(progname+5, "sum", 3) || !memcmp(progname+6, "sum", 3))))) do_sksum(progname, argv+optind); - if (!strcmp(progname, "tfbase64")) do_edbase64(argv+optind); + if (!strcmp(progname, "base64")) do_edbase64(argv+optind); idx = optind; if (argv[idx]) { - if (password || rawkey > TFC_RAWKEY_KEYFILE) goto _nokeyfd; + if ((do_edcrypt == TFC_DO_PLAIN && ctr_mode == TFC_MODE_PLAIN) + || password + || rawkey > TFC_RAWKEY_KEYFILE) goto _nokeyfd; if (!strcmp(argv[idx], "-")) kfd = 0; - else kfd = open(argv[idx], O_RDONLY | O_LARGEFILE); - if (kfd == -1) xerror(NO, NO, YES, "%s", argv[idx]); + else kfd = xopen(argv[idx], O_RDONLY | O_LARGEFILE); + + if (do_edcrypt == TFC_DO_PLAIN && ctr_mode == TFC_MODE_XOR) { + /* out: don't erase kfname if xor */ + idx++; + goto _nokeyfd; + } lio = strnlen(argv[idx], PATH_MAX); memset(argv[idx], '*', lio); @@ -667,19 +833,12 @@ _nokeyfd: if (argv[idx]) { if (!strcmp(argv[idx], "-") && kfd) sfd = 0; else { - sfd = open(argv[idx], O_RDONLY | O_LARGEFILE); + sfd = xopen(argv[idx], O_RDONLY | O_LARGEFILE); if (do_preserve_time) if (fstat(sfd, &s_stat) == -1) xerror(YES, NO, YES, "stat(%s)", argv[idx]); } - if (sfd == -1) xerror(NO, NO, YES, "%s", argv[idx]); - - if (do_edcrypt == TFC_DO_DECRYPT && do_mac != NO && maxlen != NOFSIZE) { - if (verbose) tfc_esay("%s: disabling signature verification on " - "requested partial decryption.", progname); - do_mac = NO; - } - if ((do_mac >= TFC_MAC_VRFY || do_mac == TFC_MAC_DROP) && !do_mac_file) { + if ((do_mac >= TFC_MAC_VRFY || do_mac <= TFC_MAC_DROP) && !do_mac_file) { maxlen = tfc_fdsize(sfd); if (maxlen == NOFSIZE) xerror(NO, YES, YES, @@ -702,8 +861,7 @@ _nokeyfd: int ctrfd; if (!strcmp(counter_file, "-")) ctrfd = 0; - else ctrfd = open(counter_file, O_RDONLY | O_LARGEFILE); - if (ctrfd == -1) xerror(NO, NO, YES, "%s", counter_file); + else ctrfd = xopen(counter_file, O_RDONLY | O_LARGEFILE); lio = xread(ctrfd, ctr, ctrsz); if (lio == NOSIZE) xerror(NO, NO, YES, "%s", counter_file); if (lio < ctrsz) xerror(NO, YES, YES, "counter file is too small (%zu)!", lio); @@ -748,9 +906,9 @@ _ctrskip1: xerror(ignore_seek_errors, NO, NO, "%s: seek failed", srcfname); } - if (ctr_mode == TFC_MODE_PLAIN) goto _plain; + if (do_edcrypt == TFC_DO_PLAIN) goto _plain; - if (verbose) tfc_esay("%s: hashing password", progname); + if (verbose) tfc_esay("%s: hashing password", tfc_format_pid(progname)); if (rawkey == TFC_RAWKEY_KEYFILE) { tfc_yesno xtskeyset = NO; @@ -807,6 +965,7 @@ _xts2keyaskstr: memset(&getps, 0, sizeof(struct getpasswd_state)); n = xgetpasswd(&getps); if (n == NOSIZE) xerror(NO, NO, YES, "getting string rawkey"); if (n == ((size_t)-2)) xexit(1); + if (verbose) say_hint(pblk, n, "Raw string key hint"); if (ctr_mode == TFC_MODE_XTS) { if (xtskeyset == NO) { pblk = xtskey; n = sizeof(xtskey); @@ -837,6 +996,7 @@ _rawkey_hex_again: } hex2bin(pblk, pwdask); memset(pwdask, 0, sizeof(pwdask)); + if (verbose) say_hint(pblk, n/2, "Raw hex key hint"); if (ctr_mode == TFC_MODE_XTS) { if (xtskeyset == NO) { pblk = xtskey; @@ -871,6 +1031,7 @@ _pwdagain: memset(&getps, 0, sizeof(struct getpasswd_state)); goto _pwdagain; } } + if (verbose) say_hint(pwdask, n, "Password hint"); skein(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, pwdask, n); memset(pwdask, 0, sizeof(pwdask)); memset(pwdagain, 0, sizeof(pwdagain)); @@ -900,14 +1061,13 @@ _pwdagain: memset(&getps, 0, sizeof(struct getpasswd_state)); pblk = key; if (!strcmp(genkeyf, "-")) krfd = 1; - else krfd = open(genkeyf, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666); - if (krfd == -1) xerror(NO, NO, YES, "%s", genkeyf); + else krfd = xopen(genkeyf, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags); _xts2genkey: if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerror(NO, NO, YES, "%s", genkeyf); if (do_fsync && fsync(krfd) == -1) xerror(NO, NO, YES, "%s", genkeyf); if (verbose && xtskeyset == NO) { - tfc_esay("%s: password hashing done", progname); - tfc_esay("%s: rawkey written to %s.", progname, genkeyf); - tfc_esay("%s: Have a nice day!", progname); + tfc_esay("%s: password hashing done", tfc_format_pid(progname)); + tfc_esay("%s: rawkey written to %s.", tfc_format_pid(progname), genkeyf); + tfc_esay("%s: Have a nice day!", tfc_format_pid(progname)); } if (ctr_mode == TFC_MODE_XTS) { @@ -923,20 +1083,12 @@ _xts2genkey: if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerro xexit(0); } - if (iseek_blocks && (do_edcrypt == TFC_DO_DECRYPT && do_mac != NO)) { - if (verbose) tfc_esay("%s: disabling signature verification on " - "requested partial decryption.", progname); - do_mac = NO; - } - if (do_mac != NO) { if (mackey_opt == TFC_MACKEY_RAWKEY) skein(mackey, TF_MAX_BITS, key, key, TF_FROM_BITS(TFC_KEY_BITS)); - if (ctr_mode < TFC_MODE_OCB) { - if (verbose) tfc_esay("%s: doing MAC calculation, processing speed " - "will be slower.", progname); - if (mackey_opt) skein_init_key(&sk, mackey, macbits); - else skein_init(&sk, macbits); - } + if (verbose) tfc_esay("%s: doing MAC calculation, processing speed " + "will be slower.", tfc_format_pid(progname)); + if (mackey_opt) skein_init_key(&sk, mackey, macbits); + else skein_init(&sk, macbits); } if (!counter_file && counter_opt <= TFC_CTR_SHOW && ctr_mode != TFC_MODE_ECB) { @@ -950,38 +1102,36 @@ _xts2genkey: if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerro tf_tweak_set(key, tweak); } if (ctr_mode == TFC_MODE_ECB) goto _ctrskip2; + + if (counter_opt == TFC_CTR_ZERO) memset(ctr, 0, ctrsz); + 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); - switch (counter_opt) { - case TFC_CTR_SHOW: - switch (do_outfmt) { - case TFC_OUTFMT_B64: tfc_printbase64(stderr, ctr, ctrsz, YES); break; - case TFC_OUTFMT_RAW: xwrite(2, ctr, ctrsz); break; - case TFC_OUTFMT_HEX: mehexdump(ctr, ctrsz, ctrsz, YES); break; - } - break; - case TFC_CTR_RAND: tfc_getrandom(ctr, ctrsz); break; - case TFC_CTR_ZERO: memset(ctr, 0, ctrsz); break; + if (counter_opt == TFC_CTR_SHOW) { + switch (do_outfmt) { + case TFC_OUTFMT_B64: tfc_printbase64(stderr, ctr, ctrsz, YES); break; + case TFC_OUTFMT_RAW: xwrite(2, ctr, ctrsz); break; + case TFC_OUTFMT_HEX: mehexdump(ctr, ctrsz, ctrsz, YES); break; + } } + else if (counter_opt == TFC_CTR_RAND) tfc_getrandom(ctr, ctrsz); _ctrskip2: if (kfd != -1) { xclose(kfd); kfd = -1; } - if (verbose) tfc_esay("%s: password hashing done", progname); + if (verbose) tfc_esay("%s: password hashing done", tfc_format_pid(progname)); if (overwrite_source && srcfname) argv[idx] = srcfname; _plain: if (argv[idx]) { if (!strcmp(argv[idx], "-")) dfd = 1; - else dfd = open(argv[idx], O_RDWR | O_LARGEFILE | write_flags, 0666); - if (dfd == -1) { - dfd = open(argv[idx], O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666); - if (dfd == -1) xerror(NO, NO, YES, "%s", argv[idx]); - } + else dfd = xxopen(YES, argv[idx], O_RDWR | O_LARGEFILE | write_flags); + if (dfd == -1) dfd = xopen(argv[idx], O_WRONLY | O_CREAT | O_LARGEFILE | write_flags); dstfname = argv[idx]; idx++; } @@ -996,9 +1146,8 @@ _plain: sigact.sa_flags = SA_RESTART; sigact.sa_handler = print_crypt_status; sigaction(SIGUSR1, &sigact, NULL); - sigaction(SIGTSTP, &sigact, NULL); sigaction(SIGALRM, &sigact, NULL); - if (status_timer) setup_next_alarm(status_timer); + if (status_timer) setup_next_alarm(status_timer > 1000000 ? 1000000 : status_timer); sigact.sa_handler = change_status_width; sigaction(SIGQUIT, &sigact, NULL); sigact.sa_handler = change_status_timer; @@ -1007,11 +1156,14 @@ _plain: sigact.sa_handler = print_crypt_status; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); + sigaction(SIGTSTP, &sigact, NULL); } else { sigact.sa_handler = exit_sigterm; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); + sigact.sa_handler = handle_sigtstp; + sigaction(SIGTSTP, &sigact, NULL); } memset(&sigact, 0, sizeof(struct sigaction)); @@ -1031,22 +1183,54 @@ _ctrwagain: lio = xwrite(dfd, pblk, lrem); lrem -= lio; goto _ctrwagain; } + total_written_dst += ldone; total_processed_dst += ldone; delta_processed += ldone; } 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", tfc_format_pid(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); + if (ctr_mode == TFC_MODE_STREAM) tfe_init_iv(&tfe, key, ctr); + memset(svctr, 0, TF_BLOCK_SIZE); + } + +#define FLFD(x, y) (flipfd ? y : x) +_nodecrypt_again_vrfy2: + loopcnt = 1; errno = 0; do_stop = NO; + flipfd = NO; while (1) { if (do_stop) break; + if (ctr_mode == TFC_MODE_XOR) flipfd = NO; pblk = srcblk; - ldone = 0; +_nextblk: ldone = 0; lrem = lblock = blk_len_adj(maxlen, total_processed_src, blksize); - if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(sfd); -_ragain: lio = xread(sfd, pblk, lrem); - if (lio == 0) do_stop = TFC_STOP_BEGAN; + if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(FLFD(sfd, kfd)); +_ragain: lio = xread(FLFD(sfd, kfd), pblk, lrem); + if (lio == 0) { + if ((do_read_loops != 0 && FLFD(sfd, kfd) != 0) && (loopcnt < do_read_loops)) { + lseek(FLFD(sfd, kfd), 0L, SEEK_SET); + loopcnt++; + goto _ragain; + } + + do_stop = YES; + } if (lio != NOSIZE) ldone += lio; else { if (errno != EIO && catch_all_errors != YES) @@ -1058,13 +1242,13 @@ _ragain: lio = xread(sfd, pblk, lrem); xerror(YES, NO, NO, "%s", srcfname); lio = ldone = lrem = lblock; memset(srcblk, 0, lio); - if (rdpos == NOFSIZE) lseek(sfd, lio, SEEK_CUR); - else lseek(sfd, rdpos + lio, SEEK_SET); + if (rdpos == NOFSIZE) lseek(FLFD(sfd, kfd), lio, SEEK_CUR); + else lseek(FLFD(sfd, kfd), rdpos + lio, SEEK_SET); break; default: xerror(NO, NO, NO, "%s", srcfname); break; } } - if (lio && lio < lrem) { + if (unbuffered == NO && lio && lio < lrem) { pblk += lio; lrem -= lio; goto _ragain; @@ -1078,8 +1262,14 @@ _ragain: lio = xread(sfd, pblk, lrem); memset(srcblk+orig, 0, sizeof(srcblk)-orig); } - if (do_mac == TFC_MAC_SIGN && ctr_mode < TFC_MODE_OCB) - skein_update(&sk, srcblk, ldone); + if (ctr_mode == TFC_MODE_XOR && flipfd == NO) { + if (do_stop) blksize = ldone; + flipfd = YES; + pblk = dstblk; + goto _nextblk; + } + + if (do_mac == TFC_MAC_SIGN) skein_update(&sk, srcblk, ldone); if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, dstblk, srcblk, ldone); else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, dstblk, srcblk, ldone); @@ -1095,18 +1285,19 @@ _ragain: lio = xread(sfd, pblk, lrem); tf_cbc_encrypt(key, ctr, dstblk, srcblk, ldone); else if (ctr_mode == TFC_MODE_CBC && do_edcrypt == TFC_DO_DECRYPT) tf_cbc_decrypt(key, ctr, dstblk, srcblk, ldone); - - else if (ctr_mode == TFC_MODE_OCB && do_edcrypt == TFC_DO_ENCRYPT) - tf_ocb_encrypt(key, ctr, dstblk, do_mac == TFC_MAC_SIGN ? macresult : NULL, srcblk, ldone, xtsblocks); - else if (ctr_mode == TFC_MODE_OCB && do_edcrypt == TFC_DO_DECRYPT) - tf_ocb_decrypt(key, ctr, dstblk, do_mac >= TFC_MAC_VRFY ? macresult : NULL, srcblk, ldone, xtsblocks); + else if (ctr_mode == TFC_MODE_PCBC && do_edcrypt == TFC_DO_ENCRYPT) + tf_pcbc_encrypt(key, ctr, dstblk, srcblk, ldone); + else if (ctr_mode == TFC_MODE_PCBC && do_edcrypt == TFC_DO_DECRYPT) + tf_pcbc_decrypt(key, ctr, dstblk, srcblk, ldone); else if (ctr_mode == TFC_MODE_PLAIN) memcpy(dstblk, srcblk, ldone); - 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; + else if (ctr_mode == TFC_MODE_XOR) + xor_block(dstblk, srcblk, ldone); + + if (do_mac >= TFC_MAC_VRFY) skein_update(&sk, dstblk, ldone); + if (do_mac >= TFC_MAC_JUST_VRFY) goto _nowrite; pblk = dstblk; lrem = ldone; @@ -1120,13 +1311,17 @@ _wagain: lio = xwrite(dfd, pblk, lrem); lrem -= lio; goto _wagain; } + total_written_dst += ldone; _nowrite: total_processed_dst += ldone; delta_processed += ldone; - if (maxlen != NOFSIZE && total_processed_src >= maxlen) break; + if (maxlen != NOFSIZE && total_processed_src >= maxlen) { + do_stop = YES; + break; + } } - if (do_stop == TFC_STOP_FULL) goto _nomac; + if (verbose && status_timer && do_statline_dynamic == YES && statline_was_shown == YES) tfc_esay("\n"); errno = 0; if (do_mac >= TFC_MAC_VRFY) { @@ -1164,8 +1359,7 @@ _macragain: lio = xread(sfd, pblk, lrem); int mfd; if (!strcmp(do_mac_file, "-")) mfd = 0; - else mfd = open(do_mac_file, O_RDONLY | O_LARGEFILE); - if (mfd == -1) xerror(YES, NO, NO, "%s", do_mac_file); + else mfd = xopen(do_mac_file, O_RDONLY | O_LARGEFILE); lio = ldone = xread(mfd, tmpdata, sizeof(tmpdata)); if (lio == NOSIZE) xerror(NO, NO, YES, "%s", do_mac_file); if (!memcmp(tmpdata, TFC_ASCII_TFC_MAC_FOURCC, TFC_ASCII_TFC_MAC_FOURCC_LEN)) { @@ -1180,33 +1374,41 @@ _macragain: lio = xread(sfd, pblk, lrem); if (ldone < TF_FROM_BITS(macbits)) { if (quiet == NO) tfc_esay("%s: short signature (%zu), " - "not verifying", progname, ldone); + "not verifying", tfc_format_pid(progname), ldone); exitcode = 1; goto _shortmac; } - if (ctr_mode < TFC_MODE_OCB) skein_final(macresult, &sk); - else skein(macresult, macbits, mackey, macresult, TF_FROM_BITS(macbits)); + skein_final(macresult, &sk); if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits)); else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, tmpdata, macvrfy, TF_FROM_BITS(macbits)); else if (ctr_mode == TFC_MODE_XTS) tf_xts_decrypt(key, xtskey, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits), xtsblocks); else if (ctr_mode == TFC_MODE_ECB) tf_ecb_decrypt(key, tmpdata, macvrfy, TF_FROM_BITS(macbits)); else if (ctr_mode == TFC_MODE_CBC) tf_cbc_decrypt(key, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits)); - else if (ctr_mode == TFC_MODE_OCB) tf_ocb_decrypt(key, ctr, tmpdata, NULL, macvrfy, TF_FROM_BITS(macbits), xtsblocks); + else if (ctr_mode == TFC_MODE_PCBC) tf_pcbc_decrypt(key, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits)); if (!memcmp(tmpdata, macresult, TF_FROM_BITS(macbits))) { if (quiet == NO) { - tfc_esay("%s: signature is good", progname); + tfc_esay("%s: signature is good", tfc_format_pid(progname)); if (verbose) { if (do_outfmt == TFC_OUTFMT_B64) tfc_printbase64(stderr, macresult, TF_FROM_BITS(macbits), YES); 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", tfc_format_pid(progname)); + maxlen = total_processed_src - SKEIN_DIGEST_SIZE; + do_mac = TFC_MAC_DROP2; + goto _decrypt_again_vrfy2; + } } else { - if (quiet == NO) tfc_esay("%s: signature is BAD: " - "wrong password, key, mode, or file is not signed", progname); + if (quiet == NO) { + tfc_esay("%s: signature is BAD: " + "wrong password, key, mode, or file is not signed", tfc_format_pid(progname)); + if (do_mac == TFC_MAC_JUST_VRFY2) tfc_esay("%s: -u: MAC signature is invalid, not decrypting it again", tfc_format_pid(progname)); + } exitcode = 1; } @@ -1214,17 +1416,15 @@ _shortmac: memset(macvrfy, 0, sizeof(macvrfy)); memset(macresult, 0, sizeof(macresult)); memset(tmpdata, 0, sizeof(tmpdata)); } - else if (do_mac == TFC_MAC_SIGN) { - if (ctr_mode < TFC_MODE_OCB) skein_final(macresult, &sk); - else skein(macresult, macbits, mackey, macresult, TF_FROM_BITS(macbits)); + skein_final(macresult, &sk); if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, tmpdata, macresult, TF_FROM_BITS(macbits)); else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, tmpdata, macresult, TF_FROM_BITS(macbits)); else if (ctr_mode == TFC_MODE_XTS) tf_xts_encrypt(key, xtskey, ctr, tmpdata, macresult, TF_FROM_BITS(macbits), xtsblocks); else if (ctr_mode == TFC_MODE_ECB) tf_ecb_encrypt(key, tmpdata, macresult, TF_FROM_BITS(macbits)); else if (ctr_mode == TFC_MODE_CBC) tf_cbc_encrypt(key, ctr, tmpdata, macresult, TF_FROM_BITS(macbits)); - else if (ctr_mode == TFC_MODE_OCB) tf_ocb_encrypt(key, ctr, tmpdata, NULL, macresult, TF_FROM_BITS(macbits), xtsblocks); + else if (ctr_mode == TFC_MODE_PCBC) tf_pcbc_encrypt(key, ctr, tmpdata, macresult, TF_FROM_BITS(macbits)); memset(macresult, 0, sizeof(macresult)); if (!do_mac_file) { @@ -1240,6 +1440,7 @@ _macwagain: lio = xwrite(dfd, pblk, lrem); lrem -= lio; goto _macwagain; } + total_written_dst += ldone; total_processed_dst += ldone; delta_processed += ldone; } @@ -1247,8 +1448,7 @@ _macwagain: lio = xwrite(dfd, pblk, lrem); int mfd; if (!strcmp(do_mac_file, "-")) mfd = 1; - else mfd = open(do_mac_file, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666); - if (mfd == -1) xerror(YES, NO, NO, "%s", do_mac_file); + else mfd = xopen(do_mac_file, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags); if (do_outfmt == TFC_OUTFMT_B64) { memcpy(macvrfy, tmpdata, TF_FROM_BITS(macbits)); memset(tmpdata, 0, TFC_TMPSIZE); @@ -1271,13 +1471,9 @@ _macwagain: lio = xwrite(dfd, pblk, lrem); memset(macresult, 0, sizeof(macresult)); memset(tmpdata, 0, sizeof(tmpdata)); } + else if (do_mac == TFC_MAC_DROP2) total_processed_src += SKEIN_DIGEST_SIZE; -_nomac: - if (verbose || status_timer || do_stop == TFC_STOP_FULL) print_crypt_status(0); - - if (do_preserve_time) fcopy_matime(dfd, &s_stat); - xclose(sfd); - xclose(dfd); + if (verbose || status_timer || (do_stop == YES && quiet == NO)) print_crypt_status(TFC_SIGLAST); xexit(exitcode); return -1;