X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=tfcrypt.c;h=fb3dfb9cb44a7e0826dc059c13c555ef7ecbc761;hb=c0dc5614a87ed6d0eed4906447171ef4c73b306e;hp=8608cf16011399202e66f08b8855211c6368a56e;hpb=429747d78e7e60b3dc44fd8b23f1626c386663e0;p=tfcrypt.git diff --git a/tfcrypt.c b/tfcrypt.c index 8608cf1..fb3dfb9 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: * @@ -51,6 +51,62 @@ static int getps_hex_filter(struct getpasswd_state *getps, char chr, size_t pos) return 0; } +static inline int isctrlchr(int c) +{ + if (c == 9) return 0; + if (c >= 0 && c <= 31) return 1; + if (c == 127) return 1; + return 0; +} + +static int getps_plain_filter(struct getpasswd_state *getps, char chr, size_t pos) +{ + int x; + + x = getps_filter(getps, chr, pos); + if (x != 1) return x; + + if (pos < getps->pwlen && !isctrlchr(chr)) + write(getps->efd, &chr, sizeof(char)); + return 1; +} + +static int getps_plain_hex_filter(struct getpasswd_state *getps, char chr, size_t pos) +{ + int x; + + x = getps_hex_filter(getps, chr, pos); + if (x != 1) return x; + + if (pos < getps->pwlen && !isctrlchr(chr)) + write(getps->efd, &chr, sizeof(char)); + 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) { int c; @@ -62,9 +118,22 @@ int main(int argc, char **argv) if (!isatty(2)) do_statline_dynamic = NO; + s = (char *)srcblk; + d = getenv("HOME"); + if (!d) d = ""; + n = PATH_MAX > sizeof(srcblk) ? sizeof(srcblk) : PATH_MAX; + if (xstrlcpy(s, d, n) >= n) goto _baddfname; + if (xstrlcat(s, "/.tfcrypt.defs", n) >= n) goto _baddfname; + read_defaults(s, YES); +_baddfname: + memset(s, 0, n); + opterr = 0; - while ((c = getopt(argc, argv, "s:aU:C:r:K:t:TPkzxc: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:AmM:R:Z:WHD:")) != -1) { switch (c) { + case 'L': + read_defaults(optarg, NO); + break; case 's': saltf = optarg; break; @@ -78,6 +147,31 @@ int main(int argc, char **argv) counter_opt = TFC_CTR_HEAD; else if (!strcasecmp(optarg, "rand")) 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': @@ -144,10 +238,7 @@ int main(int argc, char **argv) break; case 't': tweakf = optarg; - break; - case 'T': - tfc_saltsz = 0; - do_tfcrypt1 = YES; + do_full_key = NO; break; case 'l': if (maxlen != NOFSIZE) break; @@ -171,6 +262,10 @@ int main(int argc, char **argv) catch_all_errors = YES; break; } + if (!strcmp(optarg, "xseek")) { + ignore_seek_errors = YES; + break; + } if (!strcmp(optarg, "exit")) error_action = TFC_ERRACT_EXIT; else if (!strncmp(optarg, "cont", 4)) @@ -209,6 +304,10 @@ int main(int argc, char **argv) mac_pw_prompt = s+10; else if (!strcmp(s, "shorthex")) do_full_hexdump = NO; + else if (!strcmp(s, "fullkey")) + do_full_key = YES; + else if (!strcmp(s, "showsecrets")) + show_secrets = YES; else if (!strncmp(s, "iobs", 4) && *(s+4) == '=') { s += 5; blksize = (size_t)tfc_humanfsize(s, &stoi); @@ -324,17 +423,47 @@ int main(int argc, char **argv) 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); if (!str_empty(stoi)) { - maxkeylen = (size_t)tfc_fnamesize(s, YES); - maxkeylen = (size_t)tfc_modifysize((tfc_fsize)maxkeylen, strchr(s, ':')); + maxkeylen = tfc_fnamesize(s, YES); + maxkeylen = tfc_modifysize(maxkeylen, strchr(s, ':')); if (maxkeylen == NOSIZE) xerror(NO, YES, YES, "%s: invalid key length value", s); } - else maxkeylen = (size_t)tfc_modifysize((tfc_fsize)maxkeylen, strchr(s, ':')); + else maxkeylen = tfc_modifysize(maxkeylen, strchr(s, ':')); + } + else if (!strncmp(s, "okey", 4) && *(s+4) == '=') { + s += 5; + keyoffset = tfc_humanfsize(s, &stoi); + if (!str_empty(stoi)) { + keyoffset = tfc_fnamesize(s, YES); + keyoffset = tfc_modifysize(keyoffset, strchr(s, ':')); + if (keyoffset == NOFSIZE) + xerror(NO, YES, YES, + "%s: invalid key offset value", s); + } + else keyoffset = tfc_modifysize(keyoffset, strchr(s, ':')); } else if (!strncmp(s, "xctr", 4) && *(s+4) == '=') { s += 5; @@ -413,6 +542,7 @@ int main(int argc, char **argv) case 'q': quiet = YES; verbose = NO; + do_full_hexdump = NO; status_timer = 0; break; case 'v': @@ -462,8 +592,6 @@ int main(int argc, char **argv) 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 (tweakf && do_tfcrypt1 == NO) - xerror(NO, YES, YES, "Use -T with -t tweakfile to enable old tfcrypt mode!"); if (ctr_mode == TFC_MODE_PLAIN && (do_edcrypt || do_mac || rawkey || mackey_opt || counter_opt || counter_file)) @@ -544,20 +672,14 @@ _mkragain: lio = xread(mkfd, pblk, lrem); getps.passwd = pwdask; getps.pwlen = sizeof(pwdask)-1; getps.echo = mac_pw_prompt ? mac_pw_prompt : "Enter MAC password: "; - getps.charfilter = getps_filter; - getps.maskchar = 'x'; + getps.charfilter = (show_secrets == YES) ? getps_plain_filter : getps_filter; + getps.maskchar = (show_secrets == YES) ? 0 : 'x'; getps.flags = GETP_WAITFILL; 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)); - } } @@ -587,16 +709,16 @@ _mkragain: lio = xread(mkfd, pblk, lrem); else password = YES; errno = 0; - if (do_tfcrypt1 == YES && tweakf) { + if (do_full_key == NO && tweakf) { int twfd; if (!strcmp(tweakf, "-")) twfd = 0; else twfd = open(tweakf, O_RDONLY | O_LARGEFILE); if (twfd == -1) xerror(NO, NO, YES, "%s", tweakf); - lio = ldone = xread(twfd, key+TF_FROM_BITS(TF_MAX_BITS)+TF_SIZE_UNIT, 2*TF_SIZE_UNIT); + lio = ldone = xread(twfd, tweak, TF_TWEAK_SIZE); if (lio == NOSIZE) xerror(NO, NO, YES, "%s", tweakf); - if (ldone < 2*TF_SIZE_UNIT) - xerror(NO, NO, YES, "%s: %zu bytes tweak required", tweakf, 2*TF_SIZE_UNIT); + if (ldone < TF_TWEAK_SIZE) + xerror(NO, NO, YES, "%s: %zu bytes tweak required", tweakf, TF_TWEAK_SIZE); xclose(twfd); } @@ -683,7 +805,7 @@ _ctrskip1: if (counter_opt == TFC_CTR_HEAD && ctr_mode != TFC_MODE_ECB) iseek += ctrsz; if (lseek(sfd, iseek, SEEK_SET) == -1) - xerror(YES, NO, NO, "%s: seek failed", srcfname); + xerror(ignore_seek_errors, NO, NO, "%s: seek failed", srcfname); } if (ctr_mode == TFC_MODE_PLAIN) goto _plain; @@ -739,12 +861,13 @@ _xts2keyaskstr: memset(&getps, 0, sizeof(struct getpasswd_state)); getps.passwd = (char *)pblk; getps.pwlen = n; getps.echo = pw_prompt ? pw_prompt : "Enter rawkey (str): "; - getps.charfilter = getps_filter; - getps.maskchar = 'x'; + getps.charfilter = (show_secrets == YES) ? getps_plain_filter : getps_filter; + getps.maskchar = (show_secrets == YES) ? 0 : 'x'; getps.flags = GETP_WAITFILL; 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); @@ -763,8 +886,8 @@ _rawkey_hex_again: getps.passwd = pwdask; getps.pwlen = (TF_FROM_BITS(TFC_KEY_BITS)*2); getps.echo = pw_prompt ? pw_prompt : "Enter rawkey (hex): "; - getps.charfilter = getps_hex_filter; - getps.maskchar = 'x'; + getps.charfilter = (show_secrets == YES) ? getps_plain_hex_filter : getps_hex_filter; + getps.maskchar = (show_secrets == YES) ? 0 : 'x'; getps.flags = GETP_WAITFILL; n = xgetpasswd(&getps); if (n == NOSIZE) xerror(NO, NO, YES, "getting hex rawkey"); @@ -775,6 +898,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; @@ -789,8 +913,8 @@ _pwdagain: memset(&getps, 0, sizeof(struct getpasswd_state)); getps.passwd = pwdask; getps.pwlen = sizeof(pwdask)-1; getps.echo = pw_prompt ? pw_prompt : "Enter password: "; - getps.charfilter = getps_filter; - getps.maskchar = 'x'; + getps.charfilter = (show_secrets == YES) ? getps_plain_filter : getps_filter; + getps.maskchar = (show_secrets == YES) ? 0 : 'x'; getps.flags = GETP_WAITFILL; n = xgetpasswd(&getps); if (n == NOSIZE) xerror(NO, NO, YES, "getting password"); @@ -809,12 +933,13 @@ _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)); } else { - if (skeinfd(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, kfd, maxkeylen) != YES) + if (skeinfd(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, kfd, keyoffset, maxkeylen) != YES) xerror(NO, NO, YES, "hashing key"); } @@ -883,25 +1008,25 @@ _xts2genkey: if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerro tf_convkey(key); if (ctr_mode == TFC_MODE_XTS) tf_convkey(xtskey); - if (do_tfcrypt1 == YES) { - if (!tweakf) skein(key+TF_FROM_BITS(TF_MAX_BITS)+TF_SIZE_UNIT, 2*TF_UNIT_BITS, NULL, key, TF_FROM_BITS(TFC_KEY_BITS)); - tf_key_tweak_compat(key); + if (do_full_key == NO) { + if (!tweakf) skein(tweak, TF_NR_TWEAK_BITS, NULL, key, TF_FROM_BITS(TFC_KEY_BITS)); + tf_tweak_set(key, tweak); } - if (ctr_mode == TFC_MODE_STREAM) tfe_init_iv(&tfe, key, ctr); 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)); - 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; + 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) { @@ -926,7 +1051,7 @@ _plain: if (oseek) { if (lseek(dfd, oseek, SEEK_SET) == -1) - xerror(YES, NO, NO, "%s: seek failed", dstfname); + xerror(ignore_seek_errors, NO, NO, "%s: seek failed", dstfname); } for (x = 1; x < NSIG; x++) signal(x, SIG_IGN); @@ -973,6 +1098,8 @@ _ctrwagain: lio = xwrite(dfd, pblk, lrem); delta_processed += ldone; } + if (ctr_mode == TFC_MODE_STREAM) tfe_init_iv(&tfe, key, ctr); + errno = 0; do_stop = NO; while (1) { @@ -1213,6 +1340,10 @@ _nomac: if (do_preserve_time) fcopy_matime(dfd, &s_stat); xclose(sfd); + if (do_ftrunc > TFC_NO_FTRUNC) { + if (do_ftrunc == TFC_FTRUNC_TAIL) ftrunc_dfd = total_processed_dst; + if (ftruncate(dfd, (off_t)ftrunc_dfd) == -1) xerror(YES, NO, YES, "ftruncate(%d)", dfd); + } xclose(dfd); xexit(exitcode);