tfstream: add separate xor_block function
[tfcrypt.git] / tfc_skein.c
1 /*
2  * tfcrypt -- high security Threefish encryption tool.
3  *
4  * tfcrypt is copyrighted:
5  * Copyright (C) 2012-2019 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 #include "tfcore.h"
31
32 static void exit_sigterm_skein(int signal)
33 {
34         if (xexit_no_nl == YES) xexit_no_nl = NO;
35         exit_sigterm(signal);
36 }
37
38 void skein(void *hash, size_t bits, const void *key, const void *data, size_t szdata)
39 {
40         struct skein sk;
41
42         if (key) skein_init_key(&sk, key, bits);
43         else skein_init(&sk, bits);
44         skein_update(&sk, data, szdata);
45         skein_final(hash, &sk);
46 }
47
48 tfc_yesno skeinfd(void *hash, size_t bits, const void *key, int fd, tfc_fsize offset, tfc_fsize readto)
49 {
50         static tfc_byte skblk[TFC_BLKSIZE];
51
52         struct skein sk;
53         tfc_byte *pblk;
54         size_t ldone, lblock, lrem, lio;
55         tfc_fsize total = 0;
56
57         if (ctr_mode == TFC_MODE_SKSUM) total_processed_src = total_processed_dst = delta_processed = 0;
58
59         if (fd == -1) goto _fail;
60         if (fd > 2) {
61                 if (readto == NOFSIZE) {
62                         readto = tfc_fdsize(fd);
63                         if (readto == NOFSIZE) goto _fail;
64                 }
65                 if (offset != 0 && offset != NOFSIZE) {
66                         if (lseek(fd, (off_t)offset, SEEK_SET) == -1) {
67                                 if (ignore_seek_errors == NO) goto _fail;
68                         }
69                 }
70         }
71
72         if (key) skein_init_key(&sk, key, bits);
73         else skein_init(&sk, bits);
74
75         errno = 0;
76         do_stop = NO;
77         while (1) {
78                 if (do_stop) break;
79                 pblk = skblk;
80                 lblock = lrem = blk_len_adj(readto, total, TFC_BLKSIZE);
81                 ldone = 0;
82                 if (error_action == TFC_ERRACT_SYNC) rdpos = tfc_fdgetpos(fd);
83 _again:         lio = xread(fd, pblk, lrem);
84                 if (lio == 0) do_stop = YES;
85                 if (lio != NOSIZE) ldone += lio;
86                 else {
87                         if (errno != EIO && catch_all_errors != YES) goto _fail;
88                         switch (error_action) {
89                                 case TFC_ERRACT_CONT: xerror(YES, NO, NO, "skeinfd: %d", fd); goto _again; break;
90                                 case TFC_ERRACT_SYNC:
91                                 case TFC_ERRACT_LSYNC:
92                                         xerror(YES, NO, NO, "skeinfd: %d", fd);
93                                         lio = lrem = ldone = lblock;
94                                         total += lio;
95                                         memset(skblk, 0, lio);
96                                         if (rdpos == NOFSIZE) lseek(fd, lio, SEEK_CUR);
97                                         else lseek(fd, rdpos + lio, SEEK_SET);
98                                         break;
99                                 default: goto _fail; break;
100                         }
101                 }
102                 if (lio && lio < lrem) {
103                         pblk += lio;
104                         lrem -= lio;
105                         goto _again;
106                 }
107                 total += ldone;
108                 if (ctr_mode == TFC_MODE_SKSUM) {
109                         total_processed_src = total_processed_dst = total;
110                         delta_processed += ldone;
111                 }
112                 skein_update(&sk, skblk, ldone);
113                 if (readto != NOFSIZE && total >= readto) break;
114         }
115
116         if (fd > 2) lseek(fd, (off_t)readto, SEEK_SET);
117
118         skein_final(hash, &sk);
119         if (ctr_mode == TFC_MODE_SKSUM) {
120                 if (verbose || status_timer) {
121                         print_crypt_status(-1);
122                         tfc_esay("\n");
123                 }
124                 total_processed_src = total_processed_dst = delta_processed = 0;
125         }
126         memset(skblk, 0, TFC_BLKSIZE);
127         return YES;
128
129 _fail:
130         memset(&sk, 0, sizeof(struct skein));
131         memset(hash, 0, SKEIN_DIGEST_SIZE);
132         memset(skblk, 0, TFC_BLKSIZE);
133         return NO;
134 }
135
136 void do_sksum(char *spec, char **fargv)
137 {
138         static char sksblk[TFC_BLKSIZE / 2], tmp[TFC_TMPSIZE];
139         tfc_byte hash[SKEIN_DIGEST_SIZE];
140         int fd = -1;
141         int x = 0, xx;
142         size_t bits;
143
144         xexit_no_nl = YES;
145
146         if (macbits < TF_MAX_BITS) {
147                 bits = macbits;
148                 goto _dothat;
149         }
150
151         if (!strcmp(spec, "sksum")) {
152                 bits = TF_MAX_BITS;
153                 goto _dothat;
154         }
155
156         if ((sscanf(spec, "sk%zusum", &bits) < 1)) {
157                 bits = TF_MAX_BITS;
158         }
159
160         if (bits < 8 || bits > TF_MAX_BITS) {
161                 xerror(NO, YES, YES,
162                 "%u: invalid bits number specified!\n"
163                 "tfcrypt supports from 8 to %u bits, divisible by 8.",
164                 bits, TFC_U(TF_MAX_BITS));
165         }
166
167         if (!bits || bits % 8) {
168                 xerror(NO, YES, YES,
169                 "%u: invalid bits number specified!\n"
170                 "Number of bits must start from 8 and be divisible by 8.",
171                 bits, TFC_U(TF_MAX_BITS));
172         }
173
174 _dothat:
175         do_edcrypt = TFC_DO_PLAIN;
176         ctr_mode = TFC_MODE_SKSUM;
177
178         for (x = 1; x < NSIG; x++) signal(x, SIG_IGN);
179         memset(&sigact, 0, sizeof(sigact));
180         sigact.sa_flags = SA_RESTART;
181         sigact.sa_handler = print_crypt_status;
182         sigaction(SIGUSR1, &sigact, NULL);
183         sigaction(SIGALRM, &sigact, NULL);
184         sigact.sa_handler = change_status_width;
185         sigaction(SIGQUIT, &sigact, NULL);
186         sigact.sa_handler = change_status_timer;
187         sigaction(SIGUSR2, &sigact, NULL);
188         sigact.sa_handler = exit_sigterm_skein;
189         sigaction(SIGINT, &sigact, NULL);
190         sigaction(SIGTERM, &sigact, NULL);
191         sigact.sa_handler = handle_sigtstp;
192         sigaction(SIGTSTP, &sigact, NULL);
193         memset(&sigact, 0, sizeof(struct sigaction));
194
195         tfc_getcurtime(&delta_time);
196
197         if (sksum_hashlist_file) {
198                 FILE *f;
199                 char *s, *d, *t, *shash, *fname;
200                 int failed = 0, totaltested = 0;
201
202                 if (!strcmp(sksum_hashlist_file, "-")) f = stdin;
203                 else f = fopen(sksum_hashlist_file, "r");
204                 if (!f) xerror(NO, NO, YES, "%s", sksum_hashlist_file);
205
206                 while (1) {
207                         memset(sksblk, 0, sizeof(sksblk));
208                         if (xfgets(sksblk, sizeof(sksblk), f) != YES) break;
209
210                         s = d = sksblk; t = NULL;
211                         shash = fname = NULL;
212                         while ((s = strtok_r(d, "\t", &t))) {
213                                 if (d) d = NULL;
214
215                                 if (!shash) shash = s;
216                                 else if (shash && !fname) fname = s;
217                         }
218
219                         if (!shash || !fname) {
220                                 xerror(YES, NO, YES, "invalid string %s", sksblk);
221                                 exitcode = 2;
222                                 continue;
223                         }
224
225                         s = strchr(shash, ' ');
226                         if (s && s[1] == ' ') *s = 0;
227
228                         fd = xxopen(YES, fname, O_RDONLY | O_LARGEFILE);
229                         if (fd == -1) {
230                                 xerror(YES, NO, YES, "%s", fname);
231                                 exitcode = 1;
232                                 continue;
233                         }
234
235                         if (status_timer) setup_next_alarm(status_timer > 1000000 ? 1000000 : status_timer);
236                         if (skeinfd(hash, bits, mackey_opt ? mackey : NULL, fd, iseek, maxlen) != YES) {
237                                 xerror(YES, NO, YES, "%s", fname);
238                                 exitcode = 1;
239                                 continue;
240                         }
241                         xclose(fd);
242                         if (sksum_turns > 1) {
243                                 size_t y;
244                                 for (y = 0; y < sksum_turns; y++)
245                                         skein(hash, bits, mackey_opt ? mackey : NULL, hash, TF_FROM_BITS(bits));
246                         }
247                         if (isbase64(shash)) base64_decode(tmp, sizeof(tmp), shash, strlen(shash));
248                         else hex2bin(tmp, shash);
249
250                         if (!memcmp(hash, tmp, TF_FROM_BITS(bits))) {
251                                 tfc_say("%s: OK", fname);
252                         }
253                         else {
254                                 tfc_say("%s: FAILED", fname);
255                                 failed++;
256                         }
257                         memset(tmp, 0, sizeof(tmp));
258                         memset(sksblk, 0, sizeof(sksblk));
259                         totaltested++;
260                 }
261
262                 fclose(f);
263                 if (failed) {
264                         tfc_esay("%s: WARNING: %u of %u computed checksums did NOT match",
265                                 tfc_format_pid(progname), failed, totaltested);
266                         exitcode = 1;
267                 }
268                 xexit(exitcode);
269         }
270
271         for (xx = 0; fargv[xx]; xx++);
272         if (xx == 0) {
273                 fd = 0;
274                 x = 0;
275                 goto _dohash;
276         }
277
278         for (x = 0; fargv[x] && xx; x++) {
279                 if (!strcmp(fargv[x], "-")) fd = 0;
280                 else fd = xxopen(YES, fargv[x], O_RDONLY | O_LARGEFILE);
281                 if (fd == -1) {
282                         xerror(YES, NO, YES, "%s", fargv[x]);
283                         exitcode = 1;
284                         continue;
285                 }
286
287 _dohash:        if (status_timer) setup_next_alarm(status_timer > 1000000 ? 1000000 : status_timer);
288                 if (skeinfd(hash, bits, mackey_opt ? mackey : NULL, fd, iseek, maxlen) != YES) {
289                         xerror(YES, NO, YES, "%s", fargv[x]);
290                         exitcode = 1;
291                         continue;
292                 }
293                 xclose(fd);
294                 if (sksum_turns > 1) {
295                         size_t y;
296                         for (y = 0; y < sksum_turns; y++) skein(hash, bits, mackey_opt ? mackey : NULL, hash, TF_FROM_BITS(bits));
297                 }
298                 if (do_outfmt == TFC_OUTFMT_B64) tfc_printbase64(stdout, hash, TF_FROM_BITS(bits), 0);
299                 else if (do_outfmt == TFC_OUTFMT_RAW) xwrite(1, hash, TF_FROM_BITS(bits));
300                 else mhexdump(hash, TF_FROM_BITS(bits), TF_FROM_BITS(bits), 0);
301                 if (do_outfmt != TFC_OUTFMT_RAW) {
302                         if (quiet == NO || xx > 1) tfc_say("\t%s", fargv[x] ? fargv[x] : "-");
303                         else tfc_say("\n");
304                 }
305         }
306
307         memset(hash, 0, SKEIN_DIGEST_SIZE);
308         xexit(exitcode);
309 }