51 broke -E logic completely, rewise it
[tfcrypt.git] / tfcrypt.c
index aa7db33eacba393d5f52be7495bdd184ac2a919b..590cb33d2fa4ea2ae104a371ce862c4c8fde716a 100644 (file)
--- a/tfcrypt.c
+++ b/tfcrypt.c
 #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;
 
-       fd = open(logfile, O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC, 0666);
-       if (fd == -1) xerror(NO, NO, YES, "%s", logfile);
+       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);
@@ -123,12 +130,13 @@ static void say_hint(const void *data, size_t szdata, const char *prompt)
 
 int main(int argc, char **argv)
 {
+       tfc_yesno flipfd;
        int c;
        double td;
        char *s, *d, *t, *stoi;
        size_t x, n;
-       tfc_fsize rwd;
 
+       progpid = getpid();
        progname = basename(argv[0]);
 
        if (!isatty(2)) do_statline_dynamic = NO;
@@ -145,12 +153,18 @@ _baddfname:
 
        if (!strcmp(progname, "iotool")) {
                do_edcrypt = TFC_DO_PLAIN;
-               password = YES;
                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:O:S:AmuM: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);
@@ -161,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;
@@ -202,18 +224,23 @@ _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':
                                if (do_edcrypt != TFC_DO_PLAIN) do_edcrypt = TFC_DO_ENCRYPT;
@@ -308,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"))
@@ -334,6 +367,18 @@ _baddfname:
                                                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) == '=') {
@@ -346,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",
@@ -379,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",
@@ -438,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);
@@ -622,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;
@@ -638,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;
@@ -652,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);
 
@@ -721,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);
@@ -757,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,
@@ -792,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);
@@ -838,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;
@@ -993,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) {
@@ -1016,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) {
@@ -1064,18 +1123,15 @@ _ctrskip2:
                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++;
        }
@@ -1127,6 +1183,7 @@ _ctrwagain:       lio = xwrite(dfd, pblk, lrem);
                        lrem -= lio;
                        goto _ctrwagain;
                }
+               total_written_dst += ldone;
                total_processed_dst += ldone;
                delta_processed += ldone;
        }
@@ -1136,7 +1193,7 @@ _ctrwagain:       lio = xwrite(dfd, pblk, lrem);
        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);
+                       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;
@@ -1147,20 +1204,33 @@ _decrypt_again_vrfy2:
                }
                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 = YES;
+               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)
@@ -1172,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;
@@ -1192,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);
@@ -1209,17 +1285,18 @@ _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);
+               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;
@@ -1244,6 +1321,8 @@ _nowrite: total_processed_dst += ldone;
                }
        }
 
+       if (verbose && status_timer && do_statline_dynamic == YES && statline_was_shown == YES) tfc_esay("\n");
+
        errno = 0;
        if (do_mac >= TFC_MAC_VRFY) {
                if (!do_mac_file) {
@@ -1280,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)) {
@@ -1296,40 +1374,40 @@ _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", progname);
-                               do_mac = TFC_MAC_DROP;
+                               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 (do_mac == TFC_MAC_JUST_VRFY2) tfc_esay("%s: -u: MAC signature is invalid, not decrypting it again", progname);
+                               "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;
                }
@@ -1338,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) {
@@ -1364,6 +1440,7 @@ _macwagain:               lio = xwrite(dfd, pblk, lrem);
                                lrem -= lio;
                                goto _macwagain;
                        }
+                       total_written_dst += ldone;
                        total_processed_dst += ldone;
                        delta_processed += ldone;
                }
@@ -1371,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);
@@ -1395,8 +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;
 
-       if (verbose || status_timer || (do_stop == YES && quiet == NO)) print_crypt_status(0);
+       if (verbose || status_timer || (do_stop == YES && quiet == NO)) print_crypt_status(TFC_SIGLAST);
 
        xexit(exitcode);
        return -1;