* 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:
*
#include "tfcrypt.h"
+static tfc_byte svctr[TF_BLOCK_SIZE];
+
+static void open_log(const char *logfile)
+{
+ int fd;
+
+ fd = open(logfile, O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC, 0666);
+ if (fd == -1) xerror(NO, NO, YES, "%s", logfile);
+ xclose(2);
+ if (dup2(fd, 2) == -1) xerror(NO, NO, YES, "dup2(%d, 2) for %s", fd, logfile);
+ xclose(fd);
+ do_statline_dynamic = NO;
+}
+
static int getps_filter(struct getpasswd_state *getps, char chr, size_t pos)
{
if (chr == '\x03') {
double td;
char *s, *d, *t, *stoi;
size_t x, n;
+ tfc_fsize rwd;
progname = basename(argv[0]);
_baddfname:
memset(s, 0, n);
+ if (!strcmp(progname, "iotool")) {
+ do_edcrypt = TFC_DO_PLAIN;
+ password = YES;
+ ctr_mode = TFC_MODE_PLAIN;
+ }
+
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:O:S:AmuM:R:Z:WHD:")) != -1) {
switch (c) {
case 'L':
read_defaults(optarg, NO);
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':
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);
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))) {
do_full_key = YES;
else if (!strcmp(s, "showsecrets"))
show_secrets = YES;
+ 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);
}
else if (!strncmp(s, "ftrunc", 6) && *(s+6) == '=') {
s += 7;
- 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);
+ 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 ftrunc_dfd = tfc_modifysize(ftrunc_dfd, strchr(s, ':'));
}
else if (!strncmp(s, "xkey", 4) && *(s+4) == '=') {
s += 5;
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':
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)
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) {
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);
sigact.sa_handler = change_status_width;
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));
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) {
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 (lio == 0) do_stop = YES;
if (lio != NOSIZE) ldone += lio;
else {
if (errno != EIO && catch_all_errors != YES)
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;
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;
-
errno = 0;
if (do_mac >= TFC_MAC_VRFY) {
if (!do_mac_file) {
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;
}
memset(tmpdata, 0, sizeof(tmpdata));
}
-_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);
- if (ftrunc_dfd != NOFSIZE) if (ftruncate(dfd, (off_t)ftrunc_dfd) == -1) xerror(YES, NO, YES, "ftruncate(%d)", dfd);
- xclose(dfd);
+ if (verbose || status_timer || (do_stop == YES && quiet == NO)) print_crypt_status(0);
xexit(exitcode);
return -1;