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