fix counter adjustment on "-c zero -O iseek=".
[tfcrypt.git] / tfcrypt.c
1 /*
2  * tfcrypt -- high security Threefish encryption tool.
3  *
4  * tfcrypt is copyrighted:
5  * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
6  *
7  * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files (the
11  * "Software"), to deal in the Software without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28
29 #include "tfcrypt.h"
30
31 static int getps_filter(struct getpasswd_state *getps, char chr, size_t pos)
32 {
33         if (chr == '\x03') {
34                 getps->retn = ((size_t)-2);
35                 return 6;
36         }
37         return 1;
38 }
39
40 static int getps_hex_filter(struct getpasswd_state *getps, char chr, size_t pos)
41 {
42         if (chr == '\x03') {
43                 getps->retn = ((size_t)-2);
44                 return 6;
45         }
46         if (chr >= '0' && chr <= '9') return 1;
47         if (chr >= 'a' && chr <= 'f') return 1;
48         if (chr >= 'A' && chr <= 'F') return 1;
49         if (chr == '\x7f' || chr == '\x08'
50         || chr == '\x15' || chr == '\x17') return 1;
51         return 0;
52 }
53
54 static inline int isctrlchr(int c)
55 {
56         if (c == 9) return 0;
57         if (c >= 0 && c <= 31) return 1;
58         if (c == 127) return 1;
59         return 0;
60 }
61
62 static int getps_plain_filter(struct getpasswd_state *getps, char chr, size_t pos)
63 {
64         int x;
65
66         x = getps_filter(getps, chr, pos);
67         if (x != 1) return x;
68
69         if (pos < getps->pwlen && !isctrlchr(chr))
70                 write(getps->efd, &chr, sizeof(char));
71         return 1;
72 }
73
74 static int getps_plain_hex_filter(struct getpasswd_state *getps, char chr, size_t pos)
75 {
76         int x;
77
78         x = getps_hex_filter(getps, chr, pos);
79         if (x != 1) return x;
80
81         if (pos < getps->pwlen && !isctrlchr(chr))
82                 write(getps->efd, &chr, sizeof(char));
83         return 1;
84 }
85
86 int main(int argc, char **argv)
87 {
88         int c;
89         double td;
90         char *s, *d, *t, *stoi;
91         size_t x, n;
92
93         progname = basename(argv[0]);
94
95         if (!isatty(2)) do_statline_dynamic = NO;
96
97         s = (char *)srcblk;
98         d = getenv("HOME");
99         if (!d) d = "";
100         n = PATH_MAX > sizeof(srcblk) ? sizeof(srcblk) : PATH_MAX;
101         if (xstrlcpy(s, d, n) >= n) goto _baddfname;
102         if (xstrlcat(s, "/.tfcrypt.defs", n) >= n) goto _baddfname;
103         read_defaults(s, YES);
104 _baddfname:
105         memset(s, 0, n);
106
107         opterr = 0;
108         while ((c = getopt(argc, argv, "L:s:aU:C:r:K:t:Pkzxc:l:qedn:vV:pwE:O:S:AmM:R:Z:WHD:")) != -1) {
109                 switch (c) {
110                         case 'L':
111                                 read_defaults(optarg, NO);
112                                 break;
113                         case 's':
114                                 saltf = optarg;
115                                 break;
116                         case 'r':
117                                 randsource = optarg;
118                                 break;
119                         case 'c':
120                                 if (!strcasecmp(optarg, "show"))
121                                         counter_opt = TFC_CTR_SHOW;
122                                 else if (!strcasecmp(optarg, "head"))
123                                         counter_opt = TFC_CTR_HEAD;
124                                 else if (!strcasecmp(optarg, "rand"))
125                                         counter_opt = TFC_CTR_RAND;
126                                 else if (!strcasecmp(optarg, "zero"))
127                                         counter_opt = TFC_CTR_ZERO;
128                                 else counter_file = sksum_hashlist_file = optarg;
129                                 break;
130                         case 'C':
131                                 if (!strcasecmp(optarg, "ctr"))
132                                         ctr_mode = TFC_MODE_CTR;
133                                 else if (!strcasecmp(optarg, "stream"))
134                                         ctr_mode = TFC_MODE_STREAM;
135                                 else if (!strcasecmp(optarg, "cbc"))
136                                         ctr_mode = TFC_MODE_CBC;
137                                 else if (!strcasecmp(optarg, "ecb"))
138                                         ctr_mode = TFC_MODE_ECB;
139                                 else if (!strcasecmp(optarg, "xts"))
140                                         ctr_mode = TFC_MODE_XTS;
141                                 else if (!strcasecmp(optarg, "ocb"))
142                                         ctr_mode = TFC_MODE_OCB;
143                                 else xerror(NO, YES, YES, "%s: invalid mode of operation", optarg);
144                                 break;
145                         case 'P':
146                                 do_edcrypt = TFC_DO_PLAIN;
147                                 password = YES;
148                                 ctr_mode = TFC_MODE_PLAIN;
149                                 break;
150                         case 'e':
151                                 do_edcrypt = TFC_DO_ENCRYPT;
152                                 break;
153                         case 'd':
154                                 do_edcrypt = TFC_DO_DECRYPT;
155                                 break;
156                         case 'D':
157                                 macbits = strtoul(optarg, &stoi, 10);
158                                 if (macbits == 0 || !str_empty(stoi) || macbits < 8
159                                 || macbits > TF_MAX_BITS || macbits % 8)
160                                         xerror(NO, YES, YES, "%s: invalid MAC bits setting", optarg);
161                                 break;
162                         case 'n':
163                                 nr_turns = sksum_turns = strtoul(optarg, &stoi, 10);
164                                 if (!str_empty(stoi)) xerror(NO, YES, YES, "%s: invalid number of turns", optarg);
165                                 break;
166                         case 'U':
167                                 if (!strcasecmp(optarg, "key"))
168                                         mackey_opt = TFC_MACKEY_RAWKEY;
169                                 else if (!strcasecmp(optarg, "pwd"))
170                                         mackey_opt = TFC_MACKEY_PASSWORD;
171                                 else {
172                                         mackey_opt = TFC_MACKEY_FILE;
173                                         mackeyf = optarg;
174                                 }
175                                 break;
176                         case 'p':
177                                 password = YES;
178                                 break;
179                         case 'k':
180                                 rawkey = TFC_RAWKEY_KEYFILE;
181                                 break;
182                         case 'z':
183                                 rawkey = TFC_RAWKEY_ASKSTR;
184                                 break;
185                         case 'x':
186                                 rawkey = TFC_RAWKEY_ASKHEX;
187                                 break;
188                         case 'K':
189                                 verbose = YES;
190                                 genkeyf = optarg;
191                                 break;
192                         case 't':
193                                 tweakf = optarg;
194                                 do_full_key = NO;
195                                 break;
196                         case 'l':
197                                 if (maxlen != NOFSIZE) break;
198
199                                 maxlen = tfc_humanfsize(optarg, &stoi);
200                                 if (!str_empty(stoi)) {
201                                         maxlen = tfc_fnamesize(optarg, YES);
202                                         maxlen = tfc_modifysize(maxlen, strchr(optarg, ':'));
203                                         if (maxlen == NOFSIZE) xerror(NO, YES, YES,
204                                         "%s: invalid count value", optarg);
205                                 }
206                                 else maxlen = tfc_modifysize(maxlen, strchr(optarg, ':'));
207                                 if (counter_opt == TFC_CTR_HEAD)
208                                         maxlen += TF_BLOCK_SIZE;
209                                 break;
210                         case 'w':
211                                 overwrite_source = YES;
212                                 break;
213                         case 'E':
214                                 if (!strcmp(optarg, "xall")) {
215                                         catch_all_errors = YES;
216                                         break;
217                                 }
218                                 if (!strcmp(optarg, "xseek")) {
219                                         ignore_seek_errors = YES;
220                                         break;
221                                 }
222                                 if (!strcmp(optarg, "exit"))
223                                         error_action = TFC_ERRACT_EXIT;
224                                 else if (!strncmp(optarg, "cont", 4))
225                                         error_action = TFC_ERRACT_CONT;
226                                 else if (!strcmp(optarg, "sync"))
227                                         error_action = TFC_ERRACT_SYNC;
228                                 else if (!strcmp(optarg, "lsync"))
229                                         error_action = TFC_ERRACT_LSYNC;
230                                 else xerror(NO, YES, YES, "invalid error action %s specified", optarg);
231                                 break;
232                         case 'O':
233                                 s = d = optarg; t = NULL;
234                                 while ((s = strtok_r(d, ",", &t))) {
235                                         if (d) d = NULL;
236                                         if (!strcmp(s, "sync"))
237                                                 write_flags |= O_SYNC;
238                                         else if (!strcmp(s, "trunc"))
239                                                 write_flags |= O_TRUNC;
240                                         else if (!strcmp(s, "fsync"))
241                                                 do_fsync = YES;
242                                         else if (!strcmp(s, "pad"))
243                                                 do_pad = YES;
244                                         else if (!strcmp(s, "xtime"))
245                                                 do_preserve_time = YES;
246                                         else if (!strcmp(s, "gibsize"))
247                                                 do_stats_in_gibs = YES;
248                                         else if (!strcmp(s, "plainstats"))
249                                                 do_statline_dynamic = NO;
250                                         else if (!strcmp(s, "statless"))
251                                                 do_less_stats = YES;
252                                         else if (!strcmp(s, "norepeat"))
253                                                 no_repeat = YES;
254                                         else if (!strncmp(s, "prompt", 6) && *(s+6) == '=')
255                                                 pw_prompt = s+7;
256                                         else if (!strncmp(s, "macprompt", 9) && *(s+9) == '=')
257                                                 mac_pw_prompt = s+10;
258                                         else if (!strcmp(s, "shorthex"))
259                                                 do_full_hexdump = NO;
260                                         else if (!strcmp(s, "fullkey"))
261                                                 do_full_key = YES;
262                                         else if (!strcmp(s, "showsecrets"))
263                                                 show_secrets = YES;
264                                         else if (!strncmp(s, "iobs", 4) && *(s+4) == '=') {
265                                                 s += 5;
266                                                 blksize = (size_t)tfc_humanfsize(s, &stoi);
267                                                 if (!str_empty(stoi)) {
268                                                         blksize = (size_t)tfc_fnamesize(s, YES);
269                                                         blksize = (size_t)tfc_modifysize((tfc_fsize)blksize, strchr(s, ':'));
270                                                         if (blksize == NOSIZE) xerror(NO, YES, YES,
271                                                         "%s: invalid block size value", s);
272                                                 }
273                                                 else blksize = (size_t)tfc_modifysize((tfc_fsize)blksize, strchr(s, ':'));
274                                                 if (blksize < TF_BLOCK_SIZE) xerror(NO, YES, YES,
275                                                         "%s: block size is lesser than TF_BLOCK_SIZE (%u bytes)", s, TFC_U(TF_BLOCK_SIZE));
276                                                 if (blksize > TFC_BLKSIZE) xerror(NO, YES, YES,
277                                                         "%s: block size exceeds %u bytes",
278                                                         s, TFC_U(TFC_BLKSIZE));
279                                         }
280                                         else if (!strncmp(s, "xtsblocks", 9) && *(s+9) == '=') {
281                                                 s += 10;
282                                                 xtsblocks = (size_t)tfc_humanfsize(s, &stoi);
283                                                 if (!str_empty(stoi)) {
284                                                         xtsblocks = (size_t)tfc_fnamesize(s, YES);
285                                                         xtsblocks = (size_t)tfc_modifysize((tfc_fsize)xtsblocks, strchr(s, ':'));
286                                                         if (xtsblocks == NOSIZE) xerror(NO, YES, YES,
287                                                         "%s: invalid blocks per xts block value", s);
288                                                 }
289                                                 else xtsblocks = (size_t)tfc_modifysize((tfc_fsize)xtsblocks, strchr(s, ':'));
290                                                 if (TFC_BLKSIZE % xtsblocks) xerror(NO, YES, YES,
291                                                         "%s: nr of blocks per xts block is not round to %u bytes",
292                                                         s, TFC_U(TFC_BLKSIZE));
293                                                 if ((xtsblocks * TF_BLOCK_SIZE) > TFC_BLKSIZE) xerror(NO, YES, YES,
294                                                         "%s: nr of blocks per xts block exceeds %u bytes",
295                                                         s, TFC_U(TFC_BLKSIZE));
296                                         }
297                                         else if (!strncmp(s, "iseek", 5) && *(s+5) == '=') {
298                                                 s += 6;
299                                                 iseek = tfc_humanfsize(s, &stoi);
300                                                 if (!str_empty(stoi)) {
301                                                         iseek = tfc_fnamesize(s, YES);
302                                                         iseek = tfc_modifysize(iseek, strchr(s, ':'));
303                                                         if (iseek == NOFSIZE) xerror(NO, YES, YES,
304                                                         "%s: invalid iseek value", s);
305                                                 }
306                                                 else iseek = tfc_modifysize(iseek, strchr(s, ':'));
307                                                 if (ctr_mode != TFC_MODE_PLAIN && iseek % TF_BLOCK_SIZE)
308                                                         xerror(NO, YES, YES,
309                                                                 "%s: not round to TF block size "
310                                                                 "of %u bytes",
311                                                                 s, TFC_U(TF_BLOCK_SIZE));
312                                                 iseek_blocks = iseek / TF_BLOCK_SIZE;
313                                         }
314                                         else if (!strncmp(s, "ixseek", 6) && *(s+6) == '=') {
315                                                 s += 7;
316                                                 iseek = tfc_humanfsize(s, &stoi);
317                                                 if (!str_empty(stoi)) {
318                                                         iseek = tfc_fnamesize(s, YES);
319                                                         iseek = tfc_modifysize(iseek, strchr(s, ':'));
320                                                         if (iseek == NOFSIZE) xerror(NO, YES, YES,
321                                                                 "%s: invalid ixseek value", s);
322                                                 }
323                                                 else iseek = tfc_modifysize(iseek, strchr(s, ':'));
324                                         }
325                                         else if (!strncmp(s, "ictr", 4) && *(s+4) == '=') {
326                                                 s += 5;
327                                                 iseek_blocks = tfc_humanfsize(s, &stoi);
328                                                 if (!str_empty(stoi)) {
329                                                         iseek_blocks = tfc_fnamesize(s, YES);
330                                                         if (iseek_blocks == NOFSIZE)
331                                                                 xerror(NO, YES, YES,
332                                                                 "%s: invalid ictr value", s);
333                                                         iseek_blocks /= TF_BLOCK_SIZE;
334                                                         iseek_blocks = tfc_modifysize(iseek_blocks, strchr(s, ':'));
335                                                 }
336                                                 else iseek_blocks = tfc_modifysize(iseek_blocks, strchr(s, ':'));
337                                         }
338                                         else if (!strncmp(s, "ixctr", 5) && *(s+5) == '=') {
339                                                 s += 6;
340                                                 iseek_blocks = tfc_humanfsize(s, &stoi);
341                                                 if (!str_empty(stoi)) {
342                                                         iseek_blocks = tfc_fnamesize(s, YES);
343                                                         iseek_blocks = tfc_modifysize(iseek_blocks, strchr(s, ':'));
344                                                         if (iseek_blocks == NOFSIZE)
345                                                                 xerror(NO, YES, YES,
346                                                                 "%s: invalid ixctr value", s);
347                                                 }
348                                                 else iseek_blocks = tfc_modifysize(iseek_blocks, strchr(s, ':'));
349                                                 if (iseek_blocks % TF_BLOCK_SIZE)
350                                                         xerror(NO, YES, YES,
351                                                         "%s: not round to TF block size "
352                                                         "of %u bytes", s, TFC_U(TF_BLOCK_SIZE));
353                                                 iseek_blocks /= TF_BLOCK_SIZE;
354                                         }
355                                         else if (!strncmp(s, "oseek", 5) && *(s+5) == '=') {
356                                                 s += 6;
357                                                 oseek = tfc_humanfsize(s, &stoi);
358                                                 if (!str_empty(stoi)) {
359                                                         oseek = tfc_fnamesize(s, YES);
360                                                         oseek = tfc_modifysize(oseek, strchr(s, ':'));
361                                                         if (oseek == NOFSIZE) xerror(NO, YES, YES,
362                                                         "%s: invalid oseek value", s);
363                                                 }
364                                                 else oseek = tfc_modifysize(oseek, strchr(s, ':'));
365                                         }
366                                         else if (!strncmp(s, "count", 5) && *(s+5) == '=') {
367                                                 s += 6;
368                                                 maxlen = tfc_humanfsize(s, &stoi);
369                                                 if (!str_empty(stoi)) {
370                                                         maxlen = tfc_fnamesize(s, YES);
371                                                         maxlen = tfc_modifysize(maxlen, strchr(s, ':'));
372                                                         if (maxlen == NOFSIZE) xerror(NO, YES, YES,
373                                                         "%s: invalid count value", s);
374                                                 }
375                                                 else maxlen = tfc_modifysize(maxlen, strchr(s, ':'));
376                                                 if (counter_opt == TFC_CTR_HEAD)
377                                                         maxlen += TF_BLOCK_SIZE;
378                                         }
379                                         else if (!strncmp(s, "xkey", 4) && *(s+4) == '=') {
380                                                 s += 5;
381                                                 maxkeylen = tfc_humanfsize(s, &stoi);
382                                                 if (!str_empty(stoi)) {
383                                                         maxkeylen = tfc_fnamesize(s, YES);
384                                                         maxkeylen = tfc_modifysize(maxkeylen, strchr(s, ':'));
385                                                         if (maxkeylen == NOSIZE)
386                                                                 xerror(NO, YES, YES,
387                                                                 "%s: invalid key length value", s);
388                                                 }
389                                                 else maxkeylen = tfc_modifysize(maxkeylen, strchr(s, ':'));
390                                         }
391                                         else if (!strncmp(s, "okey", 4) && *(s+4) == '=') {
392                                                 s += 5;
393                                                 keyoffset = tfc_humanfsize(s, &stoi);
394                                                 if (!str_empty(stoi)) {
395                                                         keyoffset = tfc_fnamesize(s, YES);
396                                                         keyoffset = tfc_modifysize(keyoffset, strchr(s, ':'));
397                                                         if (keyoffset == NOFSIZE)
398                                                                 xerror(NO, YES, YES,
399                                                                 "%s: invalid key offset value", s);
400                                                 }
401                                                 else keyoffset = tfc_modifysize(keyoffset, strchr(s, ':'));
402                                         }
403                                         else if (!strncmp(s, "xctr", 4) && *(s+4) == '=') {
404                                                 s += 5;
405                                                 ctrsz = tfc_humanfsize(s, &stoi);
406                                                 if (!str_empty(stoi)) {
407                                                         ctrsz = (size_t)tfc_fnamesize(s, YES);
408                                                         ctrsz = (size_t)tfc_modifysize((tfc_fsize)ctrsz, strchr(s, ':'));
409                                                         if (ctrsz == NOSIZE)
410                                                                 xerror(NO, YES, YES,
411                                                                 "%s: invalid counter length value", s);
412                                                 }
413                                                 else ctrsz = (size_t)tfc_modifysize((tfc_fsize)ctrsz, strchr(s, ':'));
414                                                 if (ctrsz > TF_BLOCK_SIZE)
415                                                         xerror(NO, YES, YES, "%s: counter size cannot exceed TF block size", s);
416                                         }
417                                         else xerror(NO, YES, YES, "invalid option %s", s);
418                                 }
419                                 break;
420                         case 'S':
421                                 do_mac = TFC_MAC_SIGN;
422                                 if (strcasecmp(optarg, "mac") != 0)
423                                         do_mac_file = optarg;
424                                 break;
425                         case 'M':
426                                 do_mac = TFC_MAC_VRFY;
427                                 if (!strcasecmp(optarg, "drop"))
428                                         do_mac = TFC_MAC_DROP;
429                                 else if (strcasecmp(optarg, "mac") != 0)
430                                         do_mac_file = optarg;
431                                 break;
432                         case 'm':
433                                 if (do_mac != TFC_MAC_VRFY)
434                                         xerror(NO, YES, YES, "signature source was not specified");
435                                 do_mac = TFC_MAC_JUST_VRFY;
436                                 break;
437                         case 'R':
438                         case 'Z':
439                                 if (maxlen != NOFSIZE) {
440                                         if (c == 'Z') genzero_nr_bytes = maxlen;
441                                         else genrandom_nr_bytes = maxlen;
442                                 }
443                                 else {
444                                         tfc_fsize t;
445                                         if (!strcasecmp(optarg, "cbs"))
446                                                 t = TF_BLOCK_SIZE;
447                                         else if (!strcasecmp(optarg, "ks"))
448                                                 t = TF_FROM_BITS(TFC_KEY_BITS);
449                                         else if (!strcasecmp(optarg, "xks"))
450                                                 t = TF_FROM_BITS(TFC_KEY_BITS) * 2;
451                                         else if (!strcasecmp(optarg, "iobs"))
452                                                 t = blksize;
453                                         else {
454                                                 t = tfc_humanfsize(optarg, &stoi);
455                                                 if (!str_empty(stoi)) {
456                                                         t = tfc_fnamesize(optarg, NO);
457                                                         t = tfc_modifysize(t, strchr(optarg, ':'));
458                                                 }
459                                                 else t = tfc_modifysize(t, strchr(optarg, ':'));
460                                         }
461                                         if (c == 'Z') genzero_nr_bytes = maxlen = t;
462                                         else genrandom_nr_bytes = maxlen = t;
463                                 }
464                                 break;
465                         case 'a':
466                                 do_preserve_time = YES;
467                                 break;
468                         case 'A':
469                                 do_outfmt = TFC_OUTFMT_B64;
470                                 break;
471                         case 'W':
472                                 do_outfmt = TFC_OUTFMT_RAW;
473                                 break;
474                         case 'H':
475                                 do_outfmt = TFC_OUTFMT_HEX;
476                                 break;
477                         case 'q':
478                                 quiet = YES;
479                                 verbose = NO;
480                                 status_timer = 0;
481                                 break;
482                         case 'v':
483                                 verbose = YES;
484                                 break;
485                         case 'V':
486                                 td = strtod(optarg, &stoi);
487                                 status_timer = TFC_DTOUSECS(td);
488                                 if (status_timer <= TFC_DTOUSECS(0) || !str_empty(stoi)) status_timer = 0;
489                                 break;
490                         default:
491                                 usage();
492                                 break;
493                 }
494         }
495
496         if (!strcmp(progname, "tfbench")) {
497                 if (!*(argv+optind)) usage();
498
499                 td = strtod(*(argv+optind), &stoi);
500                 if (td <= TFC_DTOUSECS(0) || !str_empty(stoi))
501                         xerror(NO, YES, YES,
502                         "%s: invalid benchmark time in seconds", *(argv+optind));
503                 bench_timer = TFC_DTOUSECS(td);
504                 do_benchmark(bench_timer, td);
505         }
506         if (genrandom_nr_bytes) {
507                 ctr_mode = TFC_MODE_STREAM;
508                 do_edcrypt = TFC_DO_ENCRYPT;
509                 gen_write_bytes(*(argv+optind), oseek, genrandom_nr_bytes);
510         }
511         if (genzero_nr_bytes) {
512                 ctr_mode = TFC_MODE_PLAIN;
513                 do_edcrypt = TFC_DO_PLAIN;
514                 gen_write_bytes(*(argv+optind), oseek, genzero_nr_bytes);
515         }
516
517         if (rawkey && password)
518                 xerror(NO, YES, YES, "Cannot use rawkey and hashing password!");
519         if (do_edcrypt == TFC_DO_ENCRYPT && do_mac >= TFC_MAC_VRFY)
520                 xerror(NO, YES, YES, "Cannot encrypt and verify signature!");
521         if (do_edcrypt == TFC_DO_DECRYPT && do_mac == TFC_MAC_SIGN)
522                 xerror(NO, YES, YES, "Cannot decrypt and calculate signature!");
523         if (do_edcrypt == TFC_DO_DECRYPT && counter_opt == TFC_CTR_RAND)
524                 xerror(NO, YES, YES, "Cannot decrypt and embed a generated CTR into file!");
525         if (do_edcrypt == TFC_DO_ENCRYPT && counter_opt == TFC_CTR_HEAD)
526                 xerror(NO, YES, YES, "Cannot encrypt and read CTR from source!");
527         if (overwrite_source && counter_opt == TFC_CTR_RAND)
528                 xerror(NO, YES, YES, "Cannot embed a CTR into file when overwriting it!");
529         if (ctr_mode == TFC_MODE_PLAIN
530         && (do_edcrypt || do_mac || rawkey
531         || mackey_opt || counter_opt || counter_file))
532                 xerror(NO, YES, YES, "Encryption facility is disabled when in plain IO mode.");
533
534         errno = 0;
535         do_stop = NO;
536
537         if (saltf) {
538                 int saltfd;
539
540                 memset(tfc_salt, 0, TFC_MAX_SALT);
541                 tfc_saltsz = 0;
542                 if (!strcasecmp(saltf, "disable")) goto _nosalt;
543
544                 if (!strcmp(saltf, "-")) saltfd = 0;
545                 else saltfd = open(saltf, O_RDONLY | O_LARGEFILE);
546                 if (saltfd == -1) xerror(NO, NO, YES, "%s", saltf);
547                 lio = xread(saltfd, tfc_salt, TFC_MAX_SALT - TF_FROM_BITS(TFC_KEY_BITS));
548                 if (lio == NOSIZE) xerror(NO, NO, YES, "%s", saltf);
549                 tfc_saltsz = lio;
550                 xclose(saltfd);
551         }
552
553 _nosalt:
554         if (mackey_opt == TFC_MACKEY_FILE && mackeyf) {
555                 int mkfd = -1;
556                 tfc_yesno do_stop;
557
558                 if (!strcmp(mackeyf, "-")) mkfd = 0;
559                 else mkfd = open(mackeyf, O_RDONLY | O_LARGEFILE);
560                 if (mkfd == -1) xerror(NO, NO, YES, "%s", mackeyf);
561
562                 skein_init(&sk, TFC_KEY_BITS);
563
564                 do_stop = NO;
565                 while (1) {
566                         if (do_stop) break;
567                         pblk = tmpdata;
568                         ldone = 0;
569                         lrem = lblock = sizeof(tmpdata);
570                         if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(mkfd);
571 _mkragain:              lio = xread(mkfd, pblk, lrem);
572                         if (lio == 0) do_stop = YES;
573                         if (lio != NOSIZE) ldone += lio;
574                         else {
575                                 if (errno != EIO && catch_all_errors != YES)
576                                         xerror(NO, NO, NO, "%s", mackeyf);
577                                 switch (error_action) {
578                                         case TFC_ERRACT_CONT: xerror(YES, NO, NO, "%s", mackeyf); goto _mkragain; break;
579                                         case TFC_ERRACT_SYNC:
580                                         case TFC_ERRACT_LSYNC:
581                                                 xerror(YES, NO, NO, "%s", mackeyf);
582                                                 lio = ldone = lrem = lblock;
583                                                 memset(tmpdata, 0, lio);
584                                                 if (rdpos == NOFSIZE) lseek(mkfd, lio, SEEK_CUR);
585                                                 else lseek(mkfd, rdpos + lio, SEEK_SET);
586                                                 break;
587                                         default: xerror(NO, NO, NO, "%s", mackeyf); break;
588                                 }
589                         }
590                         if (lio && lio < lrem) {
591                                 pblk += lio;
592                                 lrem -= lio;
593                                 goto _mkragain;
594                         }
595
596                         skein_update(&sk, tmpdata, ldone);
597                 }
598
599                 skein_final(mackey, &sk);
600
601                 xclose(mkfd);
602         }
603         else if (mackey_opt == TFC_MACKEY_PASSWORD) {
604                 memset(&getps, 0, sizeof(struct getpasswd_state));
605                 getps.fd = getps.efd = -1;
606                 getps.passwd = pwdask;
607                 getps.pwlen = sizeof(pwdask)-1;
608                 getps.echo = mac_pw_prompt ? mac_pw_prompt : "Enter MAC password: ";
609                 getps.charfilter = (show_secrets == YES) ? getps_plain_filter : getps_filter;
610                 getps.maskchar = (show_secrets == YES) ? 0 : 'x';
611                 getps.flags = GETP_WAITFILL;
612                 n = xgetpasswd(&getps);
613                 if (n == NOSIZE) xerror(NO, NO, YES, "getting MAC password");
614                 if (n == ((size_t)-2)) xexit(1);
615                 skein(mackey, TF_MAX_BITS, NULL, pwdask, n);
616                 if (verbose) {
617                         skein(tmpdata, TF_MAX_BITS, NULL, mackey, TF_FROM_BITS(TF_MAX_BITS));
618                         xor_shrink(tmpdata+TF_FROM_BITS(TF_MAX_BITS), TF_SIZE_UNIT, tmpdata, TF_FROM_BITS(TF_MAX_BITS));
619                         tfc_nfsay(stderr, "MAC password hint: ");
620                         mehexdump(tmpdata+TF_FROM_BITS(TF_MAX_BITS), TF_SIZE_UNIT, TF_SIZE_UNIT, 1);
621                         memset(tmpdata, 0, sizeof(tmpdata));
622                 }
623         }
624
625         
626         if ((strlen(progname) <= 9)
627         && ((!strcmp(progname, "sksum"))
628         || ((!memcmp(progname, "sk", 2))
629         && (!memcmp(progname+3, "sum", 3)
630         || !memcmp(progname+4, "sum", 3)
631         || !memcmp(progname+5, "sum", 3)
632         || !memcmp(progname+6, "sum", 3)))))
633                 do_sksum(progname, argv+optind);
634         if (!strcmp(progname, "tfbase64")) do_edbase64(argv+optind);
635
636         idx = optind;
637
638         if (argv[idx]) {
639                 if (password || rawkey > TFC_RAWKEY_KEYFILE) goto _nokeyfd;
640                 if (!strcmp(argv[idx], "-")) kfd = 0;
641                 else kfd = open(argv[idx], O_RDONLY | O_LARGEFILE);
642                 if (kfd == -1) xerror(NO, NO, YES, "%s", argv[idx]);
643
644                 lio = strnlen(argv[idx], PATH_MAX);
645                 memset(argv[idx], '*', lio);
646
647                 idx++;
648         }
649         else password = YES;
650
651         errno = 0;
652         if (do_full_key == NO && tweakf) {
653                 int twfd;
654
655                 if (!strcmp(tweakf, "-")) twfd = 0;
656                 else twfd = open(tweakf, O_RDONLY | O_LARGEFILE);
657                 if (twfd == -1) xerror(NO, NO, YES, "%s", tweakf);
658                 lio = ldone = xread(twfd, tweak, TF_TWEAK_SIZE);
659                 if (lio == NOSIZE) xerror(NO, NO, YES, "%s", tweakf);
660                 if (ldone < TF_TWEAK_SIZE)
661                         xerror(NO, NO, YES, "%s: %zu bytes tweak required", tweakf, TF_TWEAK_SIZE);
662                 xclose(twfd);
663         }
664
665 _nokeyfd:
666         errno = 0;
667         if (argv[idx]) {
668                 if (!strcmp(argv[idx], "-") && kfd) sfd = 0;
669                 else {
670                         sfd = open(argv[idx], O_RDONLY | O_LARGEFILE);
671                         if (do_preserve_time) if (fstat(sfd, &s_stat) == -1)
672                                 xerror(YES, NO, YES, "stat(%s)", argv[idx]);
673                 }
674                 if (sfd == -1) xerror(NO, NO, YES, "%s", argv[idx]);
675
676                 if (do_edcrypt == TFC_DO_DECRYPT && do_mac != NO && maxlen != NOFSIZE) {
677                         if (verbose) tfc_esay("%s: disabling signature verification on "
678                                 "requested partial decryption.", progname);
679                         do_mac = NO;
680                 }
681
682                 if ((do_mac >= TFC_MAC_VRFY || do_mac == TFC_MAC_DROP) && !do_mac_file) {
683                         maxlen = tfc_fdsize(sfd);
684                         if (maxlen == NOFSIZE)
685                                 xerror(NO, YES, YES,
686                                 "Cannot verify embedded MAC with non-seekable source!");
687                         maxlen -= TF_FROM_BITS(macbits);
688                 }
689                 srcfname = argv[idx];
690                 idx++;
691         }
692
693         if (!do_mac_file && (do_mac >= TFC_MAC_VRFY && sfd == 0))
694                 xerror(NO, YES, YES, "Cannot verify embedded MAC with non-seekable source!");
695
696         if (ctrsz == NOSIZE) ctrsz = TF_BLOCK_SIZE;
697         if (ctrsz > TF_BLOCK_SIZE) ctrsz = TF_BLOCK_SIZE;
698
699         if (ctr_mode == TFC_MODE_ECB) goto _ctrskip1;
700         errno = 0;
701         if (counter_file) {
702                 int ctrfd;
703
704                 if (!strcmp(counter_file, "-")) ctrfd = 0;
705                 else ctrfd = open(counter_file, O_RDONLY | O_LARGEFILE);
706                 if (ctrfd == -1) xerror(NO, NO, YES, "%s", counter_file);
707                 lio = xread(ctrfd, ctr, ctrsz);
708                 if (lio == NOSIZE) xerror(NO, NO, YES, "%s", counter_file);
709                 if (lio < ctrsz) xerror(NO, YES, YES, "counter file is too small (%zu)!", lio);
710                 xclose(ctrfd);
711         }
712         else if (counter_opt == TFC_CTR_HEAD) {
713                 pblk = ctr;
714                 ldone = 0;
715                 lrem = lblock = ctrsz;
716                 if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(sfd);
717 _ctrragain:     lio = xread(sfd, pblk, lrem);
718                 if (lio != NOSIZE) ldone += lio;
719                 else {
720                         if (errno != EIO && catch_all_errors != YES)
721                                 xerror(NO, NO, NO, "%s", srcfname);
722                         switch (error_action) {
723                                 case TFC_ERRACT_CONT: xerror(YES, NO, NO, "%s", srcfname); goto _ctrragain; break;
724                                 case TFC_ERRACT_SYNC:
725                                 case TFC_ERRACT_LSYNC:
726                                         xerror(YES, NO, NO, "%s", srcfname);
727                                         lio = ldone = lrem = lblock;
728                                         memset(ctr, 0, lio);
729                                         if (rdpos == NOFSIZE) lseek(sfd, lio, SEEK_CUR);
730                                         else lseek(sfd, rdpos + lio, SEEK_SET);
731                                         break;
732                                 default: xerror(NO, NO, NO, "%s", srcfname); break;
733                         }
734                 }
735                 if (lio && lio < lrem) {
736                         pblk += lio;
737                         lrem -= lio;
738                         goto _ctrragain;
739                 }
740                 total_processed_src += ldone;
741         }
742
743 _ctrskip1:
744         if (iseek) {
745                 if (counter_opt == TFC_CTR_HEAD && ctr_mode != TFC_MODE_ECB)
746                         iseek += ctrsz;
747                 if (lseek(sfd, iseek, SEEK_SET) == -1)
748                         xerror(ignore_seek_errors, NO, NO, "%s: seek failed", srcfname);
749         }
750
751         if (ctr_mode == TFC_MODE_PLAIN) goto _plain;
752
753         if (verbose) tfc_esay("%s: hashing password", progname);
754
755         if (rawkey == TFC_RAWKEY_KEYFILE) {
756                 tfc_yesno xtskeyset = NO;
757
758                 pblk = key;
759 _xts2key:       ldone = 0;
760                 lrem = lblock = TF_FROM_BITS(TFC_KEY_BITS);
761                 if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(kfd);
762 _keyragain:     lio = xread(kfd, pblk, lrem);
763                 if (lio != NOSIZE) ldone += lio;
764                 else {
765                         if (errno != EIO && catch_all_errors != YES)
766                                 xerror(NO, NO, NO, "reading key");
767                         switch (error_action) {
768                                 case TFC_ERRACT_CONT: xerror(YES, NO, NO, "reading key"); goto _keyragain; break;
769                                 case TFC_ERRACT_SYNC:
770                                 case TFC_ERRACT_LSYNC:
771                                         xerror(YES, NO, NO, "reading key");
772                                         lio = ldone = lrem = lblock;
773                                         memset(key, 0, lio);
774                                         if (rdpos == NOFSIZE) lseek(kfd, lio, SEEK_CUR);
775                                         else lseek(kfd, rdpos + lio, SEEK_SET);
776                                         break;
777                                 default: xerror(NO, NO, NO, "reading key"); break;
778                         }
779                 }
780                 if (lio && lio < lrem) {
781                         pblk += lio;
782                         lrem -= lio;
783                         goto _keyragain;
784                 }
785                 if (ldone < lblock) xerror(NO, YES, YES, "rawkey too small! (%zu)", ldone);
786
787                 if (ctr_mode == TFC_MODE_XTS) {
788                         if (xtskeyset == NO) {
789                                 pblk = xtskey;
790                                 xtskeyset = YES;
791                                 goto _xts2key;
792                         }
793                 }
794         }
795         else if (rawkey == TFC_RAWKEY_ASKSTR) {
796                 tfc_yesno xtskeyset = NO;
797
798                 pblk = key; n = sizeof(key);
799 _xts2keyaskstr: memset(&getps, 0, sizeof(struct getpasswd_state));
800                 getps.fd = getps.efd = -1;
801                 getps.passwd = (char *)pblk;
802                 getps.pwlen = n;
803                 getps.echo = pw_prompt ? pw_prompt : "Enter rawkey (str): ";
804                 getps.charfilter = (show_secrets == YES) ? getps_plain_filter : getps_filter;
805                 getps.maskchar = (show_secrets == YES) ? 0 : 'x';
806                 getps.flags = GETP_WAITFILL;
807                 n = xgetpasswd(&getps);
808                 if (n == NOSIZE) xerror(NO, NO, YES, "getting string rawkey");
809                 if (n == ((size_t)-2)) xexit(1);
810                 if (ctr_mode == TFC_MODE_XTS) {
811                         if (xtskeyset == NO) {
812                                 pblk = xtskey; n = sizeof(xtskey);
813                                 xtskeyset = YES;
814                                 goto _xts2keyaskstr;
815                         }
816                 }
817         }
818         else if (rawkey == TFC_RAWKEY_ASKHEX) {
819                 tfc_yesno xtskeyset = NO;
820
821                 pblk = key;
822 _rawkey_hex_again:
823                 memset(&getps, 0, sizeof(struct getpasswd_state));
824                 getps.fd = getps.efd = -1;
825                 getps.passwd = pwdask;
826                 getps.pwlen = (TF_FROM_BITS(TFC_KEY_BITS)*2);
827                 getps.echo = pw_prompt ? pw_prompt : "Enter rawkey (hex): ";
828                 getps.charfilter = (show_secrets == YES) ? getps_plain_hex_filter : getps_hex_filter;
829                 getps.maskchar = (show_secrets == YES) ? 0 : 'x';
830                 getps.flags = GETP_WAITFILL;
831                 n = xgetpasswd(&getps);
832                 if (n == NOSIZE) xerror(NO, NO, YES, "getting hex rawkey");
833                 if (n == ((size_t)-2)) xexit(1);
834                 if (n % 2) {
835                         tfc_esay("Please input even number of hex digits!");
836                         goto _rawkey_hex_again;
837                 }
838                 hex2bin(pblk, pwdask);
839                 memset(pwdask, 0, sizeof(pwdask));
840                 if (ctr_mode == TFC_MODE_XTS) {
841                         if (xtskeyset == NO) {
842                                 pblk = xtskey;
843                                 xtskeyset = YES;
844                                 goto _rawkey_hex_again;
845                         }
846                 }
847         }
848         else if (password) {
849 _pwdagain:      memset(&getps, 0, sizeof(struct getpasswd_state));
850                 getps.fd = getps.efd = -1;
851                 getps.passwd = pwdask;
852                 getps.pwlen = sizeof(pwdask)-1;
853                 getps.echo = pw_prompt ? pw_prompt : "Enter password: ";
854                 getps.charfilter = (show_secrets == YES) ? getps_plain_filter : getps_filter;
855                 getps.maskchar = (show_secrets == YES) ? 0 : 'x';
856                 getps.flags = GETP_WAITFILL;
857                 n = xgetpasswd(&getps);
858                 if (n == NOSIZE) xerror(NO, NO, YES, "getting password");
859                 if (n == ((size_t)-2)) xexit(1);
860                 if (do_edcrypt == TFC_DO_ENCRYPT && no_repeat == NO) {
861                         getps.fd = getps.efd = -1;
862                         getps.passwd = pwdagain;
863                         getps.pwlen = sizeof(pwdagain)-1;
864                         getps.echo = "Enter it again: ";
865                         getps.flags = GETP_WAITFILL;
866                         n = xgetpasswd(&getps);
867                         if (n == NOSIZE) xerror(NO, NO, YES, "getting password again");
868                         if (n == ((size_t)-2)) xexit(1);
869                         if (strncmp(pwdask, pwdagain, sizeof(pwdagain)-1) != 0) {
870                                 tfc_esay("Passwords are different, try again");
871                                 goto _pwdagain;
872                         }
873                 }
874                 skein(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, pwdask, n);
875                 memset(pwdask, 0, sizeof(pwdask));
876                 memset(pwdagain, 0, sizeof(pwdagain));
877         }
878         else {
879                 if (skeinfd(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, kfd, keyoffset, maxkeylen) != YES)
880                         xerror(NO, NO, YES, "hashing key");
881         }
882
883         if (rawkey == NO) {
884                 if (tfc_saltsz > 0) {
885                         memcpy(tfc_salt+tfc_saltsz, key, TF_FROM_BITS(TFC_KEY_BITS));
886                         skein(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, tfc_salt, tfc_saltsz+TF_FROM_BITS(TFC_KEY_BITS));
887                 }
888                 if (nr_turns > 1) for (x = 0; x < nr_turns; x++)
889                         skein(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, key, TF_FROM_BITS(TFC_KEY_BITS));
890                 memset(tfc_salt, 0, TFC_MAX_SALT);
891         }
892
893         if (ctr_mode == TFC_MODE_XTS && rawkey == NO) {
894                 skein(xtskey, TF_NR_KEY_BITS, mackey_opt ? mackey : NULL, key, TF_FROM_BITS(TFC_KEY_BITS));
895         }
896
897         if (genkeyf) {
898                 int krfd;
899                 tfc_yesno xtskeyset = NO;
900
901                 pblk = key;
902                 if (!strcmp(genkeyf, "-")) krfd = 1;
903                 else krfd = open(genkeyf, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
904                 if (krfd == -1) xerror(NO, NO, YES, "%s", genkeyf);
905 _xts2genkey:    if (xwrite(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == NOSIZE) xerror(NO, NO, YES, "%s", genkeyf);
906                 if (do_fsync && fsync(krfd) == -1) xerror(NO, NO, YES, "%s", genkeyf);
907                 if (verbose && xtskeyset == NO) {
908                         tfc_esay("%s: password hashing done", progname);
909                         tfc_esay("%s: rawkey written to %s.", progname, genkeyf);
910                         tfc_esay("%s: Have a nice day!", progname);
911                 }
912
913                 if (ctr_mode == TFC_MODE_XTS) {
914                         if (xtskeyset == NO) {
915                                 pblk = xtskey;
916                                 xtskeyset = YES;
917                                 goto _xts2genkey;
918                         }
919                 }
920
921                 fchmod(krfd, 0600);
922                 xclose(krfd);
923                 xexit(0);
924         }
925
926         if (iseek_blocks && (do_edcrypt == TFC_DO_DECRYPT && do_mac != NO)) {
927                 if (verbose) tfc_esay("%s: disabling signature verification on "
928                         "requested partial decryption.", progname);
929                 do_mac = NO;
930         }
931
932         if (do_mac != NO) {
933                 if (mackey_opt == TFC_MACKEY_RAWKEY) skein(mackey, TF_MAX_BITS, key, key, TF_FROM_BITS(TFC_KEY_BITS));
934                 if (ctr_mode < TFC_MODE_OCB) {
935                         if (verbose) tfc_esay("%s: doing MAC calculation, processing speed "
936                                 "will be slower.", progname);
937                         if (mackey_opt) skein_init_key(&sk, mackey, macbits);
938                         else skein_init(&sk, macbits);
939                 }
940         }
941
942         if (!counter_file && counter_opt <= TFC_CTR_SHOW && ctr_mode != TFC_MODE_ECB) {
943                 skein(ctr, TF_TO_BITS(ctrsz), mackey_opt ? mackey : NULL, key, TF_FROM_BITS(TFC_KEY_BITS));
944         }
945
946         tf_convkey(key);
947         if (ctr_mode == TFC_MODE_XTS) tf_convkey(xtskey);
948         if (do_full_key == NO) {
949                 if (!tweakf) skein(tweak, TF_NR_TWEAK_BITS, NULL, key, TF_FROM_BITS(TFC_KEY_BITS));
950                 tf_tweak_set(key, tweak);
951         }
952         if (ctr_mode == TFC_MODE_ECB) goto _ctrskip2;
953
954         if (counter_opt == TFC_CTR_ZERO) memset(ctr, 0, ctrsz);
955
956         tfc_data_to_words64(&iseek_blocks, sizeof(iseek_blocks));
957         tf_ctr_set(ctr, &iseek_blocks, sizeof(iseek_blocks));
958
959         if (counter_opt == TFC_CTR_SHOW) {
960                 switch (do_outfmt) {
961                         case TFC_OUTFMT_B64: tfc_printbase64(stderr, ctr, ctrsz, YES); break;
962                         case TFC_OUTFMT_RAW: xwrite(2, ctr, ctrsz); break;
963                         case TFC_OUTFMT_HEX: mehexdump(ctr, ctrsz, ctrsz, YES); break;
964                 }
965         }
966         else if (counter_opt == TFC_CTR_RAND) tfc_getrandom(ctr, ctrsz);
967
968 _ctrskip2:
969         if (kfd != -1) {
970                 xclose(kfd);
971                 kfd = -1;
972         }
973         if (verbose) tfc_esay("%s: password hashing done", progname);
974
975         if (overwrite_source && srcfname) argv[idx] = srcfname;
976
977 _plain:
978         if (argv[idx]) {
979                 if (!strcmp(argv[idx], "-")) dfd = 1;
980                 else dfd = open(argv[idx], O_RDWR | O_LARGEFILE | write_flags, 0666);
981                 if (dfd == -1) {
982                         dfd = open(argv[idx], O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
983                         if (dfd == -1) xerror(NO, NO, YES, "%s", argv[idx]);
984                 }
985                 dstfname = argv[idx];
986                 idx++;
987         }
988
989         if (oseek) {
990                 if (lseek(dfd, oseek, SEEK_SET) == -1)
991                         xerror(ignore_seek_errors, NO, NO, "%s: seek failed", dstfname);
992         }
993
994         for (x = 1; x < NSIG; x++) signal(x, SIG_IGN);
995         memset(&sigact, 0, sizeof(sigact));
996         sigact.sa_flags = SA_RESTART;
997         sigact.sa_handler = print_crypt_status;
998         sigaction(SIGUSR1, &sigact, NULL);
999         sigaction(SIGTSTP, &sigact, NULL);
1000         sigaction(SIGALRM, &sigact, NULL);
1001         if (status_timer) setup_next_alarm(status_timer);
1002         sigact.sa_handler = change_status_width;
1003         sigaction(SIGQUIT, &sigact, NULL);
1004         sigact.sa_handler = change_status_timer;
1005         sigaction(SIGUSR2, &sigact, NULL);
1006         if (quiet == NO) {
1007                 sigact.sa_handler = print_crypt_status;
1008                 sigaction(SIGINT, &sigact, NULL);
1009                 sigaction(SIGTERM, &sigact, NULL);
1010         }
1011         else {
1012                 sigact.sa_handler = exit_sigterm;
1013                 sigaction(SIGINT, &sigact, NULL);
1014                 sigaction(SIGTERM, &sigact, NULL);
1015         }
1016         memset(&sigact, 0, sizeof(struct sigaction));
1017
1018         tfc_getcurtime(&delta_time);
1019
1020         errno = 0;
1021         if (counter_opt == TFC_CTR_RAND && ctr_mode != TFC_MODE_ECB) {
1022                 pblk = ctr;
1023                 lio = lrem = ctrsz;
1024                 ldone = 0;
1025 _ctrwagain:     lio = xwrite(dfd, pblk, lrem);
1026                 if (lio != NOSIZE) ldone += lio;
1027                 else xerror(NO, NO, NO, "%s", dstfname);
1028                 if (do_fsync && fsync(dfd) == -1) xerror(NO, NO, NO, "%s", dstfname);
1029                 if (lio < lrem) {
1030                         pblk += lio;
1031                         lrem -= lio;
1032                         goto _ctrwagain;
1033                 }
1034                 total_processed_dst += ldone;
1035                 delta_processed += ldone;
1036         }
1037
1038         if (ctr_mode == TFC_MODE_STREAM) tfe_init_iv(&tfe, key, ctr);
1039
1040         errno = 0;
1041         do_stop = NO;
1042         while (1) {
1043                 if (do_stop) break;
1044                 pblk = srcblk;
1045                 ldone = 0;
1046                 lrem = lblock = blk_len_adj(maxlen, total_processed_src, blksize);
1047                 if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(sfd);
1048 _ragain:        lio = xread(sfd, pblk, lrem);
1049                 if (lio == 0) do_stop = TFC_STOP_BEGAN;
1050                 if (lio != NOSIZE) ldone += lio;
1051                 else {
1052                         if (errno != EIO && catch_all_errors != YES)
1053                                 xerror(NO, NO, NO, "%s", srcfname);
1054                         switch (error_action) {
1055                                 case TFC_ERRACT_CONT: xerror(YES, NO, NO, "%s", srcfname); goto _ragain; break;
1056                                 case TFC_ERRACT_SYNC:
1057                                 case TFC_ERRACT_LSYNC:
1058                                         xerror(YES, NO, NO, "%s", srcfname);
1059                                         lio = ldone = lrem = lblock;
1060                                         memset(srcblk, 0, lio);
1061                                         if (rdpos == NOFSIZE) lseek(sfd, lio, SEEK_CUR);
1062                                         else lseek(sfd, rdpos + lio, SEEK_SET);
1063                                         break;
1064                                 default: xerror(NO, NO, NO, "%s", srcfname); break;
1065                         }
1066                 }
1067                 if (lio && lio < lrem) {
1068                         pblk += lio;
1069                         lrem -= lio;
1070                         goto _ragain;
1071                 }
1072                 total_processed_src += ldone;
1073
1074                 if (do_pad && (ldone % TF_BLOCK_SIZE)) {
1075                         size_t orig = ldone;
1076                         ldone += (TF_BLOCK_SIZE - (ldone % TF_BLOCK_SIZE));
1077                         if (ldone > blksize) ldone = blksize;
1078                         memset(srcblk+orig, 0, sizeof(srcblk)-orig);
1079                 }
1080
1081                 if (do_mac == TFC_MAC_SIGN && ctr_mode < TFC_MODE_OCB)
1082                         skein_update(&sk, srcblk, ldone);
1083
1084                 if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, dstblk, srcblk, ldone);
1085                 else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, dstblk, srcblk, ldone);
1086                 else if (ctr_mode == TFC_MODE_XTS && do_edcrypt == TFC_DO_ENCRYPT)
1087                         tf_xts_encrypt(key, xtskey, ctr, dstblk, srcblk, ldone, xtsblocks);
1088                 else if (ctr_mode == TFC_MODE_XTS && do_edcrypt == TFC_DO_DECRYPT)
1089                         tf_xts_decrypt(key, xtskey, ctr, dstblk, srcblk, ldone, xtsblocks);
1090                 else if (ctr_mode == TFC_MODE_ECB && do_edcrypt == TFC_DO_ENCRYPT)
1091                         tf_ecb_encrypt(key, dstblk, srcblk, ldone);
1092                 else if (ctr_mode == TFC_MODE_ECB && do_edcrypt == TFC_DO_DECRYPT)
1093                         tf_ecb_decrypt(key, dstblk, srcblk, ldone);
1094                 else if (ctr_mode == TFC_MODE_CBC && do_edcrypt == TFC_DO_ENCRYPT)
1095                         tf_cbc_encrypt(key, ctr, dstblk, srcblk, ldone);
1096                 else if (ctr_mode == TFC_MODE_CBC && do_edcrypt == TFC_DO_DECRYPT)
1097                         tf_cbc_decrypt(key, ctr, dstblk, srcblk, ldone);
1098
1099                 else if (ctr_mode == TFC_MODE_OCB && do_edcrypt == TFC_DO_ENCRYPT)
1100                         tf_ocb_encrypt(key, ctr, dstblk, do_mac == TFC_MAC_SIGN ? macresult : NULL, srcblk, ldone, xtsblocks);
1101                 else if (ctr_mode == TFC_MODE_OCB && do_edcrypt == TFC_DO_DECRYPT)
1102                         tf_ocb_decrypt(key, ctr, dstblk, do_mac >= TFC_MAC_VRFY ? macresult : NULL, srcblk, ldone, xtsblocks);
1103
1104                 else if (ctr_mode == TFC_MODE_PLAIN)
1105                         memcpy(dstblk, srcblk, ldone);
1106
1107                 if (do_mac >= TFC_MAC_VRFY && ctr_mode < TFC_MODE_OCB)
1108                         skein_update(&sk, dstblk, ldone);
1109                 if (do_mac == TFC_MAC_JUST_VRFY) goto _nowrite;
1110
1111                 pblk = dstblk;
1112                 lrem = ldone;
1113                 ldone = 0;
1114 _wagain:        lio = xwrite(dfd, pblk, lrem);
1115                 if (lio != NOSIZE) ldone += lio;
1116                 else xerror(NO, NO, NO, "%s", dstfname);
1117                 if (do_fsync && fsync(dfd) == -1) xerror(NO, NO, NO, "%s", dstfname);
1118                 if (lio < lrem) {
1119                         pblk += lio;
1120                         lrem -= lio;
1121                         goto _wagain;
1122                 }
1123 _nowrite:       total_processed_dst += ldone;
1124                 delta_processed += ldone;
1125
1126                 if (maxlen != NOFSIZE && total_processed_src >= maxlen) break;
1127         }
1128
1129         if (do_stop == TFC_STOP_FULL) goto _nomac;
1130
1131         errno = 0;
1132         if (do_mac >= TFC_MAC_VRFY) {
1133                 if (!do_mac_file) {
1134                         pblk = macvrfy;
1135                         ldone = 0;
1136                         lrem = lblock = TF_FROM_BITS(macbits);
1137                         if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(sfd);
1138 _macragain:             lio = xread(sfd, pblk, lrem);
1139                         if (lio != NOSIZE) ldone += lio;
1140                         else {
1141                                 if (errno != EIO && catch_all_errors != YES)
1142                                         xerror(NO, NO, NO, "%s", srcfname);
1143                                 switch (error_action) {
1144                                         case TFC_ERRACT_CONT: xerror(YES, NO, NO, "%s", srcfname); goto _macragain; break;
1145                                         case TFC_ERRACT_SYNC:
1146                                         case TFC_ERRACT_LSYNC:
1147                                                 xerror(YES, NO, NO, "%s", srcfname);
1148                                                 lio = ldone = lrem = lblock;
1149                                                 memset(macvrfy, 0, lio);
1150                                                 if (rdpos == NOFSIZE) lseek(sfd, lio, SEEK_CUR);
1151                                                 else lseek(sfd, rdpos + lio, SEEK_SET);
1152                                                 break;
1153                                         default: xerror(NO, NO, NO, "%s", srcfname); break;
1154                                 }
1155                         }
1156                         if (lio && lio < lrem) {
1157                                 pblk += lio;
1158                                 lrem -= lio;
1159                                 goto _macragain;
1160                         }
1161                         total_processed_src += ldone;
1162                 }
1163                 else {
1164                         int mfd;
1165
1166                         if (!strcmp(do_mac_file, "-")) mfd = 0;
1167                         else mfd = open(do_mac_file, O_RDONLY | O_LARGEFILE);
1168                         if (mfd == -1) xerror(YES, NO, NO, "%s", do_mac_file);
1169                         lio = ldone = xread(mfd, tmpdata, sizeof(tmpdata));
1170                         if (lio == NOSIZE) xerror(NO, NO, YES, "%s", do_mac_file);
1171                         if (!memcmp(tmpdata, TFC_ASCII_TFC_MAC_FOURCC, TFC_ASCII_TFC_MAC_FOURCC_LEN)) {
1172                                 memmove(tmpdata, tmpdata+TFC_ASCII_TFC_MAC_FOURCC_LEN,
1173                                         sizeof(tmpdata)-TFC_ASCII_TFC_MAC_FOURCC_LEN);
1174                                 lio = TF_FROM_BITS(macbits);
1175                                 base64_decode((char *)macvrfy, lio, (char *)tmpdata, sizeof(tmpdata));
1176                         }
1177                         else memcpy(macvrfy, tmpdata, TF_FROM_BITS(macbits));
1178                         xclose(mfd);
1179                 }
1180
1181                 if (ldone < TF_FROM_BITS(macbits)) {
1182                         if (quiet == NO) tfc_esay("%s: short signature (%zu), "
1183                                 "not verifying", progname, ldone);
1184                         exitcode = 1;
1185                         goto _shortmac;
1186                 }
1187
1188                 if (ctr_mode < TFC_MODE_OCB) skein_final(macresult, &sk);
1189                 else skein(macresult, macbits, mackey, macresult, TF_FROM_BITS(macbits));
1190
1191                 if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits));
1192                 else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, tmpdata, macvrfy, TF_FROM_BITS(macbits));
1193                 else if (ctr_mode == TFC_MODE_XTS) tf_xts_decrypt(key, xtskey, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits), xtsblocks);
1194                 else if (ctr_mode == TFC_MODE_ECB) tf_ecb_decrypt(key, tmpdata, macvrfy, TF_FROM_BITS(macbits));
1195                 else if (ctr_mode == TFC_MODE_CBC) tf_cbc_decrypt(key, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits));
1196                 else if (ctr_mode == TFC_MODE_OCB) tf_ocb_decrypt(key, ctr, tmpdata, NULL, macvrfy, TF_FROM_BITS(macbits), xtsblocks);
1197
1198                 if (!memcmp(tmpdata, macresult, TF_FROM_BITS(macbits))) {
1199                         if (quiet == NO) {
1200                                 tfc_esay("%s: signature is good", progname);
1201                                 if (verbose) {
1202                                         if (do_outfmt == TFC_OUTFMT_B64) tfc_printbase64(stderr, macresult, TF_FROM_BITS(macbits), YES);
1203                                         else mehexdump(macresult, TF_FROM_BITS(macbits), TF_FROM_BITS(macbits), YES);
1204                                 }
1205                         }
1206                 }
1207                 else {
1208                         if (quiet == NO) tfc_esay("%s: signature is BAD: "
1209                                 "wrong password, key, mode, or file is not signed", progname);
1210                         exitcode = 1;
1211                 }
1212
1213 _shortmac:      memset(macvrfy, 0, sizeof(macvrfy));
1214                 memset(macresult, 0, sizeof(macresult));
1215                 memset(tmpdata, 0, sizeof(tmpdata));
1216         }
1217
1218         else if (do_mac == TFC_MAC_SIGN) {
1219                 if (ctr_mode < TFC_MODE_OCB) skein_final(macresult, &sk);
1220                 else skein(macresult, macbits, mackey, macresult, TF_FROM_BITS(macbits));
1221
1222                 if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, tmpdata, macresult, TF_FROM_BITS(macbits));
1223                 else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, tmpdata, macresult, TF_FROM_BITS(macbits));
1224                 else if (ctr_mode == TFC_MODE_XTS) tf_xts_encrypt(key, xtskey, ctr, tmpdata, macresult, TF_FROM_BITS(macbits), xtsblocks);
1225                 else if (ctr_mode == TFC_MODE_ECB) tf_ecb_encrypt(key, tmpdata, macresult, TF_FROM_BITS(macbits));
1226                 else if (ctr_mode == TFC_MODE_CBC) tf_cbc_encrypt(key, ctr, tmpdata, macresult, TF_FROM_BITS(macbits));
1227                 else if (ctr_mode == TFC_MODE_OCB) tf_ocb_encrypt(key, ctr, tmpdata, NULL, macresult, TF_FROM_BITS(macbits), xtsblocks);
1228                 memset(macresult, 0, sizeof(macresult));
1229
1230                 if (!do_mac_file) {
1231                         pblk = tmpdata;
1232                         lio = lrem = TF_FROM_BITS(macbits);
1233                         ldone = 0;
1234 _macwagain:             lio = xwrite(dfd, pblk, lrem);
1235                         if (lio != NOSIZE) ldone += lio;
1236                         else xerror(NO, NO, NO, "%s", dstfname);
1237                         if (do_fsync && fsync(dfd) == -1) xerror(NO, NO, NO, "%s", dstfname);
1238                         if (lio < lrem) {
1239                                 pblk += lio;
1240                                 lrem -= lio;
1241                                 goto _macwagain;
1242                         }
1243                         total_processed_dst += ldone;
1244                         delta_processed += ldone;
1245                 }
1246                 else {
1247                         int mfd;
1248
1249                         if (!strcmp(do_mac_file, "-")) mfd = 1;
1250                         else mfd = open(do_mac_file, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
1251                         if (mfd == -1) xerror(YES, NO, NO, "%s", do_mac_file);
1252                         if (do_outfmt == TFC_OUTFMT_B64) {
1253                                 memcpy(macvrfy, tmpdata, TF_FROM_BITS(macbits));
1254                                 memset(tmpdata, 0, TFC_TMPSIZE);
1255                                 memcpy(tmpdata, TFC_ASCII_TFC_MAC_FOURCC, TFC_ASCII_TFC_MAC_FOURCC_LEN);
1256                                 base64_encode((char *)tmpdata+TFC_ASCII_TFC_MAC_FOURCC_LEN, (char *)macvrfy, TF_FROM_BITS(macbits));
1257                                 lrem = strnlen((char *)tmpdata, sizeof(tmpdata));
1258                                 if (lrem) {
1259                                         tmpdata[lrem] = '\n';
1260                                         lrem++;
1261                                 }
1262                                 lio = xwrite(mfd, tmpdata, lrem);
1263                         }
1264                         else lio = xwrite(mfd, tmpdata, TF_FROM_BITS(macbits));
1265                         if (lio == NOSIZE) xerror(NO, NO, YES, "%s", do_mac_file);
1266                         if (do_fsync && fsync(mfd) == -1) xerror(NO, NO, YES, "%s", do_mac_file);
1267                         xclose(mfd);
1268                 }
1269
1270                 memset(macvrfy, 0, sizeof(macvrfy));
1271                 memset(macresult, 0, sizeof(macresult));
1272                 memset(tmpdata, 0, sizeof(tmpdata));
1273         }
1274
1275 _nomac:
1276         if (verbose || status_timer || do_stop == TFC_STOP_FULL) print_crypt_status(0);
1277
1278         if (do_preserve_time) fcopy_matime(dfd, &s_stat);
1279         xclose(sfd);
1280         xclose(dfd);
1281
1282         xexit(exitcode);
1283         return -1;
1284 }