tfcrypt 1.
authorAndrey Rys <rys@lynxlynx.ru>
Mon, 12 Nov 2018 05:58:34 +0000 (12:58 +0700)
committerAndrey Rys <rys@lynxlynx.ru>
Wed, 14 Nov 2018 16:07:25 +0000 (23:07 +0700)
39 files changed:
.gitignore [new file with mode: 0644]
COPYRIGHT [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
VERSION [new file with mode: 0644]
base64.c [new file with mode: 0644]
base64.h [new file with mode: 0644]
getpasswd.c [new file with mode: 0644]
getpasswd.h [new file with mode: 0644]
mhexdump.c [new file with mode: 0644]
skein.c [new file with mode: 0644]
skein.h [new file with mode: 0644]
tfc_base64.c [new file with mode: 0644]
tfc_bench.c [new file with mode: 0644]
tfc_conv.c [new file with mode: 0644]
tfc_error.c [new file with mode: 0644]
tfc_misc.c [new file with mode: 0644]
tfc_random.c [new file with mode: 0644]
tfc_say.c [new file with mode: 0644]
tfc_signal.c [new file with mode: 0644]
tfc_skein.c [new file with mode: 0644]
tfc_vars.c [new file with mode: 0644]
tfcbc.c [new file with mode: 0644]
tfcore.h [new file with mode: 0644]
tfcrypt.c [new file with mode: 0644]
tfcrypt.h [new file with mode: 0644]
tfctr.c [new file with mode: 0644]
tfctrapi.c [new file with mode: 0644]
tfdec.c [new file with mode: 0644]
tfdef.h [new file with mode: 0644]
tfe.c [new file with mode: 0644]
tfe.h [new file with mode: 0644]
tfecb.c [new file with mode: 0644]
tfenc.c [new file with mode: 0644]
tfocb.c [new file with mode: 0644]
tfprng.c [new file with mode: 0644]
tfprng.h [new file with mode: 0644]
tfstream.c [new file with mode: 0644]
tfxts.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..923d987
--- /dev/null
@@ -0,0 +1,13 @@
+_*
+*.swp
+*.o
+*.out
+*.key
+*.diff
+*.patch
+tags
+tfcrypt
+tfcrypt.upx
+sksum
+tfbench
+tfbase64
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..0f88a50
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,23 @@
+The tfcrypt program is copyrighted:
+
+Copyright © 2012-2018 Andrey Rys.
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..7f6672d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,36 @@
+VERSION:=$(shell cat VERSION)
+override CFLAGS+=-D_TFCRYPT_VERSION=\"$(VERSION)\" -Wall
+UPX=upx
+
+ifneq (,$(DEBUG))
+override CFLAGS+=-O0 -g
+else
+override CFLAGS+=-O3
+endif
+
+ifneq (,$(STATIC))
+override LDFLAGS+=-static
+endif
+
+ifneq (,$(STRIP))
+override LDFLAGS+=-s
+endif
+
+SRCS = $(wildcard *.c)
+HDRS = $(wildcard *.h)
+OBJS = $(SRCS:.c=.o)
+
+all: tfcrypt
+
+%.o: %.c VERSION $(HDRS)
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+tfcrypt: $(OBJS)
+       $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@
+
+tfcrypt.upx: $(OBJS)
+       $(CC) $(CFLAGS) $(LDFLAGS) -static -s $(OBJS) -o $@
+       $(UPX) --best $@
+
+clean:
+       rm -f $(OBJS) tfcrypt tfcrypt.upx
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..f26c346
--- /dev/null
+++ b/README
@@ -0,0 +1,65 @@
+tfcrypt -- high security Threefish encryption tool.
+
+tfcrypt is a modern, dd(1)-like raw data manipulation tool with embedded strong encryption.
+It has precise IO layer inside which can be used to encrypt files, disks and other media,
+as well as to manipulate raw data directly, dd(1) style.
+
+tfcrypt uses Skein and Threefish - public domain SHA3 candidate from famous,
+well recognised cryptographer Bruce Schneier, author of famous, still uncracked
+Blowfish and Twofish ciphers, which are in use still up to today.
+
+tfcrypt is actually a frontend for Threefish with (by default) XTS mode of operation.
+As a key it uses either password or keyfile, which is then hashed many times
+with Skein hash function. Default key length is 1280 bits (160 bytes).
+
+This program is incompatible with older, "tf1024" tfcrypt version. This version aims to
+provide a portable encryption tool to encrypt fixed media such as disks and archive files,
+as well as to provide decades long privacy for encrypted data. That's why it uses 1024 bit
+encryption and, unlike older version, extends key size to 1280 bits, eliminates tweak feature
+from Threefish and uses either XTS (by default) or OCB modes of operation instead,
+to encrypt fixed media in a secure undetectable way.
+
+Supported modes of operation: CTR, ECB, CBC, XTS, OCB and arbitrary long keystream.
+OCB mode does not use Skein hash function to hash and verify message, instead, it does
+a single pass crypt and verify, thus, it is faster than other modes when both crypt and verify.
+
+THREEFISH NOTES
+
+Please note that this encryption software includes Threefish cipher, which is terribly
+slow on 32 bit systems. This way, it cannot be efficiently used on pure 32 bit machines.
+
+Threefish contained here is stripped off of it's tweak property, thus, it is turned into a
+regular block cipher. To add tweakability, either XTS or OCB modes of operation are used.
+Default wide block size is 4096 bytes. Author strongly believes that Threefish _may_ be subject
+to related key attacks when used in a tweaked mode, so this property is easy to remove.
+Because tweak occupied another 192 bits of key material, these 192 bits are added to effective
+key length. Another key word is extracted from the sum of all the user key words, thus,
+another 64 bits. Total +256 additional bits of key = 1280 key bits.
+
+SKEIN NOTES
+
+Unlike "tf1024" implementation, this Skein's MAC feature simply copies user rawkey into
+Skein structure context without preprocessing as defined by official Skein implementation.
+If you never used MAC feature, then you will get the same hashes as the official Skein.
+If you did, then possibly you used it together with encryption. Since this implementation
+employs longer key lengths, it's anyway time to move.
+
+Author believes that there is no problem with just copying raw MAC key versus preprocessing.
+A preprocessing is already done by separate Skein sequential invocations on the user long
+key material. The code becomes simpler and easier to understand.
+
+Apart from that, the Skein implementation here is fully conformant to the official one.
+
+TODO
+
+Add test vectors from older version, as well as test data for all modes of operation there.
+
+LICENSE
+
+This tfcrypt, unlike it's previous version, is copyrighted:
+
+       Copyright (C) Andrey Rys <rys@lynxlynx.ru>, 2012-2018.
+
+It maybe freely used by anyone who agrees to the terms and conditions of the MIT license.
+
+tfcipher code parts used are public domain, and maybe reused freely without license.
diff --git a/VERSION b/VERSION
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+1
diff --git a/base64.c b/base64.c
new file mode 100644 (file)
index 0000000..07df7ac
--- /dev/null
+++ b/base64.c
@@ -0,0 +1,247 @@
+/*
+ * base64.c: libb64 compressed code. Public domain.
+ * See http://libb64.sourceforge.net/ for original code and infos.
+ *
+ * Modified and fixed by Lynx <lynx@lynxlynx.ru> 03Jun2016:
+ * - Single TU, minimal external dependencies
+ * - Stream operation, no newline insertions
+ * - Fixed code style to pure K&R
+ * - Fixed integer overflows and fixed size types
+ * - Fixed out of bounds access in base64_decode_block 
+ * - Force specify output size for output buffer when decoding
+ * - Fixed signed/unsigned issue on ARM
+ * - Added generic memory converter wrappers which do not expose internals
+ * - All functions calculate number of processed characters and return them to caller
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+enum base64_decodestep {
+       estep_a, estep_b, estep_c, estep_d
+};
+
+struct base64_decodestate {
+       enum base64_decodestep step;
+       char plainchar;
+       size_t count;
+};
+
+enum base64_encodestep {
+       dstep_a, dstep_b, dstep_c
+};
+
+struct base64_encodestate {
+       enum base64_encodestep step;
+       char result;
+       size_t count;
+};
+
+int base64_decode_value(signed char value_in)
+{
+       static const signed char decoding[] = {
+               62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1,
+               -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+               21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+               35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+       };
+       static const char decoding_size = sizeof(decoding);
+       if (value_in < 43) return -1;
+       value_in -= 43;
+       if (value_in >= decoding_size) return -1;
+       return decoding[(int)value_in];
+}
+
+void base64_init_decodestate(struct base64_decodestate *state_in)
+{
+       state_in->step = estep_a;
+       state_in->plainchar = 0;
+       state_in->count = 0;
+}
+
+#define CHECK_BOUNDS do { if (plainchar-plaintext_out >= plaintext_outl) goto _ret; } while (0)
+
+size_t base64_decode_block(const char *code_in, size_t length_in, char *plaintext_out, size_t plaintext_outl, struct base64_decodestate *state_in)
+{
+       const char *codechar = code_in;
+       char *plainchar = plaintext_out;
+       int fragment;
+       
+       *plainchar = state_in->plainchar;
+       
+       switch (state_in->step) {
+               while (1) {
+                       case estep_a:
+                                       do {
+                                               if (codechar == code_in+length_in) {
+                                                       state_in->step = estep_a;
+                                                       state_in->plainchar = *plainchar;
+                                                       state_in->count += (plainchar - plaintext_out);
+                                                       return plainchar - plaintext_out;
+                                               }
+                                               fragment = base64_decode_value(*codechar++);
+                                       } while (fragment < 0);
+                                       *plainchar = (fragment & 0x3f) << 2;
+                       case estep_b:
+                                       do {
+                                               if (codechar == code_in+length_in) {
+                                                       state_in->step = estep_b;
+                                                       state_in->plainchar = *plainchar;
+                                                       state_in->count += (plainchar - plaintext_out);
+                                                       return plainchar - plaintext_out;
+                                               }
+                                               fragment = base64_decode_value(*codechar++);
+                                       } while (fragment < 0);
+                                       *plainchar++ |= (fragment & 0x30) >> 4;
+                                       CHECK_BOUNDS;
+                                       *plainchar = (fragment & 0x0f) << 4;
+                       case estep_c:
+                                       do {
+                                               if (codechar == code_in+length_in) {
+                                                       state_in->step = estep_c;
+                                                       state_in->plainchar = *plainchar;
+                                                       state_in->count += (plainchar - plaintext_out);
+                                                       return plainchar - plaintext_out;
+                                               }
+                                               fragment = base64_decode_value(*codechar++);
+                                       } while (fragment < 0);
+                                       *plainchar++ |= (fragment & 0x3c) >> 2;
+                                       CHECK_BOUNDS;
+                                       *plainchar = (fragment & 0x03) << 6;
+                       case estep_d:
+                                       do {
+                                               if (codechar == code_in+length_in) {
+                                                       state_in->step = estep_d;
+                                                       state_in->plainchar = *plainchar;
+                                                       state_in->count += (plainchar - plaintext_out);
+                                                       return plainchar - plaintext_out;
+                                               }
+                                               fragment = base64_decode_value(*codechar++);
+                                       } while (fragment < 0);
+                                       *plainchar++ |= (fragment & 0x3f);
+               }
+       }
+
+_ret:  state_in->count += (plainchar - plaintext_out);
+       return plainchar - plaintext_out;
+}
+
+void base64_init_encodestate(struct base64_encodestate *state_in)
+{
+       state_in->step = dstep_a;
+       state_in->result = 0;
+       state_in->count = 0;
+}
+
+char base64_encode_value(char value_in)
+{
+       static const char *encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+       if (value_in > 63) return '=';
+       return encoding[(int)value_in];
+}
+
+size_t base64_encode_block(const char *plaintext_in, size_t length_in, char *code_out, struct base64_encodestate *state_in)
+{
+       const char *plainchar = plaintext_in;
+       const char *const plaintextend = plaintext_in + length_in;
+       char *codechar = code_out;
+       char result;
+       char fragment;
+       
+       result = state_in->result;
+       
+       switch (state_in->step) {
+               while (1) {
+                       case dstep_a:
+                                       if (plainchar == plaintextend) {
+                                               state_in->result = result;
+                                               state_in->step = dstep_a;
+                                               state_in->count += (codechar - code_out);
+                                               return codechar - code_out;
+                                       }
+                                       fragment = *plainchar++;
+                                       result = (fragment & 0xfc) >> 2;
+                                       *codechar++ = base64_encode_value(result);
+                                       result = (fragment & 0x03) << 4;
+                       case dstep_b:
+                                       if (plainchar == plaintextend) {
+                                               state_in->result = result;
+                                               state_in->step = dstep_b;
+                                               state_in->count += (codechar - code_out);
+                                               return codechar - code_out;
+                                       }
+                                       fragment = *plainchar++;
+                                       result |= (fragment & 0xf0) >> 4;
+                                       *codechar++ = base64_encode_value(result);
+                                       result = (fragment & 0x0f) << 2;
+                       case dstep_c:
+                                       if (plainchar == plaintextend) {
+                                               state_in->result = result;
+                                               state_in->step = dstep_c;
+                                               state_in->count += (codechar - code_out);
+                                               return codechar - code_out;
+                                       }
+                                       fragment = *plainchar++;
+                                       result |= (fragment & 0xc0) >> 6;
+                                       *codechar++ = base64_encode_value(result);
+                                       result  = (fragment & 0x3f) >> 0;
+                                       *codechar++ = base64_encode_value(result);
+               }
+       }
+       /* control should not reach here */
+       state_in->count += (codechar - code_out);
+       return codechar - code_out;
+}
+
+size_t base64_encode_blockend(char *code_out, struct base64_encodestate *state_in)
+{
+       char *codechar = code_out + state_in->count;
+       
+       switch (state_in->step) {
+               case dstep_b:
+                       *codechar++ = base64_encode_value(state_in->result);
+                       *codechar++ = '=';
+                       *codechar++ = '=';
+                       state_in->count += 3;
+                       break;
+               case dstep_c:
+                       *codechar++ = base64_encode_value(state_in->result);
+                       *codechar++ = '=';
+                       state_in->count += 2;
+                       break;
+               case dstep_a:
+                       break;
+       }
+
+       return codechar - code_out;
+}
+
+/* Process single block of memory */
+size_t base64_decode(char *output, size_t outputl, const char *input, size_t inputl)
+{
+       struct base64_decodestate dstate;
+       size_t r;
+
+       base64_init_decodestate(&dstate);
+       base64_decode_block(input, inputl, output, outputl, &dstate);
+
+       r = dstate.count;
+       memset(&dstate, 0, sizeof(struct base64_decodestate));
+
+       return r;
+}
+
+size_t base64_encode(char *output, const char *input, size_t inputl)
+{
+       struct base64_encodestate estate;
+       size_t r;
+
+       base64_init_encodestate(&estate);
+       base64_encode_block(input, inputl, output, &estate);
+       base64_encode_blockend(output, &estate);
+
+       r = estate.count;
+       memset(&estate, 0, sizeof(struct base64_encodestate));
+
+       return r;
+}
diff --git a/base64.h b/base64.h
new file mode 100644 (file)
index 0000000..a4a441e
--- /dev/null
+++ b/base64.h
@@ -0,0 +1,35 @@
+#ifndef _BASE64_H
+#define _BASE64_H
+
+enum base64_decodestep {
+       estep_a, estep_b, estep_c, estep_d
+};
+
+struct base64_decodestate {
+       enum base64_decodestep step;
+       char plainchar;
+       size_t count;
+};
+
+enum base64_encodestep {
+       dstep_a, dstep_b, dstep_c
+};
+
+struct base64_encodestate {
+       enum base64_encodestep step;
+       char result;
+       size_t count;
+};
+
+int base64_decode_value(signed char value_in);
+void base64_init_decodestate(struct base64_decodestate *state_in);
+size_t base64_decode_block(const char *code_in, size_t length_in, char *plaintext_out, size_t plaintext_outl, struct base64_decodestate *state_in);
+void base64_init_encodestate(struct base64_encodestate *state_in);
+char base64_encode_value(char value_in);
+size_t base64_encode_block(const char *plaintext_in, size_t length_in, char *code_out, struct base64_encodestate *state_in);
+size_t base64_encode_blockend(char *code_out, struct base64_encodestate *state_in);
+
+size_t base64_decode(char *output, size_t outputl, const char *input, size_t inputl);
+size_t base64_encode(char *output, const char *input, size_t inputl);
+
+#endif
diff --git a/getpasswd.c b/getpasswd.c
new file mode 100644 (file)
index 0000000..633b3fd
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "getpasswd.h"
+
+size_t xgetpasswd(struct getpasswd_state *getps)
+{
+       char c;
+       int tty_opened = 0, x;
+       int clear;
+       struct termios s, t;
+       size_t l, echolen = 0;
+
+       if (!getps) return ((size_t)-1);
+
+       /*
+        * Both stdin and stderr point to same fd. This cannot happen.
+        * This only means that getps was memzero'd.
+        * Do not blame user for that, just fix it.
+        */
+       if ((getps->fd == 0 && getps->efd == 0) || getps->efd == -1) getps->efd = 2;
+
+       if (getps->fd == -1) {
+               if ((getps->fd = open("/dev/tty", O_RDONLY|O_NOCTTY)) == -1) getps->fd = 0;
+               else tty_opened = 1;
+       }
+
+       memset(&t, 0, sizeof(struct termios));
+       memset(&s, 0, sizeof(struct termios));
+       if (tcgetattr(getps->fd, &t) == -1) {
+               getps->error = errno;
+               return ((size_t)-1);
+       }
+       s = t;
+       if (getps->sanetty) memcpy(getps->sanetty, &s, sizeof(struct termios));
+       cfmakeraw(&t);
+       t.c_iflag |= ICRNL;
+       if (tcsetattr(getps->fd, TCSANOW, &t) == -1) {
+               getps->error = errno;
+               return ((size_t)-1);
+       }
+
+       if (getps->echo) {
+               echolen = strlen(getps->echo);
+               if (write(getps->efd, getps->echo, echolen) == -1) {
+                       getps->error = errno;
+                       l = ((size_t)-1);
+                       goto _xerr;
+               }
+       }
+
+       l = 0; x = 0;
+       memset(getps->passwd, 0, getps->pwlen);
+       while (1) {
+               clear = 1;
+               if (read(getps->fd, &c, sizeof(char)) == -1) {
+                       getps->error = errno;
+                       l = ((size_t)-1);
+                       goto _xerr;
+               }
+               if (getps->charfilter) {
+                       x = getps->charfilter(getps, c, l);
+                       if (x == 0) {
+                               clear = 0;
+                               goto _newl;
+                       }
+                       else if (x == 2) continue;
+                       else if (x == 3) goto _erase;
+                       else if (x == 4) goto _delete;
+                       else if (x == 5) break;
+                       else if (x == 6) {
+                               clear = 0;
+                               l = getps->retn;
+                               memset(getps->passwd, 0, getps->pwlen);
+                               goto _err;
+                       }
+               }
+               if (l >= getps->pwlen && (getps->flags & GETP_WAITFILL)) clear = 0;
+
+               if (c == '\x7f'
+               || (c == '\x08' && !(getps->flags & GETP_NOINTERP))) { /* Backspace / ^H */
+_erase:                        if (l == 0) continue;
+                       clear = 0;
+                       l--;
+                       if (!(getps->flags & GETP_NOECHO)) {
+                               if (write(getps->efd, "\x08\033[1X", sizeof("\x08\033[1X")-1) == -1) {
+                                       getps->error = errno;
+                                       l = ((size_t)-1);
+                                       goto _xerr;
+                               }
+                       }
+               }
+               else if (!(getps->flags & GETP_NOINTERP)
+               && (c == '\x15' || c == '\x17')) { /* ^U / ^W */
+_delete:               clear = 0;
+                       l = 0;
+                       memset(getps->passwd, 0, getps->pwlen);
+                       if (write(getps->efd, "\033[2K\033[0G", sizeof("\033[2K\033[0G")-1) == -1) {
+                               getps->error = errno;
+                               l = ((size_t)-1);
+                               goto _xerr;
+                       }
+                       if (getps->echo) {
+                               if (write(getps->efd, getps->echo, echolen) == -1) {
+                                       getps->error = errno;
+                                       l = ((size_t)-1);
+                                       goto _xerr;
+                               }
+                       }
+               }
+_newl:         if (c == '\n'
+               || c == '\r'
+               || (!(getps->flags & GETP_NOINTERP) && c == '\x04')) break;
+               if (clear) {
+                       *(getps->passwd+l) = c;
+                       l++;
+                       if (!(getps->flags & GETP_NOECHO)) {
+                               if (getps->maskchar &&
+                                       write(getps->efd, &getps->maskchar,
+                                       sizeof(char)) == -1) {
+                                               getps->error = errno;
+                                               l = ((size_t)-1);
+                                               goto _xerr;
+                               }
+                       }
+               }
+               if (l >= getps->pwlen && !(getps->flags & GETP_WAITFILL)) break;
+       };
+
+_err:  if (write(getps->efd, "\r\n", sizeof("\r\n")-1) == -1) {
+               getps->error = errno;
+               l = ((size_t)-1);
+       }
+       if (x != 6) *(getps->passwd+l) = 0;
+
+_xerr: if (tcsetattr(getps->fd, TCSANOW, &s) == -1) {
+               if (getps->error == 0) {
+                       getps->error = errno;
+                       l = ((size_t)-1);
+               }
+       }
+
+       if (tty_opened) close(getps->fd);
+
+       return l;
+}
diff --git a/getpasswd.h b/getpasswd.h
new file mode 100644 (file)
index 0000000..a6dbd56
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _GETPASSWD_H
+#define _GETPASSWD_H
+
+#define GETP_NOECHO 1
+#define GETP_NOINTERP 2
+#define GETP_WAITFILL 4
+
+struct getpasswd_state;
+struct termios;
+
+typedef int (*getpasswd_filt)(struct getpasswd_state *, char, size_t);
+
+struct getpasswd_state {
+       char *passwd;
+       size_t pwlen;
+       const char *echo;
+       char maskchar;
+       getpasswd_filt charfilter;
+       int fd;
+       int efd;
+       int error;
+       struct termios *sanetty;
+       int flags;
+       size_t retn;
+};
+
+size_t xgetpasswd(struct getpasswd_state *getps);
+
+#endif
diff --git a/mhexdump.c b/mhexdump.c
new file mode 100644 (file)
index 0000000..5d927f7
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdint.h>
+
+struct mhexdump_args {
+       const void *data;
+       size_t szdata;
+       int group;
+       int hexgroup;
+       int hexstr;
+       int addaddr;
+       int newline;
+       FILE *fp;
+       int closef;
+};
+
+#if SIZE_MAX == 0xffffffff
+#define ADDRFMT "%08x: "
+#define paddr (mha->addaddr == 2 ? (uint32_t)P+(x*mha->group) : (x*mha->group))
+#else
+#define ADDRFMT "%016lx: "
+#define paddr (mha->addaddr == 2 ? (uint64_t)P+(x*mha->group) : (x*mha->group))
+#endif
+
+#define BYTEOUT ((unsigned char)P[y+(x*mha->group)])
+
+int fmhexdump(const struct mhexdump_args *mha)
+{
+       const unsigned char *P = mha->data;
+       int x, y;
+
+       if (!mha->fp || !mha->data || mha->szdata == 0) return 0;
+
+       for (x = 0; x < mha->szdata/mha->group; x++) {
+               if (mha->addaddr) fprintf(mha->fp, ADDRFMT, paddr);
+               for (y = 0; y < mha->group; y++) {
+                       fprintf(mha->fp, "%02hhx", BYTEOUT);
+                       if (((y+1) % mha->hexgroup) == 0 && (y != (mha->group)-1)) fputc(' ', mha->fp);
+               }
+               if (mha->hexstr) fprintf(mha->fp, "  ");
+               if (mha->hexstr) for (y = 0; y < mha->group; y++) {
+                       if (isprint(BYTEOUT)) fprintf(mha->fp, "%c", BYTEOUT);
+                       else fputc('.', mha->fp);
+               }
+               if (mha->szdata/mha->group == 1 && mha->szdata-mha->group == 0) {
+                       if (mha->newline) fputc('\n', mha->fp);
+               }
+               else fputc('\n', mha->fp);
+       }
+       if (mha->szdata-(x*mha->group) == 0) goto _ret;
+
+       if (mha->addaddr) fprintf(mha->fp, ADDRFMT, paddr);
+       for (y = 0; y < mha->szdata-(x*mha->group); y++) {
+               fprintf(mha->fp, "%02hhx", BYTEOUT);
+               if (((y+1) % mha->hexgroup) == 0) fputc(' ', mha->fp);
+       }
+       if (mha->hexstr) for (; y < mha->group; y++) {
+               fprintf(mha->fp, "  ");
+               if (((y+1) % mha->hexgroup) == 0 && (y != mha->group-1)) fputc(' ', mha->fp);
+       }
+       if (mha->hexstr) fprintf(mha->fp, "  ");
+       if (mha->hexstr) for (y = 0; y < mha->szdata-(x*mha->group); y++) {
+               if (isprint(BYTEOUT)) fprintf(mha->fp, "%c", BYTEOUT);
+               else fputc('.', mha->fp);
+       }
+
+       if (mha->newline) fputc('\n', mha->fp);
+
+_ret:  fflush(mha->fp);
+       if (mha->closef) fclose(mha->fp);
+       return 1;
+}
+
+#undef BYTEOUT
+
+int xmhexdump(int to, const void *data, size_t szdata, int hgroup, int hexstr, int newline)
+{
+       struct mhexdump_args mha;
+
+       if (hgroup == 0) hgroup = 16;
+
+       memset(&mha, 0, sizeof(struct mhexdump_args));
+       mha.fp = (to == 2) ? stderr : stdout;
+       mha.closef = 0;
+       mha.data = data;
+       mha.szdata = szdata;
+       mha.group = hgroup;
+       mha.hexgroup = hgroup;
+       mha.hexstr = hexstr;
+       mha.addaddr = 0;
+       mha.newline = newline;
+
+       return fmhexdump(&mha);
+}
diff --git a/skein.c b/skein.c
new file mode 100644 (file)
index 0000000..b1da775
--- /dev/null
+++ b/skein.c
@@ -0,0 +1,131 @@
+#include <string.h>
+#include "tfdef.h"
+#include "tfcore.h"
+#include "skein.h"
+
+static inline void puthash(TF_BYTE_TYPE *dst, const TF_UNIT_TYPE *src, size_t l)
+{
+       size_t n;
+       for (n = 0; n < l; n++) dst[n] = (TF_BYTE_TYPE)(src[n>>3] >> (TF_SIZE_UNIT*(n&7)));
+}
+
+static void skein_process_blk(struct skein *sk, const TF_BYTE_TYPE *in, size_t szin, size_t l)
+{
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS];
+       size_t i;
+
+       do {
+               sk->key[TF_TWEAK_WORD1] += l;
+
+               memcpy(x, in, TF_BLOCK_SIZE);
+               data_to_words(x, TF_BLOCK_SIZE);
+               in += TF_BLOCK_SIZE;
+
+               sk->key[TF_NR_KEY_UNITS-1-3] = THREEFISH_CONST;
+               for (i = 0; i < TF_NR_KEY_UNITS-1-3; i++)
+                       sk->key[TF_NR_KEY_UNITS-1-3] ^= sk->key[i];
+               sk->key[TF_TWEAK_WORD3] = sk->key[TF_TWEAK_WORD1] ^ sk->key[TF_TWEAK_WORD2];
+
+               tf_encrypt_rawblk(y, x, sk->key);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) sk->key[i] = y[i] ^ x[i];
+
+               sk->key[TF_TWEAK_WORD2] &= ~SKEIN_FLAG_FIRST;
+       } while (--szin);
+}
+
+void skein_init_key(struct skein *sk, const void *ukey, size_t bits)
+{
+       TF_UNIT_TYPE cfg[TF_NR_BLOCK_UNITS];
+
+       memset(sk, 0, sizeof(struct skein));
+
+       if (ukey) {
+               memcpy(sk->key, ukey, TF_FROM_BITS(TF_MAX_BITS));
+               data_to_words(sk->key, TF_FROM_BITS(TF_MAX_BITS));
+       }
+
+       sk->bits = bits;
+       sk->carry_bytes = 0;
+
+       memset(cfg, 0, sizeof(cfg));
+       cfg[0] = TF_SWAP_FUNC(((TF_UNIT_TYPE)SKEIN_VERSION << 32) + (TF_UNIT_TYPE)SKEIN_ID);
+       cfg[1] = TF_SWAP_FUNC(bits);
+
+       sk->key[TF_TWEAK_WORD1] = 0;
+       sk->key[TF_TWEAK_WORD2] = SKEIN_BLOCK_CFG | SKEIN_FLAG_FIRST | SKEIN_FLAG_LAST;
+
+       skein_process_blk(sk, (TF_BYTE_TYPE *)cfg, 1, 32);
+
+       sk->key[TF_TWEAK_WORD1] = 0;
+       sk->key[TF_TWEAK_WORD2] = SKEIN_BLOCK_MSG | SKEIN_FLAG_FIRST;
+}
+
+void skein_init(struct skein *sk, size_t bits)
+{
+       skein_init_key(sk, NULL, bits);
+}
+
+void skein_update(struct skein *sk, const void *msg, size_t msgsz)
+{
+       const TF_BYTE_TYPE *umsg = msg;
+       size_t n;
+
+       if (msgsz + sk->carry_bytes > TF_BLOCK_SIZE) {
+               if (sk->carry_bytes) {
+                       n = TF_BLOCK_SIZE - sk->carry_bytes;
+                       if (n) {
+                               memcpy(&sk->carry_block[sk->carry_bytes], umsg, n);
+                               msgsz -= n;
+                               umsg += n;
+                               sk->carry_bytes += n;
+                       }
+                       skein_process_blk(sk, sk->carry_block, 1, TF_BLOCK_SIZE);
+                       sk->carry_bytes = 0;
+               }
+
+               if (msgsz > TF_BLOCK_SIZE) {
+                       n = (msgsz-1) / TF_BLOCK_SIZE;
+                       skein_process_blk(sk, umsg, n, TF_BLOCK_SIZE);
+                       msgsz -= n * TF_BLOCK_SIZE;
+                       umsg += n * TF_BLOCK_SIZE;
+               }
+       }
+
+       if (msgsz) {
+               memcpy(&sk->carry_block[sk->carry_bytes], umsg, msgsz);
+               sk->carry_bytes += msgsz;
+       }
+}
+
+void skein_final(void *result, struct skein *sk)
+{
+       TF_BYTE_TYPE *uresult = result;
+       TF_UNIT_TYPE key[TF_NR_BLOCK_UNITS], *X;
+       size_t i, b, n;
+
+       if (sk->carry_bytes < TF_BLOCK_SIZE)
+               memset(sk->carry_block+sk->carry_bytes, 0, TF_BLOCK_SIZE-sk->carry_bytes);
+       sk->key[TF_TWEAK_WORD2] |= SKEIN_FLAG_LAST;
+       skein_process_blk(sk, sk->carry_block, 1, sk->carry_bytes);
+
+       b = (sk->bits + 7) / 8;
+
+       memset(sk->carry_block, 0, sizeof(sk->carry_block));
+       memcpy(key, sk->key, sizeof(key));
+
+       for (i = 0; (i * TF_BLOCK_SIZE) < b; i++) {
+               X = (TF_UNIT_TYPE *)sk->carry_block;
+               X[0] = TF_SWAP_FUNC((TF_UNIT_TYPE)i);
+               sk->key[TF_TWEAK_WORD1] = 0;
+               sk->key[TF_TWEAK_WORD2] = SKEIN_BLOCK_OUT | SKEIN_FLAG_FIRST | SKEIN_FLAG_LAST;
+               sk->carry_bytes = 0;
+
+               skein_process_blk(sk, sk->carry_block, 1, TF_SIZE_UNIT);
+               n = b-(i*TF_BLOCK_SIZE);
+               if (n >= TF_BLOCK_SIZE) n = TF_BLOCK_SIZE;
+               puthash(uresult+(i*TF_BLOCK_SIZE), sk->key, n);
+               memcpy(sk->key, key, TF_BLOCK_SIZE);
+       }
+
+       memset(sk, 0, sizeof(struct skein));
+}
diff --git a/skein.h b/skein.h
new file mode 100644 (file)
index 0000000..f36769b
--- /dev/null
+++ b/skein.h
@@ -0,0 +1,29 @@
+#ifndef _THREEFISH_SKEIN_DEFINITIONS_HEADER
+#define _THREEFISH_SKEIN_DEFINITIONS_HEADER
+
+#include "tfdef.h"
+
+#define SKEIN_VERSION 1
+#define SKEIN_ID 0x33414853
+
+#define SKEIN_BLOCK_CFG ((TF_UNIT_TYPE)4 << 56)
+#define SKEIN_BLOCK_MSG ((TF_UNIT_TYPE)48 << 56)
+#define SKEIN_BLOCK_OUT ((TF_UNIT_TYPE)63 << 56)
+#define SKEIN_FLAG_FIRST ((TF_UNIT_TYPE)1 << 62)
+#define SKEIN_FLAG_LAST ((TF_UNIT_TYPE)1 << 63)
+
+#define SKEIN_DIGEST_SIZE TF_BLOCK_SIZE
+
+struct skein {
+       TF_UNIT_TYPE key[TF_NR_KEY_UNITS];
+       TF_BYTE_TYPE carry_block[TF_BLOCK_SIZE];
+       size_t carry_bytes;
+       size_t bits;
+};
+
+void skein_init_key(struct skein *sk, const void *ukey, size_t bits);
+void skein_init(struct skein *sk, size_t bits);
+void skein_update(struct skein *sk, const void *msg, size_t msgsz);
+void skein_final(void *result, struct skein *sk);
+
+#endif
diff --git a/tfc_base64.c b/tfc_base64.c
new file mode 100644 (file)
index 0000000..b92ac96
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+void do_edbase64(char **fargv)
+{
+       struct base64_decodestate dstate;
+       struct base64_encodestate estate;
+       size_t lread = 0;
+
+       sfd = 0; dfd = 1;
+
+       if (fargv[0]) {
+               if (!strcmp(fargv[0], "-")) sfd = 0;
+               else {
+                       sfd = open(fargv[0], O_RDONLY | O_LARGEFILE);
+                       if (do_preserve_time) if (fstat(sfd, &s_stat) == -1)
+                               xerror(YES, NO, YES, "stat(%s)", fargv[0]);
+               }
+               if (sfd == -1) xerror(NO, NO, YES, "%s", fargv[0]);
+       }
+
+       if (fargv[0] && fargv[1]) {
+               if (!strcmp(fargv[1], "-")) dfd = 1;
+               else dfd = open(fargv[1], O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
+               if (dfd == -1) xerror(NO, NO, YES, "%s", fargv[1]);
+       }
+
+       if (do_edcrypt == TFC_DO_ENCRYPT) {
+               memset(&estate, 0, sizeof(struct base64_encodestate));
+               base64_init_encodestate(&estate);
+       }
+       else if (do_edcrypt == TFC_DO_DECRYPT) {
+               memset(&dstate, 0, sizeof(struct base64_decodestate));
+               base64_init_decodestate(&dstate);
+       }
+
+       errno = 0;
+       do_stop = NO;
+       while (1) {
+               if (do_stop) break;
+               pblk = srcblk;
+               lblock = lrem = do_edcrypt == TFC_DO_DECRYPT ? TFC_B64_DWIDTH : TFC_B64_EWIDTH;
+               ldone = 0;
+_again:                lio = read(sfd, pblk, lrem);
+               if (lio == 0) do_stop = YES;
+               if (lio != NOSIZE) ldone += lio;
+               else {
+                       if (errno != EIO && catch_all_errors != YES)
+                               xerror(NO, NO, NO, "%s", fargv[0]);
+                       switch (error_action) {
+                               case TFC_ERRACT_CONT: xerror(YES, NO, NO, "%s", fargv[0]); goto _again; break;
+                               case TFC_ERRACT_SYNC:
+                                       xerror(YES, NO, NO, "%s", fargv[0]);
+                                       lio = ldone = lrem = lblock;
+                                       memset(srcblk, 0, lio);
+                                       lseek(sfd, lio, SEEK_CUR);
+                                       break;
+                               default: xerror(NO, NO, NO, "%s", fargv[0]); break;
+                       }
+               }
+               if (lio && lio < lrem) {
+                       pblk += lio;
+                       lrem -= lio;
+                       goto _again;
+               }
+
+               if (do_edcrypt == TFC_DO_ENCRYPT) {
+                       estate.count = 0;
+                       base64_encode_block((const char *)srcblk, ldone, (char *)dstblk, &estate);
+                       lread = ldone;
+                       ldone = estate.count;
+               }
+               else if (do_edcrypt == TFC_DO_DECRYPT) {
+                       dstate.count = 0;
+                       base64_decode_block((const char *)srcblk, ldone, (char *)dstblk, sizeof(dstblk), &dstate);
+                       ldone = dstate.count;
+               }
+
+               pblk = dstblk;
+               if (ldone == 0) {
+                       do_stop = TFC_STOP_FULL;
+                       break;
+               }
+               lrem = ldone;
+               ldone = 0;
+_wagain:       lio = write(dfd, pblk, lrem);
+               if (lio != NOSIZE) ldone += lio;
+               else xerror(NO, NO, NO, "%s", fargv[1]);
+               if (do_edcrypt == TFC_DO_ENCRYPT) {
+                       size_t t;
+                       if (lread >= lblock || do_stop == TFC_STOP_FULL) {
+                               t = write(dfd, "\n", 1);
+                               if (t != NOSIZE) lio += t;
+                               else lio = NOSIZE;
+                       }
+               }
+               if (lio != NOSIZE) ldone += lio;
+               else xerror(NO, NO, NO, "%s", fargv[1]);
+               if (do_fsync && fsync(dfd) == -1) xerror(NO, NO, NO, "%s", fargv[1]);
+               if (lio < lrem) {
+                       pblk += lio;
+                       lrem -= lio;
+                       goto _wagain;
+               }
+       }
+
+       if (do_edcrypt == TFC_DO_ENCRYPT && do_stop == TFC_STOP_BEGAN) {
+               size_t t = estate.count;
+               pblk = dstblk + estate.count;
+               base64_encode_blockend((char *)dstblk, &estate);
+               lrem = estate.count - t;
+               ldone = 0;
+               do_stop = TFC_STOP_FULL;
+               goto _wagain;
+       }
+
+       memset(&estate, 0, sizeof(struct base64_encodestate));
+       memset(&dstate, 0, sizeof(struct base64_decodestate));
+       if (do_preserve_time) fcopy_matime(dfd, &s_stat);
+       xexit(0);
+}
+
+static void base64_eprint(FILE *where, struct base64_encodestate *estate, const char *input, size_t inputl)
+{
+       static char t[256];
+       ssize_t ix = inputl;
+
+       while (ix > 0) {
+               memset(t, 0, sizeof(t));
+               estate->count = 0;
+               base64_encode_block(input, ix > 128 ? 128 : ix, t, estate);
+               ix -= 128;
+               if (ix < 128) base64_encode_blockend(t, estate);
+               fprintf(where, "%s", t);
+               fflush(where);
+       }
+
+       memset(t, 0, sizeof(t));
+}
+
+void tfc_printbase64(FILE *where, const void *p, size_t n, tfc_yesno nl)
+{
+       struct base64_encodestate estate;
+       memset(&estate, 0, sizeof(struct base64_encodestate));
+       base64_eprint(where, &estate, (const char *)p, n);
+       if (nl) tfc_nfsay(where, "\n");
+}
diff --git a/tfc_bench.c b/tfc_bench.c
new file mode 100644 (file)
index 0000000..595009e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+void do_benchmark(tfc_useconds useconds, double dseconds)
+{
+       size_t x, lblock;
+
+       for (x = 1; x < NSIG; x++) signal(x, SIG_IGN);
+       memset(&sigact, 0, sizeof(sigact));
+       sigact.sa_flags = SA_RESTART;
+       sigact.sa_handler = print_crypt_status;
+       sigaction(SIGINT, &sigact, NULL);
+       sigaction(SIGTERM, &sigact, NULL);
+       sigaction(SIGTSTP, &sigact, NULL);
+       sigaction(SIGALRM, &sigact, NULL);
+       setup_next_alarm(useconds);
+       memset(&sigact, 0, sizeof(struct sigaction));
+
+       tfc_getcurtime(&delta_time);
+
+       tfc_getrandom(key, sizeof(key));
+       tfc_getrandom(ctr, sizeof(ctr));
+       if (do_mac != NO) {
+               tfc_getrandom(mackey, sizeof(mackey));
+               if (ctr_mode < TFC_MODE_OCB) skein_init_key(&sk, mackey, macbits);
+       }
+       if (ctr_mode == TFC_MODE_STREAM) tfe_init_iv(&tfe, key, ctr);
+       if (ctr_mode == TFC_MODE_XTS) tfc_getrandom(xtskey, sizeof(xtskey));
+
+       tfc_nfsay(stdout, "%s: doing %s benchmark for %.4f seconds ... ", progname, tfc_modename(ctr_mode), dseconds);
+
+       do_stop = NO;
+       while (1) {
+               if (do_stop) break;
+
+               lblock = blk_len_adj(NOFSIZE, total_processed_src, blksize);
+               total_processed_src += lblock;
+
+               if (do_mac != NO && ctr_mode < TFC_MODE_OCB)
+                       skein_update(&sk, srcblk, lblock);
+
+               if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, srcblk, srcblk, lblock);
+               else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, srcblk, srcblk, lblock);
+               else if (ctr_mode == TFC_MODE_XTS && do_edcrypt == TFC_DO_ENCRYPT)
+                       tf_xts_encrypt(key, xtskey, ctr, srcblk, srcblk, lblock, xtsblocks);
+               else if (ctr_mode == TFC_MODE_XTS && do_edcrypt == TFC_DO_DECRYPT)
+                       tf_xts_decrypt(key, xtskey, ctr, srcblk, srcblk, lblock, xtsblocks);
+               else if (ctr_mode == TFC_MODE_ECB && do_edcrypt == TFC_DO_ENCRYPT)
+                       tf_ecb_encrypt(key, srcblk, srcblk, lblock);
+               else if (ctr_mode == TFC_MODE_ECB && do_edcrypt == TFC_DO_DECRYPT)
+                       tf_ecb_decrypt(key, srcblk, srcblk, lblock);
+               else if (ctr_mode == TFC_MODE_CBC && do_edcrypt == TFC_DO_ENCRYPT)
+                       tf_cbc_encrypt(key, ctr, srcblk, srcblk, lblock);
+               else if (ctr_mode == TFC_MODE_CBC && do_edcrypt == TFC_DO_DECRYPT)
+                       tf_cbc_decrypt(key, ctr, srcblk, srcblk, lblock);
+
+               else if (ctr_mode == TFC_MODE_OCB && do_edcrypt == TFC_DO_ENCRYPT)
+                       tf_ocb_encrypt(key, ctr, srcblk, do_mac ? macresult : NULL, srcblk, lblock, xtsblocks);
+               else if (ctr_mode == TFC_MODE_OCB && do_edcrypt == TFC_DO_DECRYPT)
+                       tf_ocb_decrypt(key, ctr, srcblk, do_mac ? macresult : NULL, srcblk, lblock, xtsblocks);
+
+               delta_processed += lblock;
+       }
+}
diff --git a/tfc_conv.c b/tfc_conv.c
new file mode 100644 (file)
index 0000000..045c06d
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+static const char *tfc_size_scale[] = {"B", "K", "M", "G", "T", "P"};
+
+void tfc_data_to_words64(void *data, size_t szdata)
+{
+#ifndef TF_NO_ENDIAN
+       size_t idx;
+       uint64_t *d = data;
+       uint64_t t;
+
+       for (idx = 0; idx < (szdata/sizeof(uint64_t)); idx++) {
+#ifdef TF_BIG_ENDIAN
+               t = htobe64(d[idx]);
+#else
+               t = htole64(d[idx]);
+#endif
+               d[idx] = t;
+       }
+#endif
+}
+
+static tfc_yesno tfc_is_number(const char *s)
+{
+       char *p;
+       if (!s || str_empty(s)) return NO;
+       strtol(s, &p, 10);
+       return str_empty(p) ? YES : NO;
+}
+
+tfc_fsize tfc_humanfsize(const char *s, char **stoi)
+{
+       char pfx[2], T[2], N[48], *ss;
+       int base = 10;
+       size_t l;
+       tfc_fsize gbgib = 0, ret = 0;
+
+       if (!s) return 0;
+
+       memset(N, 0, sizeof(N));
+       memset(pfx, 0, sizeof(pfx));
+       memset(T, 0, sizeof(T));
+
+       if (!strncmp(s, "0x", 2)) {
+               s += 2;
+               base = 16;
+       }
+       else if (s[0] == '0') base = 0;
+
+       l = strnlen(s, sizeof(N)-1);
+       memcpy(N, s, l);
+
+       ss = strchr(N, ':');
+       if (ss && ss[1] && (ss[1] == '+' || ss[1] == '-' || ss[1] == '*' || ss[1] == '/')) {
+               ss[0] = 0;
+               l = strnlen(N, sizeof(N)-1);
+       }
+
+       if (base == 16) goto _nopfx;
+
+       pfx[0] = N[l-1];
+       if (tfc_is_number(pfx) == NO) N[l-1] = 0;
+
+_nopfx:
+       *stoi = NULL;
+       if (tfc_is_number(pfx) || pfx[0] == 'B' || pfx[0] == 'c') ret = strtoull(N, stoi, base);
+       else if (pfx[0] == 'W') ret = strtoull(N, stoi, base)*2;
+       else if (pfx[0] == 'I') ret = strtoull(N, stoi, base)*4;
+       else if (pfx[0] == 'L') ret = strtoull(N, stoi, base)*8;
+       else if (pfx[0] == 'e') ret = strtoull(N, stoi, base)*TF_BLOCK_SIZE;
+       else if (pfx[0] == 'y') ret = strtoull(N, stoi, base)*TF_FROM_BITS(TFC_KEY_BITS);
+       else if (pfx[0] == 'x') ret = strtoull(N, stoi, base)*TF_FROM_BITS(TFC_KEY_BITS)*2;
+       else if (pfx[0] == 'E') ret = strtoull(N, stoi, base)*blksize;
+       else if (pfx[0] == 'b' || pfx[0] == 's') ret = strtoull(N, stoi, base)*512;
+       else if (pfx[0] == 'p' || pfx[0] == 'S') ret = strtoull(N, stoi, base)*4096;
+       else if (pfx[0] == 'k' || pfx[0] == 'K') {
+               gbgib = do_stats_in_gibs == YES ? 1000 : 1024;
+       }
+       else if (pfx[0] == 'm' || pfx[0] == 'M') {
+               gbgib = do_stats_in_gibs == YES ? 1000 * 1000 : 1024 * 1024;
+       }
+       else if (pfx[0] == 'g' || pfx[0] == 'G') {
+               gbgib = do_stats_in_gibs == YES ? 1000 * 1000 * 1000 : 1024 * 1024 * 1024;
+       }
+       else if (pfx[0] == 'T') {
+               gbgib = do_stats_in_gibs == YES ? 1000000000000ULL : 1099511627776ULL;
+       }
+       else if (pfx[0] == 'P') {
+               gbgib = do_stats_in_gibs == YES ? 1000000000000000ULL : 1125899906842624ULL;
+       }
+       else ret = strtoull(N, stoi, base);
+       if (gbgib) ret = strtoull(N, stoi, base) * gbgib;
+
+       return ret;
+}
+
+const char *tfc_getscale(int scale)
+{
+       return scale >= TFC_ARRAY_SIZE(tfc_size_scale) ?
+               tfc_size_scale[TFC_ARRAY_SIZE(tfc_size_scale)-1] : tfc_size_scale[scale];
+}
+
+void tfc_describescale(tfc_fsize num, double *w, int *scale)
+{
+       tfc_fsize gbgib = (do_stats_in_gibs == YES) ? 1000 : 1024;
+
+       if (num <= gbgib) {
+               *w = num;
+               *scale = 0;
+       }
+       else if ((num > gbgib)
+               && (num <= gbgib * gbgib)) {
+               *w = (double)num / gbgib;
+               *scale = 1;
+       }
+       else if ((num > gbgib * gbgib)
+               && (num <= gbgib * gbgib * gbgib)) {
+               *w = (double)num / (gbgib * gbgib);
+               *scale = 2;
+       }
+       else if ((num > gbgib * gbgib * gbgib)
+               && (num <= gbgib * gbgib * gbgib * gbgib)) {
+               *w = (double)num / (gbgib * gbgib * gbgib);
+               *scale = 3;
+       }
+       else if ((num > gbgib * gbgib * gbgib * gbgib)
+               && num <= gbgib * gbgib * gbgib * gbgib * gbgib) {
+               *w = (double)num/ (gbgib * gbgib * gbgib * gbgib);
+               *scale = 4;
+       }
+       else {
+               *w = (double)num / (gbgib * gbgib * gbgib * gbgib * gbgib);
+               *scale = 5;
+       }
+}
diff --git a/tfc_error.c b/tfc_error.c
new file mode 100644 (file)
index 0000000..7c001da
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+void xerror(tfc_yesno noexit, tfc_yesno noerrno, tfc_yesno nostats, const char *fmt, ...)
+{
+       va_list ap;
+       char *s;
+
+       if (quiet) goto _ex;
+
+       va_start(ap, fmt);
+
+       if (statline_was_shown == YES && do_statline_dynamic == YES) tfc_esay("\n");
+
+       tfc_nfsay(stderr, "%s: ", progname);
+       tfc_vfsay(stderr, NO, fmt, ap);
+       if (errno && noerrno == NO) {
+               s = strerror(errno);
+               tfc_esay(": %s", s);
+       }
+       else tfc_esay("\n");
+
+       va_end(ap);
+
+       if (nostats == NO) print_crypt_status(-1);
+
+_ex:
+       if (noexit == YES) {
+               errno = 0;
+               return;
+       }
+
+       xexit(2);
+}
+
+void xexit(int status)
+{
+       memset(srcblk, 0, sizeof(srcblk));
+       memset(dstblk, 0, sizeof(dstblk));
+
+       memset(key, 0, sizeof(key));
+       memset(ctr, 0, sizeof(ctr));
+       memset(mackey, 0, sizeof(mackey));
+       memset(xtskey, 0, sizeof(xtskey));
+       memset(&sk, 0, sizeof(struct skein));
+       memset(&tfe, 0, sizeof(struct tfe_stream));
+
+       tfc_finirandom();
+
+       memset(macvrfy, 0, sizeof(macvrfy));
+       memset(macresult, 0, sizeof(macresult));
+
+       memset(tmpdata, 0, sizeof(tmpdata));
+       memset(&getps, 0, sizeof(struct getpasswd_state));
+       memset(pwdask, 0, sizeof(pwdask));
+       memset(pwdagain, 0, sizeof(pwdagain));
+
+       exit(status);
+}
+
+void usage(void)
+{
+       tfc_yesno is_embedded_prog = NO;
+
+       if (optopt == 'V') {
+               tfc_say("tfcrypt toolkit, version %s.", _TFCRYPT_VERSION);
+               xexit(0);
+       }
+
+       if ((strlen(progname) <= 9)
+       && ((!strcmp(progname, "sksum"))
+       || ((!memcmp(progname, "sk", 2))
+       && (!memcmp(progname+3, "sum", 3)
+       || !memcmp(progname+4, "sum", 3)
+       || !memcmp(progname+5, "sum", 3)
+       || !memcmp(progname+6, "sum", 3))))) {
+               is_embedded_prog = YES;
+               tfc_say("usage: %s [-AW] [-D BITS] [-n TURNS] [-l length] [-c <file>] [-U <file>] [source] ...", progname);
+               tfc_say("\n");
+               tfc_say("%s: calculate and print Skein hashsum of stream.", progname);
+               tfc_say("  -D BITS: specify bits as it was skBITSsum.");
+               tfc_say("  -n TURNS: number of turns to perform in Skein function.");
+               tfc_say("    sksum defaults to just one in all modes.");
+               tfc_say("  -A: format checksum in base64 rather than in binary hex.");
+               tfc_say("  -W: output raw binary checksum and remove filename(s) from output.");
+               tfc_say("  -H: output small hexdump (hex string and ASCII printable characters).");
+               tfc_say("  -l length: read only these first bytes of source.");
+               tfc_say("  -c <file>: read hashes list from file and check them.");
+               tfc_say("  -U <file>: read Skein MAC key from file.");
+               tfc_say("multiple sources can be given in cmdline, and if one of");
+               tfc_say("them is specified as \"-\", then reads are performed from stdin.");
+               tfc_say("\n");
+       }
+       else if (!strcmp(progname, "base64")) {
+               is_embedded_prog = YES;
+               tfc_say("usage: %s [-ed] [source] [output]", progname);
+               tfc_say("\n");
+               tfc_say("tfcrypt embedded base64 encoder/decoder.");
+               tfc_say("  -e: encode stream into base64.");
+               tfc_say("  -d: decode base64 stream.");
+               tfc_say("no error checking is performed.");
+               tfc_say("\n");
+       }
+       else if (!strcmp(progname, "tfbench")) {
+               is_embedded_prog = YES;
+               tfc_say("usage: %s seconds", progname);
+               tfc_say("do an in-memory random data benchmark of Threefish.");
+               tfc_say("\n");
+       }
+
+       if (is_embedded_prog) {
+               tfc_say("This program is physical part of tfcrypt toolkit.");
+               tfc_say("(see it's version with %s -V)", progname);
+               tfc_say("Please note that other tfcrypt options are either ignored there,");
+               tfc_say("or result of using them is undefined and it's not a bug.");
+
+               xexit(1);
+       }
+
+       tfc_say("usage: %s [opts] [--] [key] [source] [output]", progname);
+       tfc_say("\n");
+       tfc_say("tfcrypt toolkit: encrypt streams with Threefish in CTR mode,");
+       tfc_say("calculate and check Skein hashsums, generate CSPRNG quality random data,");
+       tfc_say("convert encrypted data into ASCII format to ease transmission.");
+       tfc_say("\n");
+       tfc_say("  -e, -d: encrypt, decrypt (it maybe required).");
+       tfc_say("  -p: instead of using key, ask for password.");
+       tfc_say("  -k: use raw (%u byte) key instead of deriving it from arbitrary data.", TFC_U(TF_KEY_SIZE));
+       tfc_say("  -z: ask for key in plain C string form through password asker.");
+       tfc_say("  -x: ask for key in hex string form through password asker.");
+       tfc_say("  -K <file>: generate key from keyfile or password and write it to file.");
+       tfc_say("  -T: enable tfcrypt1 old mode (useful only for old encryptions).");
+       tfc_say("  -t <file>: use tweak from file (useful only for old encryptions).");
+       tfc_say("  -w: overwrite source file. If not file, ignored.");
+       tfc_say("  -n TURNS: number of turns to perform in Skein function.");
+       tfc_say("    Default is always defined when building tfcrypt.");
+       tfc_say("  -C mode: mode of operation: CTR, STREAM, XTS, ECB, CBC, OCB.");
+       tfc_say("    Default encryption mode can be changed when building tfcrypt.");
+       tfc_say("  -c opt: initial CTR value initialisation mode:");
+       tfc_say("    show: do default action, then dump CTR value to stderr,");
+       tfc_say("    head: when decrypting, read CTR from beginning of stream,");
+       tfc_say("    rand: generate random CTR and write it to beginning of stream,");
+       tfc_say("    <file>: read CTR from given file (both when encrypting/decrypting).");
+       tfc_say("      default is to derive CTR from user provided password or keyfile with");
+       tfc_say("      a single Skein function turn over derived, %u byte raw key", TFC_U(TF_KEY_SIZE));
+       tfc_say("  -q: always be quiet, never tell anything (except when signaled).");
+       tfc_say("  -v: print number of read and written encrypted bytes, and explain stages.");
+       tfc_say("  -V seconds: activate timer that will repeatedly print statistics to stderr.");
+       tfc_say("  -a: shortcut of -O xtime.");
+       tfc_say("  -r <file>: specify random source instead of /dev/urandom.");
+       tfc_say("  -R nr_bytes: generate nr_bytes of random bytes suitable for use as key data.");
+       tfc_say("    -R also supports these aliases specified instead of nr_bytes:");
+       tfc_say("    cbs: output fixed maximum crypt block size (%u bytes),", TFC_U(TF_BLOCK_SIZE));
+       tfc_say("    ks: output fixed maximum crypt key size (%u bytes)", TFC_U(TF_KEY_SIZE));
+       tfc_say("    xks: output fixed maximum crypt XTS key size (%u bytes)", TFC_U(TF_KEY_SIZE*2));
+       tfc_say("    iobs: output %s builtin block size TFC_BLKSIZE (%u bytes),", progname, TFC_U(TFC_BLKSIZE));
+       tfc_say("    if nr_bytes is not a valid number or alias, this string will be");
+       tfc_say("    used to attempt to open it as file, and examine it's size.");
+       tfc_say("    Then this examined size will be set as nr_bytes to output.");
+       tfc_say("  -Z nr_bytes: like -R, but emit zero stream instead of random.");
+       tfc_say("  -D MACBITS: specify bit width of a MAC signature.");
+       tfc_say("  -U key/pwd/<file>: read Skein MAC key from file.");
+       tfc_say("    key: use primary encryption rawkey as a MAC key.");
+       tfc_say("    pwd: ask for password string that will be used as MAC key.");
+       tfc_say("  -S MAC: append MAC signature to end of file:");
+       tfc_say("    MAC: embed MAC signature into file itself at the end,");
+       tfc_say("    <file>: write a detached MAC signature into separate <file>,");
+       tfc_say("    -: write a detached MAC signature to stdout.");
+       tfc_say("    useful only with variable length files! For block devices,");
+       tfc_say("    specify a separate file name to save signature to: -S file.");
+       tfc_say("  -A: format raw binary data, like MAC signature or Skein hash, in base64.");
+       tfc_say("  -W: output pure binary data, and disable any strings addition in Skein.");
+       tfc_say("  -H: output small hexdump (hex string and ASCII printable characters).");
+       tfc_say("  -M MAC: verify attached MAC signature when decrypting a file:");
+       tfc_say("    MAC: embed MAC signature into file itself at the end,");
+       tfc_say("    <file>: write a detached MAC signature into separate <file>,");
+       tfc_say("    -: read a detached MAC signature from stdin,");
+       tfc_say("    drop: do not verify attached MAC, if any, and drop it from output.");
+       tfc_say("  -m: just verify MAC provided with -M. Do not write output file.");
+       tfc_say("    This option must be specified after -M.");
+       tfc_say("  -E how: how to behave on I/O errors (both src or dst):");
+       tfc_say("    exit: print error if not quiet, then exit,");
+       tfc_say("    cont: print error if not quiet, then continue,");
+       tfc_say("      no action to pad missing data is attempted.");
+       tfc_say("      may be dangerous when working with block devices.");
+       tfc_say("    sync: print error if not quiet, then continue.");
+       tfc_say("      pad missing data block with zeroes.");
+       tfc_say("      note that sync works only with read errors!");
+       tfc_say("  default error action is exit with printing status if not quiet.");
+       tfc_say("  -E xall: turn on error actions above for all errors, not just EIO errors.");
+       tfc_say("    This must be a separate option given before usual -E how option.");
+       tfc_say("  -O opts: set options (comma separated list):");
+       tfc_say("    sync: request a synchronous I/O for a output,");
+       tfc_say("    fsync: on each write() call a corresponding fsync(fd),");
+       tfc_say("    trunc: open(O_WRONLY) will truncate output file to zero size.");
+       tfc_say("    pad: pad incomplete (l.t. %u bytes) block with zeroes.", TFC_U(TF_BLOCK_SIZE));
+       tfc_say("    xtime: copy timestamps from source to destination files.");
+       tfc_say("    gibsize: use SI units of size: 1k = 1000. Applies only to size prefixes.");
+       tfc_say("    Computers convention is to use 1024, whereas SI/hdd measure in 1000.");
+       tfc_say("    plainstats: force status line to be plain: no fancy dynamic stuff.");
+       tfc_say("    Dynamic line works well only on VT100 compatible ttys, and");
+       tfc_say("    when the whole status line width is smaller than tty width.");
+       tfc_say("    statless: emit less information in status line (only processed data).");
+       tfc_say("    norepeat: do not ask for any possible password confirmations.");
+       tfc_say("    prompt=str: set main password prompts to this string.");
+       tfc_say("    macprompt=str: set MAC password prompts to this string.");
+       tfc_say("    shorthex: with -H, do not print printable characters, dump only hex string.");
+       tfc_say("    iobs=val: set IO block size value. Must not exceed %u bytes.", TFC_U(TFC_BLKSIZE));
+       tfc_say("    xtsblocks=val: use these nr of TF blocks per XTS block. Default is %u.", TFC_U(TFC_XTSBLOCKS));
+       tfc_say("    iseek=val: seek source file/device by these val bytes.");
+       tfc_say("    Initial counter is adjusted automatically.");
+       tfc_say("    ixseek=val: rawseek source file/device by these val bytes.");
+       tfc_say("    Do not adjust initial counter automatically.");
+       tfc_say("    ictr=val: Increment initial counter by this val blocks.");
+       tfc_say("    The size of each block is %u bytes.", TFC_U(TF_BLOCK_SIZE));
+       tfc_say("    ictr option is valid only for CTR and CTR like modes.");
+       tfc_say("    ixctr=val: Increment initial counter by this val bytes.");
+       tfc_say("    Internally this number is translated into number of %u byte blocks.", TFC_U(TF_BLOCK_SIZE));
+       tfc_say("    oseek=val: seek destination file/device by these val bytes.");
+       tfc_say("    count=val: process only these val bytes, both input and output.");
+       tfc_say("    xkey=val: take only val bytes from user keyfile.");
+       tfc_say("    xctr=val: specify size in bytes of initial counter prepended or read.");
+       tfc_say("  -P: plain IO mode: disable encryption/decryption code at all.");
+       tfc_say("\n");
+       tfc_say("Default is to ask for password, then encrypt stdin into stdout.");
+       tfc_say("Some cmdline parameters may be mutually exclusive, or they can");
+       tfc_say("generate errors or behave abnormally. Please understand that some");
+       tfc_say("dumb mode error checking may be not performed well, and please read");
+       tfc_say("the README included within package and this help text carefully.");
+       tfc_say("\n");
+
+       xexit(1);
+}
diff --git a/tfc_misc.c b/tfc_misc.c
new file mode 100644 (file)
index 0000000..d1bb783
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+size_t blk_len_adj(tfc_fsize filelen, tfc_fsize read_already, size_t blklen)
+{
+       if (filelen == NOFSIZE) return blklen;
+       return ((filelen - read_already) >= blklen) ? blklen : (filelen - read_already);
+}
+
+tfc_yesno xor_shrink(void *dst, size_t szdst, const void *src, size_t szsrc)
+{
+       unsigned char *udst = dst;
+       const unsigned char *usrc = src;
+       size_t x, y;
+
+       if ((szsrc % szdst) != 0) return NO;
+       if (szdst >= szsrc) {
+               if (szdst == szsrc) {
+                       memmove(dst, src, szsrc);
+                       return YES;
+               }
+               return NO;
+       }
+
+       memset(dst, 0, szdst);
+       for (x = 0; x < (szsrc / szdst); x++) {
+               for (y = 0; y < szdst; y++) udst[y] ^= usrc[(x*szdst)+y];
+       }
+
+       return YES;
+}
+
+tfc_yesno str_empty(const char *str)
+{
+       if (!*str) return YES;
+       return NO;
+}
+
+void xclose(int fd)
+{
+       if (fd < 3) return;
+       if (close(fd) == -1) xerror(YES, NO, NO, "close(%d)", fd);
+}
+
+const char *tfc_modename(int mode)
+{
+       switch (mode) {
+               case TFC_MODE_CTR: return "CTR";
+               case TFC_MODE_STREAM: return "STREAM";
+               case TFC_MODE_XTS: return "XTS";
+               case TFC_MODE_ECB: return "ECB";
+               case TFC_MODE_CBC: return "CBC";
+               case TFC_MODE_OCB: return "OCB";
+       }
+
+       return NULL;
+}
+
+void tfc_getcurtime(tfc_useconds *tx)
+{
+       struct timeval t;
+       memset(&t, 0, sizeof(t));
+
+       gettimeofday(&t, NULL);
+       *tx = t.tv_sec * 1000000 + t.tv_usec;
+
+       memset(&t, 0, sizeof(t));
+}
+
+tfc_fsize tfc_fdsize(int fd)
+{
+       off_t l, cur;
+
+       cur = lseek(fd, 0L, SEEK_CUR);
+       l = lseek(fd, 0L, SEEK_SET);
+       if (l == -1) return -1;
+       l = lseek(fd, 0L, SEEK_END);
+       if (l == -1) return -1;
+       lseek(fd, cur, SEEK_SET);
+
+       return (tfc_fsize)l;
+}
+
+tfc_fsize tfc_fnamesize(char *fname, tfc_yesno noexit)
+{
+       int fnmfd;
+       tfc_fsize ret;
+       char *s, T[2];
+
+       if (!fname) return 0;
+
+       s = strchr(fname, ':');
+       if (s && s[1] && (s[1] == '+' || s[1] == '-' || s[1] == '*' || s[1] == '/')) {
+               memcpy(T, s, 2);
+               memset(s, 0, 2);
+       }
+
+       fnmfd = open(fname, O_RDONLY);
+       if (s) memcpy(s, T, 2);
+       if (fnmfd == -1) {
+               xerror(noexit, NO, YES, "%s", fname);
+               return NOFSIZE;
+       }
+       ret = tfc_fdsize(fnmfd);
+       if (ret == NOFSIZE) {
+               xerror(noexit, NO, YES, "%s: not a seekable file", fname);
+               return ret;
+       }
+       xclose(fnmfd);
+
+       return ret;
+}
+
+tfc_fsize tfc_modifysize(tfc_fsize szmodify, const char *szspec)
+{
+       tfc_fsize t;
+       const char *s;
+       char *stoi, c;
+
+       if (szmodify == NOFSIZE) return NOFSIZE;
+       if (!szspec) return szmodify;
+       s = szspec;
+
+       if (*s != ':') return szmodify;
+       s++;
+       if (!(*s == '+' || *s == '-' || *s == '*' || *s == '/')) return szmodify;
+       c = *s;
+       s++;
+       if (strchr(s, '/') || strchr(s, '.')) return szmodify;
+
+       t = tfc_humanfsize(s, &stoi);
+       if (!str_empty(stoi)) return szmodify;
+
+       switch (c) {
+               case '+': szmodify += t; break;
+               case '-': szmodify -= t; break;
+               case '*': szmodify *= t; break;
+               case '/': szmodify /= t; break;
+               default: break;
+       }
+
+       return szmodify;
+}
+
+void fcopy_matime(int fd, const struct stat *st)
+{
+       struct timeval times[2];
+
+       times[1].tv_sec = times[0].tv_sec = st->st_mtime;
+       times[1].tv_usec = times[0].tv_usec = 0;
+       if (futimes(fd, times) == -1) xerror(YES, NO, YES, "futimes(%d)", fd);
+}
+
+static void char_to_nul(char *s, size_t l, int c)
+{
+       while (*s && l) { if (*s == c) { *s = 0; break; } s++; l--; }
+}
+
+tfc_yesno xfgets(char *s, size_t n, FILE *f)
+{
+       memset(s, 0, n);
+
+       if (fgets(s, (int)n, f) == s) {
+               char_to_nul(s, n, '\n');
+               return YES;
+       }
+
+       return NO;
+}
+
+tfc_yesno isbase64(const char *s)
+{
+       while (*s) {
+               if (*s >= 'g' && *s <= 'z') return YES;
+               if (*s >= 'G' && *s <= 'Z') return YES;
+               if (*s == '+' || *s == '/' || *s == '=') return YES;
+               s++;
+       }
+       return NO;
+}
+
+static int chrbin(char x)
+{
+       if (x >= '0' && x <= '9')
+               return x - '0';
+       if (x >= 'A' && x <= 'F')
+               return x - 'A' + 10;
+       if (x >= 'a' && x <= 'f')
+               return x - 'a' + 10;
+       return 0;
+}
+
+void hex2bin(void *d, const char *s)
+{
+       const char *S = s;
+       char *D = d;
+       int x = 0;
+
+       while (*s) {
+               if ((s-S) % 2) {
+                       x = (x << 4) ^ chrbin(*s);
+                       *D = x; D++;
+               }
+               else x = chrbin(*s);
+               s++;
+       }
+}
diff --git a/tfc_random.c b/tfc_random.c
new file mode 100644 (file)
index 0000000..4b82aee
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+static void get_urandom(const char *src, void *buf, size_t size)
+{
+       tfc_byte *ubuf = buf;
+       int fd = -1;
+       size_t sz = size, rd;
+
+       if (src == NULL) fd = -1;
+       else fd = open(src, O_RDONLY);
+
+       if (fd == -1) fd = open("/dev/urandom", O_RDONLY);
+       if (fd == -1) fd = open("/dev/arandom", O_RDONLY);
+       if (fd == -1) fd = open("/dev/prandom", O_RDONLY);
+       if (fd == -1) fd = open("/dev/srandom", O_RDONLY);
+       if (fd == -1) fd = open("/dev/random", O_RDONLY);
+       if (fd == -1) xerror(NO, YES, YES, "random source is required (tried %s)", src);
+
+_again:        rd = read(fd, ubuf, sz);
+       if (rd < sz && rd != NOSIZE) {
+               ubuf += rd;
+               sz -= rd;
+               goto _again;
+       }
+
+       xclose(fd);
+}
+
+static tfc_yesno tfc_random_initialised;
+
+static void tfc_initrandom(const char *rndsrc)
+{
+       tfc_byte k[TF_KEY_SIZE];
+
+       if (tfc_random_initialised == YES) return;
+
+       get_urandom(rndsrc, k, TF_KEY_SIZE);
+       tf_prng_seedkey(k);
+       memset(k, 0, TF_KEY_SIZE);
+
+       tfc_random_initialised = YES;
+}
+
+void tfc_finirandom(void)
+{
+       tf_prng_seedkey(NULL);
+       tfc_random_initialised = NO;
+}
+
+void tfc_getrandom(void *buf, size_t sz)
+{
+       if (tfc_random_initialised == NO) tfc_initrandom(randsource);
+       tf_prng_genrandom(buf, sz);
+}
+
+void gen_write_bytes(const char *foutname, tfc_fsize offset, tfc_fsize nrbytes)
+{
+       int fd, x;
+       size_t lblock;
+
+       for (x = 1; x < NSIG; x++) signal(x, SIG_IGN);
+       memset(&sigact, 0, sizeof(sigact));
+       sigact.sa_flags = SA_RESTART;
+       sigact.sa_handler = print_crypt_status;
+       sigaction(SIGUSR1, &sigact, NULL);
+       sigaction(SIGTSTP, &sigact, NULL);
+       sigaction(SIGALRM, &sigact, NULL);
+       if (status_timer) setup_next_alarm(status_timer);
+       sigact.sa_handler = change_status_width;
+       sigaction(SIGQUIT, &sigact, NULL);
+       sigact.sa_handler = change_status_timer;
+       sigaction(SIGUSR2, &sigact, NULL);
+       if (quiet == NO) {
+               sigact.sa_handler = print_crypt_status;
+               sigaction(SIGINT, &sigact, NULL);
+               sigaction(SIGTERM, &sigact, NULL);
+       }
+       else {
+               sigact.sa_handler = exit_sigterm;
+               sigaction(SIGINT, &sigact, NULL);
+               sigaction(SIGTERM, &sigact, NULL);
+       }
+       memset(&sigact, 0, sizeof(struct sigaction));
+
+       tfc_getcurtime(&delta_time);
+
+       if (do_less_stats) do_less_stats = NO;
+       else do_less_stats = YES;
+
+       if (!foutname) {
+               fd = 1;
+               foutname = TFC_STDOUT_NAME;
+       }
+       else if (!strcmp(foutname, "-")) {
+               fd = 1;
+               foutname = TFC_STDOUT_NAME;
+       }
+       else fd = open(foutname, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
+       if (fd == -1) xerror(NO, NO, YES, "%s", foutname);
+
+       if (offset) {
+               if (lseek(fd, offset, SEEK_SET) == -1)
+                       xerror(YES, NO, NO, "%s: seek failed", foutname);
+       }
+
+       if (ctr_mode == TFC_MODE_PLAIN) memset(srcblk, 0, sizeof(srcblk));
+
+       if (verbose) tfc_nfsay(stderr, "%s: writing %lld bytes to %s ... ",
+               progname, nrbytes, foutname);
+
+       errno = 0;
+       do_stop = NO;
+       while (1) {
+               if (do_stop) break;
+               lblock = blk_len_adj(nrbytes, total_processed_src, sizeof(srcblk));
+
+               if (ctr_mode != TFC_MODE_PLAIN) tfc_getrandom(srcblk, lblock);
+
+               if (write(fd, srcblk, lblock) == -1)
+                       xerror(NO, NO, YES, "%s", foutname);
+               if (do_fsync && fsync(fd) == -1) xerror(NO, NO, YES, "%s", foutname);
+
+               total_processed_src += lblock;
+               delta_processed += lblock;
+               total_processed_dst = total_processed_src;
+               if (total_processed_src >= nrbytes) break;
+       }
+
+       if (verbose) tfc_esay("done!");
+       if (verbose || status_timer) print_crypt_status(0);
+
+       xclose(fd);
+       xexit(0);
+}
diff --git a/tfc_say.c b/tfc_say.c
new file mode 100644 (file)
index 0000000..04d4da4
--- /dev/null
+++ b/tfc_say.c
@@ -0,0 +1,68 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+void tfc_vfsay(FILE *where, tfc_yesno addnl, const char *fmt, va_list ap)
+{
+       if (!strcmp(fmt, "\n")) {
+               fputc('\n', where);
+               return;
+       }
+
+       vfprintf(where, fmt, ap);
+       if (addnl) fputc('\n', where);
+       fflush(where);
+}
+
+void tfc_nfsay(FILE *where, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       tfc_vfsay(where, NO, fmt, ap);
+       va_end(ap);
+}
+
+void tfc_esay(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       tfc_vfsay(stderr, YES, fmt, ap);
+       va_end(ap);
+}
+
+void tfc_say(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       tfc_vfsay(stdout, YES, fmt, ap);
+       va_end(ap);
+}
diff --git a/tfc_signal.c b/tfc_signal.c
new file mode 100644 (file)
index 0000000..3cb10b8
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+void exit_sigterm(int signal)
+{
+       xexit(0);
+}
+
+void print_crypt_status(int signal)
+{
+       tfc_fsize wr_speed;
+       double seconds, human_totalproc_src, human_totalproc_dst, human_wr_speed;
+       int src_scale_idx, dst_scale_idx, wr_speed_scale;
+       const char *oper_mode, *inplace;
+       static tfc_yesno last, was_sigint;
+
+       if (last == YES) return;
+       if (signal == 0) last = YES;
+
+       switch (do_edcrypt) {
+               case TFC_DO_ENCRYPT: oper_mode = "encrypted"; break;
+               case TFC_DO_DECRYPT: oper_mode = "decrypted"; break;
+               default:
+                       if (ctr_mode == TFC_MODE_PLAIN) oper_mode = "written";
+                       else if (ctr_mode == TFC_MODE_SKSUM) oper_mode = "hashed";
+                       else oper_mode = NULL;
+                       break;
+       }
+
+       if (signal == SIGINT || signal == SIGTERM) {
+               if (signal == SIGINT) was_sigint = YES;
+               if (do_stop == TFC_STOP_FULL) xexit(0);
+               do_stop = TFC_STOP_FULL;
+               status_timer = 0;
+               verbose = NO;
+               if (bench_timer) goto _out;
+               return;
+       }
+
+_out:  tfc_getcurtime(&current_time);
+       seconds = TFC_UTODSECS(current_time - delta_time);
+       wr_speed = delta_processed / seconds;
+       tfc_describescale(total_processed_src, &human_totalproc_src, &src_scale_idx);
+       tfc_describescale(total_processed_dst, &human_totalproc_dst, &dst_scale_idx);
+       tfc_describescale(wr_speed, &human_wr_speed, &wr_speed_scale);
+
+       if (bench_timer) {
+               tfc_say("done!");
+               tfc_say("%s %s benchmark results:", progname, tfc_modename(ctr_mode));
+               tfc_nfsay(stdout, "%s %llu (%.2f%s) bytes, "
+                       "avg. speed %llu (%.2f%s) B/s, time %.4fs.",
+                       oper_mode,
+                       total_processed_src, human_totalproc_src, tfc_getscale(src_scale_idx),
+                       wr_speed, human_wr_speed, tfc_getscale(wr_speed_scale),
+                       TFC_UTODSECS(current_time - delta_time));
+               if (was_sigint == NO) tfc_esay("\n");
+               xexit(0);
+       }
+
+       if (do_statline_dynamic == YES) inplace = "\033[2K\r";
+       else inplace = "";
+
+       if (do_less_stats == YES) {
+               tfc_nfsay(stderr, "%s%s:"
+                       " %s %.2f%s,"
+                       " %.2f%s B/s",
+                       inplace, progname,
+                       oper_mode,
+                       human_totalproc_dst, tfc_getscale(dst_scale_idx),
+                       human_wr_speed, tfc_getscale(wr_speed_scale));
+       }
+       else {
+               if (ctr_mode <= TFC_MODE_PLAIN) tfc_nfsay(stderr, "%s%s: read: %llu (%.2f%s),"
+                       " %s %llu (%.2f%s) bytes,"
+                       " (%llu (%.2f%s) B/s)",
+                       inplace, progname,
+                       total_processed_src, human_totalproc_src, tfc_getscale(src_scale_idx),
+                       oper_mode,
+                       total_processed_dst, human_totalproc_dst, tfc_getscale(dst_scale_idx),
+                       wr_speed, human_wr_speed, tfc_getscale(wr_speed_scale));
+               else tfc_nfsay(stderr, "%s%s: read: %llu (%.2f%s),"
+                       " %s %s %llu (%.2f%s) bytes,"
+                       " (%llu (%.2f%s) B/s)",
+                       inplace, progname,
+                       total_processed_src, human_totalproc_src, tfc_getscale(src_scale_idx),
+                       tfc_modename(ctr_mode), oper_mode,
+                       total_processed_dst, human_totalproc_dst, tfc_getscale(dst_scale_idx),
+                       wr_speed, human_wr_speed, tfc_getscale(wr_speed_scale));
+       }
+
+       if ((do_statline_dynamic == NO || last == YES || signal == -1) && was_sigint == NO) tfc_esay("\n");
+       statline_was_shown = YES;
+
+       delta_processed = 0;
+       tfc_getcurtime(&delta_time);
+
+       if (signal == SIGTSTP) {
+               tfc_esay("stopping.");
+               kill(getpid(), SIGSTOP);
+       }
+
+       if (status_timer) setup_next_alarm(status_timer);
+}
+
+void change_status_width(int signal)
+{
+       if (do_less_stats == YES) do_less_stats = NO;
+       else if (do_less_stats == NO) do_less_stats = YES;
+}
+
+void change_status_timer(int signal)
+{
+       static tfc_useconds reset_timer;
+       tfc_useconds t;
+
+       tfc_getcurtime(&t);
+       if (reset_timer && (t - reset_timer) < TFC_DTOUSECS(0.1)) status_timer = 0;
+       reset_timer = t;
+
+       if (status_timer == 0) status_timer = TFC_DTOUSECS(0.25);
+       else status_timer *= 2;
+
+       if (verbose) tfc_esay("%s: status timer was changed to %.2fs",
+               progname, TFC_UTODSECS(status_timer));
+       setup_next_alarm(status_timer);
+}
+
+void setup_next_alarm(tfc_useconds useconds)
+{
+       struct itimerval it;
+
+       memset(&it, 0, sizeof(struct itimerval));
+       it.it_value.tv_sec = useconds / 1000000;
+       it.it_value.tv_usec = useconds % 1000000;
+       setitimer(ITIMER_REAL, &it, NULL);
+}
diff --git a/tfc_skein.c b/tfc_skein.c
new file mode 100644 (file)
index 0000000..369fc23
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+#include "tfcore.h"
+
+void skein(void *hash, size_t bits, const void *key, const void *data, size_t szdata)
+{
+       struct skein sk;
+
+       if (key) skein_init_key(&sk, key, bits);
+       else skein_init(&sk, bits);
+       skein_update(&sk, data, szdata);
+       skein_final(hash, &sk);
+}
+
+void tf_key_tweak_compat(void *key)
+{
+       TF_UNIT_TYPE *ukey = key, c = THREEFISH_CONST;
+       size_t x;
+
+       for (x = 0; x < TF_NR_BLOCK_UNITS; x++) c ^= ukey[x];
+       ukey[x] = c;
+       ukey[TF_TWEAK_WORD3] = ukey[TF_TWEAK_WORD1] ^ ukey[TF_TWEAK_WORD2];
+}
+
+tfc_yesno skeinfd(void *hash, size_t bits, const void *key, int fd, tfc_fsize readto)
+{
+       static tfc_byte skblk[TFC_BLKSIZE];
+
+       struct skein sk;
+       tfc_byte *pblk;
+       size_t ldone, lblock, lrem, lio;
+       tfc_fsize total = 0;
+       tfc_yesno stop;
+
+       if (ctr_mode == TFC_MODE_SKSUM) total_processed_src = total_processed_dst = delta_processed = 0;
+
+       if (fd == -1) goto _fail;
+       if (fd > 2 && readto == NOFSIZE) {
+               readto = tfc_fdsize(fd);
+               if (readto == NOFSIZE) goto _fail;
+       }
+
+       if (key) skein_init_key(&sk, key, bits);
+       else skein_init(&sk, bits);
+
+       errno = 0;
+       stop = NO;
+       while (1) {
+               if (stop) break;
+               pblk = skblk;
+               lblock = lrem = blk_len_adj(readto, total, TFC_BLKSIZE);
+               ldone = 0;
+_again:                lio = read(fd, pblk, lrem);
+               if (lio == 0) stop = YES;
+               if (lio != NOSIZE) ldone += lio;
+               else {
+                       if (errno != EIO && catch_all_errors != YES) goto _fail;
+                       switch (error_action) {
+                               case TFC_ERRACT_CONT: xerror(YES, NO, NO, "skeinfd: %d", fd); goto _again; break;
+                               case TFC_ERRACT_SYNC:
+                                       xerror(YES, NO, NO, "skeinfd: %d", fd);
+                                       lio = lrem = ldone = lblock;
+                                       total += lio;
+                                       memset(skblk, 0, lio);
+                                       lseek(fd, lio, SEEK_CUR);
+                                       break;
+                               default: goto _fail; break;
+                       }
+               }
+               if (lio && lio < lrem) {
+                       pblk += lio;
+                       lrem -= lio;
+                       goto _again;
+               }
+               total += ldone;
+               if (ctr_mode == TFC_MODE_SKSUM) {
+                       total_processed_src = total_processed_dst = total;
+                       delta_processed += ldone;
+               }
+               skein_update(&sk, skblk, ldone);
+               if (readto != NOFSIZE && total >= readto) break;
+       }
+
+       if (fd > 2) lseek(fd, (off_t)readto, SEEK_SET);
+
+       skein_final(hash, &sk);
+       if (ctr_mode == TFC_MODE_SKSUM) {
+               if (verbose || status_timer) print_crypt_status(-1);
+               total_processed_src = total_processed_dst = delta_processed = 0;
+       }
+       memset(skblk, 0, TFC_BLKSIZE);
+       return YES;
+
+_fail:
+       memset(&sk, 0, sizeof(struct skein));
+       memset(hash, 0, SKEIN_DIGEST_SIZE);
+       memset(skblk, 0, TFC_BLKSIZE);
+       return NO;
+}
+
+void do_sksum(char *spec, char **fargv)
+{
+       static char sksblk[TFC_BLKSIZE / 2], tmp[TFC_TMPSIZE];
+       tfc_byte hash[SKEIN_DIGEST_SIZE];
+       int fd = -1;
+       int x = 0, xx;
+       size_t bits;
+
+       if (macbits < TF_MAX_BITS) {
+               bits = macbits;
+               goto _dothat;
+       }
+
+       if (!strcmp(spec, "sksum")) {
+               bits = TF_MAX_BITS;
+               goto _dothat;
+       }
+
+       if ((sscanf(spec, "sk%zusum", &bits) < 1)) {
+               bits = TF_MAX_BITS;
+       }
+
+       if (bits < 8 || bits > TF_MAX_BITS) {
+               xerror(NO, YES, YES,
+               "%u: invalid bits number specified!\n"
+               "tfcrypt supports from 8 to %u bits, divisible by 8.",
+               bits, TFC_U(TF_MAX_BITS));
+       }
+
+       if (!bits || bits % 8) {
+               xerror(NO, YES, YES,
+               "%u: invalid bits number specified!\n"
+               "Number of bits must start from 8 and be divisible by 8.",
+               bits, TFC_U(TF_MAX_BITS));
+       }
+
+_dothat:
+       do_edcrypt = TFC_DO_PLAIN;
+       ctr_mode = TFC_MODE_SKSUM;
+
+       for (x = 1; x < NSIG; x++) signal(x, SIG_IGN);
+       memset(&sigact, 0, sizeof(sigact));
+       sigact.sa_flags = SA_RESTART;
+       sigact.sa_handler = print_crypt_status;
+       sigaction(SIGUSR1, &sigact, NULL);
+       sigaction(SIGTSTP, &sigact, NULL);
+       sigaction(SIGALRM, &sigact, NULL);
+       sigact.sa_handler = change_status_width;
+       sigaction(SIGQUIT, &sigact, NULL);
+       sigact.sa_handler = change_status_timer;
+       sigaction(SIGUSR2, &sigact, NULL);
+       sigact.sa_handler = exit_sigterm;
+       sigaction(SIGINT, &sigact, NULL);
+       sigaction(SIGTERM, &sigact, NULL);
+       memset(&sigact, 0, sizeof(struct sigaction));
+
+       tfc_getcurtime(&delta_time);
+
+       if (sksum_hashlist_file) {
+               FILE *f;
+               char *s, *d, *t, *shash, *fname;
+               int failed = 0, totaltested = 0;
+
+               if (!strcmp(sksum_hashlist_file, "-")) f = stdin;
+               else f = fopen(sksum_hashlist_file, "r");
+               if (!f) xerror(NO, NO, YES, "%s", sksum_hashlist_file);
+
+               while (1) {
+                       memset(sksblk, 0, sizeof(sksblk));
+                       x = xfgets(sksblk, sizeof(sksblk), f);
+                       if (x == 0) break;
+
+                       s = d = sksblk; t = NULL;
+                       shash = fname = NULL;
+                       while ((s = strtok_r(d, "\t", &t))) {
+                               if (d) d = NULL;
+
+                               if (!shash) shash = s;
+                               else if (shash && !fname) fname = s;
+                       }
+
+                       if (!shash || !fname) {
+                               xerror(YES, NO, YES, "invalid string %s", sksblk);
+                               exitcode = 2;
+                               continue;
+                       }
+
+                       s = strchr(shash, ' ');
+                       if (s && s[1] == ' ') *s = 0;
+
+                       fd = open(fname, O_RDONLY | O_LARGEFILE);
+                       if (fd == -1) {
+                               xerror(YES, NO, YES, "%s", fname);
+                               exitcode = 1;
+                               continue;
+                       }
+
+                       if (status_timer) setup_next_alarm(status_timer);
+                       if (skeinfd(hash, bits, mackey_opt ? mackey : NULL, fd, maxlen) != YES) {
+                               xerror(YES, NO, YES, "%s", fname);
+                               exitcode = 1;
+                               continue;
+                       }
+                       xclose(fd);
+                       if (sksum_turns > 1) {
+                               size_t y;
+                               for (y = 0; y < sksum_turns; y++)
+                                       skein(hash, bits, mackey_opt ? mackey : NULL, hash, TF_FROM_BITS(bits));
+                       }
+                       if (isbase64(shash)) base64_decode(tmp, sizeof(tmp), shash, strlen(shash));
+                       else hex2bin(tmp, shash);
+
+                       if (!memcmp(hash, tmp, TF_FROM_BITS(bits))) {
+                               tfc_say("%s: OK", fname);
+                       }
+                       else {
+                               tfc_say("%s: FAILED", fname);
+                               failed++;
+                       }
+                       memset(tmp, 0, sizeof(tmp));
+                       memset(sksblk, 0, sizeof(sksblk));
+                       totaltested++;
+               }
+
+               fclose(f);
+               if (failed) {
+                       tfc_esay("%s: WARNING: %u of %u computed checksums did NOT match",
+                               progname, failed, totaltested);
+                       exitcode = 1;
+               }
+               xexit(exitcode);
+       }
+
+       for (xx = 0; fargv[xx]; xx++);
+       if (xx == 0) {
+               fd = 0;
+               x = 0;
+               goto _dohash;
+       }
+
+       for (x = 0; fargv[x] && xx; x++) {
+               if (!strcmp(fargv[x], "-")) fd = 0;
+               else fd = open(fargv[x], O_RDONLY | O_LARGEFILE);
+               if (fd == -1) {
+                       xerror(YES, NO, YES, "%s", fargv[x]);
+                       exitcode = 1;
+                       continue;
+               }
+
+_dohash:       if (status_timer) setup_next_alarm(status_timer);
+               if (skeinfd(hash, bits, mackey_opt ? mackey : NULL, fd, maxlen) != YES) {
+                       xerror(YES, NO, YES, "%s", fargv[x]);
+                       exitcode = 1;
+                       continue;
+               }
+               xclose(fd);
+               if (sksum_turns > 1) {
+                       size_t y;
+                       for (y = 0; y < sksum_turns; y++) skein(hash, bits, mackey_opt ? mackey : NULL, hash, TF_FROM_BITS(bits));
+               }
+               if (do_outfmt == TFC_OUTFMT_B64) tfc_printbase64(stdout, hash, TF_FROM_BITS(bits), 0);
+               else if (do_outfmt == TFC_OUTFMT_RAW) write(1, hash, TF_FROM_BITS(bits));
+               else mhexdump(hash, TF_FROM_BITS(bits), TF_FROM_BITS(bits), 0);
+               if (do_outfmt != TFC_OUTFMT_RAW) {
+                       if (quiet == NO || xx > 1) tfc_say("\t%s", fargv[x] ? fargv[x] : "-");
+                       else tfc_say("\n");
+               }
+       }
+
+       memset(hash, 0, SKEIN_DIGEST_SIZE);
+       xexit(exitcode);
+}
diff --git a/tfc_vars.c b/tfc_vars.c
new file mode 100644 (file)
index 0000000..7f78b84
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+char *progname;
+int exitcode;
+
+size_t nr_turns = TFC_NR_TURNS;
+int ctr_mode = TFC_CTR_MODE;
+size_t macbits = TF_MAX_BITS;
+
+tfc_byte key[TF_KEY_SIZE], ctr[TF_BLOCK_SIZE], xtskey[TF_KEY_SIZE], mackey[TF_FROM_BITS(TF_MAX_BITS)];
+struct skein sk;
+struct tfe_stream tfe;
+tfc_byte srcblk[TFC_BLKSIZE], dstblk[TFC_BLKSIZE], *pblk;
+tfc_byte macvrfy[SKEIN_DIGEST_SIZE], macresult[SKEIN_DIGEST_SIZE];
+tfc_byte tmpdata[TFC_TMPSIZE];
+
+char *randsource = TFC_DEFAULT_RANDSOURCE;
+
+tfc_fsize iseek_blocks, iseek, oseek, maxlen = NOFSIZE;
+tfc_fsize total_processed_src, total_processed_dst;
+tfc_fsize delta_processed;
+tfc_fsize genrandom_nr_bytes, genzero_nr_bytes;
+int sfd, kfd = -1, dfd = 1;
+struct stat s_stat;
+size_t blksize = TFC_BLKSIZE, xtsblocks = TFC_XTSBLOCKS;
+char pwdask[512], pwdagain[512];
+
+size_t lio, lrem, ldone, lblock;
+size_t maxkeylen = NOSIZE, ctrsz = NOSIZE;
+
+struct sigaction sigact;
+
+size_t sksum_turns;
+
+int do_edcrypt = TFC_DO_ENCRYPT, do_stop, quiet, error_action;
+int counter_opt, mackey_opt, do_mac, do_outfmt = TFC_OUTFMT_B64, rawkey;
+int idx, write_flags;
+tfc_yesno catch_all_errors, password, overwrite_source, do_fsync, do_pad, do_tfcrypt1;
+tfc_yesno do_preserve_time, do_stats_in_gibs, do_statline_dynamic = YES, do_less_stats;
+tfc_yesno no_repeat, do_full_hexdump = YES, verbose, statline_was_shown;
+char *srcfname = TFC_STDIN_NAME, *dstfname = TFC_STDOUT_NAME, *do_mac_file, *counter_file, *sksum_hashlist_file;
+char *genkeyf, *mackeyf, *tweakf;
+char *pw_prompt, *mac_pw_prompt;
+tfc_useconds status_timer, bench_timer;
+tfc_useconds current_time, delta_time;
+
+struct getpasswd_state getps;
diff --git a/tfcbc.c b/tfcbc.c
new file mode 100644 (file)
index 0000000..2d47fe8
--- /dev/null
+++ b/tfcbc.c
@@ -0,0 +1,88 @@
+#include <string.h>
+#include "tfdef.h"
+
+void tf_cbc_encrypt(const void *key, void *iv, void *out, const void *in, size_t sz)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE *uiv = iv;
+       const TF_UNIT_TYPE *ukey = key;
+       size_t sl = sz, i;
+
+       if (sl >= TF_BLOCK_SIZE) {
+               do {
+                       memcpy(x, uin, TF_BLOCK_SIZE);
+                       uin += TF_BLOCK_SIZE;
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] = x[i] ^ uiv[i];
+                       tf_encrypt_rawblk(x, y, ukey);
+                       memcpy(iv, x, TF_BLOCK_SIZE);
+
+                       data_to_words(x, TF_BLOCK_SIZE);
+                       memcpy(uout, x, TF_BLOCK_SIZE);
+                       uout += TF_BLOCK_SIZE;
+               } while ((sl -= TF_BLOCK_SIZE) >= TF_BLOCK_SIZE);
+       }
+
+       if (sl) {
+               memset(x, 0, TF_BLOCK_SIZE);
+               memcpy(x, uin, sl);
+               data_to_words(x, TF_BLOCK_SIZE);
+
+               ctr_inc(uiv, TF_NR_BLOCK_UNITS);
+               tf_encrypt_rawblk(y, uiv, ukey);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= x[i];
+
+               data_to_words(y, TF_BLOCK_SIZE);
+               memcpy(uout, y, sl);
+       }
+
+       memset(x, 0, TF_BLOCK_SIZE);
+       memset(y, 0, TF_BLOCK_SIZE);
+}
+
+void tf_cbc_decrypt(const void *key, void *iv, void *out, const void *in, size_t sz)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS], t[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE *uiv = iv;
+       const TF_UNIT_TYPE *ukey = key;
+       size_t sl = sz, i;
+
+       if (sl >= TF_BLOCK_SIZE) {
+               do {
+                       memcpy(x, uin, TF_BLOCK_SIZE);
+                       uin += TF_BLOCK_SIZE;
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       memcpy(t, x, TF_BLOCK_SIZE);
+                       tf_decrypt_rawblk(y, x, ukey);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= uiv[i];
+                       memcpy(iv, t, TF_BLOCK_SIZE);
+
+                       data_to_words(y, TF_BLOCK_SIZE);
+                       memcpy(uout, y, TF_BLOCK_SIZE);
+                       uout += TF_BLOCK_SIZE;
+               } while ((sl -= TF_BLOCK_SIZE) >= TF_BLOCK_SIZE);
+       }
+
+       if (sl) {
+               memset(x, 0, TF_BLOCK_SIZE);
+               memcpy(x, uin, sl);
+               data_to_words(x, TF_BLOCK_SIZE);
+
+               ctr_inc(uiv, TF_NR_BLOCK_UNITS);
+               tf_encrypt_rawblk(y, uiv, ukey);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= x[i];
+
+               data_to_words(y, TF_BLOCK_SIZE);
+               memcpy(uout, y, sl);
+       }
+
+       memset(t, 0, TF_BLOCK_SIZE);
+       memset(x, 0, TF_BLOCK_SIZE);
+       memset(y, 0, TF_BLOCK_SIZE);
+}
diff --git a/tfcore.h b/tfcore.h
new file mode 100644 (file)
index 0000000..d6247bc
--- /dev/null
+++ b/tfcore.h
@@ -0,0 +1,86 @@
+#ifndef _THREEFISH_CIPHER_CORE_HEADER
+#define _THREEFISH_CIPHER_CORE_HEADER
+
+#ifndef _THREEFISH_CIPHER_DEFINITIONS_HEADER
+#error Threefish definitions header is required! Include tfdef.h first.
+#endif
+
+#define ROL(x, s, max) ((x << s) | (x >> (-s & (max-1))))
+#define ROR(x, s, max) ((x >> s) | (x << (-s & (max-1))))
+
+#define KE_MIX(x, y, k1, k2, sl)                               \
+       do {                                                    \
+               x += k1;                                        \
+               y += x;                                         \
+               y += k2;                                        \
+               x = ROL(x, sl, TF_UNIT_BITS);                   \
+               x ^= y;                                         \
+       } while (0)
+
+#define BE_MIX(x, y, sl)                                       \
+       do {                                                    \
+               x += y;                                         \
+               y = ROL(y, sl, TF_UNIT_BITS);                   \
+               y ^= x;                                         \
+       } while (0)
+
+#define KD_MIX(x, y, k1, k2, sr)                               \
+       do {                                                    \
+               x ^= y;                                         \
+               x = ROR(x, sr, TF_UNIT_BITS);                   \
+               y -= x;                                         \
+               y -= k2;                                        \
+               x -= k1;                                        \
+       } while (0)
+
+#define BD_MIX(x, y, sr)                                       \
+       do {                                                    \
+               y ^= x;                                         \
+               y = ROR(y, sr, TF_UNIT_BITS);                   \
+               x -= y;                                         \
+       } while (0)
+
+#define THREEFISH_CONST 0x1bd11bdaa9fc1a22ULL
+
+#if defined(TF_256BITS)
+enum tf_rotations {
+       TFS_KS01 = 14, TFS_KS02 = 16, TFS_KS03 = 25, TFS_KS04 = 33,
+       TFS_BS01 = 52, TFS_BS02 = 57, TFS_BS03 = 23, TFS_BS04 = 40,
+       TFS_BS05 =  5, TFS_BS06 = 37, TFS_BS07 = 46, TFS_BS08 = 12,
+       TFS_BS09 = 58, TFS_BS10 = 22, TFS_BS11 = 32, TFS_BS12 = 32,
+};
+#elif defined(TF_512BITS)
+enum tf_rotations {
+       TFS_KS01 = 46, TFS_KS02 = 36, TFS_KS03 = 19, TFS_KS04 = 37,
+       TFS_KS05 = 39, TFS_KS06 = 30, TFS_KS07 = 34, TFS_KS08 = 24,
+       TFS_BS01 = 33, TFS_BS02 = 27, TFS_BS03 = 14, TFS_BS04 = 42,
+       TFS_BS05 = 17, TFS_BS06 = 49, TFS_BS07 = 36, TFS_BS08 = 39,
+       TFS_BS09 = 44, TFS_BS10 =  9, TFS_BS11 = 54, TFS_BS12 = 56,
+       TFS_BS13 = 13, TFS_BS14 = 50, TFS_BS15 = 10, TFS_BS16 = 17,
+       TFS_BS17 = 25, TFS_BS18 = 29, TFS_BS19 = 39, TFS_BS20 = 43,
+       TFS_BS21 =  8, TFS_BS22 = 35, TFS_BS23 = 56, TFS_BS24 = 22,
+};
+#elif defined(TF_1024BITS)
+enum tf_rotations {
+       TFS_KS01 = 24, TFS_KS02 = 13, TFS_KS03 =  8, TFS_KS04 = 47,
+       TFS_KS05 =  8, TFS_KS06 = 17, TFS_KS07 = 22, TFS_KS08 = 37,
+       TFS_KS09 = 41, TFS_KS10 =  9, TFS_KS11 = 37, TFS_KS12 = 31,
+       TFS_KS13 = 12, TFS_KS14 = 47, TFS_KS15 = 44, TFS_KS16 = 30,
+       TFS_BS01 = 38, TFS_BS02 = 19, TFS_BS03 = 10, TFS_BS04 = 55,
+       TFS_BS05 = 49, TFS_BS06 = 18, TFS_BS07 = 23, TFS_BS08 = 52,
+       TFS_BS09 = 33, TFS_BS10 =  4, TFS_BS11 = 51, TFS_BS12 = 13,
+       TFS_BS13 = 34, TFS_BS14 = 41, TFS_BS15 = 59, TFS_BS16 = 17,
+       TFS_BS17 =  5, TFS_BS18 = 20, TFS_BS19 = 48, TFS_BS20 = 41,
+       TFS_BS21 = 47, TFS_BS22 = 28, TFS_BS23 = 16, TFS_BS24 = 25,
+       TFS_BS25 = 16, TFS_BS26 = 34, TFS_BS27 = 56, TFS_BS28 = 51,
+       TFS_BS29 =  4, TFS_BS30 = 53, TFS_BS31 = 42, TFS_BS32 = 41,
+       TFS_BS33 = 31, TFS_BS34 = 44, TFS_BS35 = 47, TFS_BS36 = 46,
+       TFS_BS37 = 19, TFS_BS38 = 42, TFS_BS39 = 44, TFS_BS40 = 25,
+       TFS_BS41 =  9, TFS_BS42 = 48, TFS_BS43 = 35, TFS_BS44 = 52,
+       TFS_BS45 = 23, TFS_BS46 = 31, TFS_BS47 = 37, TFS_BS48 = 20,
+};
+#else
+#error No cipher was defined! Aborting build.
+#endif
+
+#endif
diff --git a/tfcrypt.c b/tfcrypt.c
new file mode 100644 (file)
index 0000000..dcf9ea9
--- /dev/null
+++ b/tfcrypt.c
@@ -0,0 +1,1177 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "tfcrypt.h"
+
+static int getps_filter(struct getpasswd_state *getps, char chr, size_t pos)
+{
+       if (chr == '\x03') {
+               getps->retn = ((size_t)-2);
+               return 6;
+       }
+       return 1;
+}
+
+static int getps_hex_filter(struct getpasswd_state *getps, char chr, size_t pos)
+{
+       if (chr == '\x03') {
+               getps->retn = ((size_t)-2);
+               return 6;
+       }
+       if (chr >= '0' && chr <= '9') return 1;
+       if (chr >= 'a' && chr <= 'f') return 1;
+       if (chr >= 'A' && chr <= 'F') return 1;
+       if (chr == '\x7f' || chr == '\x08'
+       || chr == '\x15' || chr == '\x17') return 1;
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int c;
+       double td;
+       char *s, *d, *t, *stoi;
+       size_t x, n;
+
+       progname = basename(argv[0]);
+
+       if (!isatty(2)) do_statline_dynamic = NO;
+
+       opterr = 0;
+       while ((c = getopt(argc, argv, "aU:C:r:K:t:TPkzxc:l:qedn:vV:pwE:O:S:AmM:R:Z:WHD:")) != -1) {
+               switch (c) {
+                       case 'r':
+                               randsource = optarg;
+                               break;
+                       case 'c':
+                               if (!strcasecmp(optarg, "show"))
+                                       counter_opt = TFC_CTR_SHOW;
+                               else if (!strcasecmp(optarg, "head"))
+                                       counter_opt = TFC_CTR_HEAD;
+                               else if (!strcasecmp(optarg, "rand"))
+                                       counter_opt = TFC_CTR_RAND;
+                               else counter_file = sksum_hashlist_file = optarg;
+                               break;
+                       case 'C':
+                               if (!strcasecmp(optarg, "ctr"))
+                                       ctr_mode = TFC_MODE_CTR;
+                               else if (!strcasecmp(optarg, "stream"))
+                                       ctr_mode = TFC_MODE_STREAM;
+                               else if (!strcasecmp(optarg, "cbc"))
+                                       ctr_mode = TFC_MODE_CBC;
+                               else if (!strcasecmp(optarg, "ecb"))
+                                       ctr_mode = TFC_MODE_ECB;
+                               else if (!strcasecmp(optarg, "xts"))
+                                       ctr_mode = TFC_MODE_XTS;
+                               else if (!strcasecmp(optarg, "ocb"))
+                                       ctr_mode = TFC_MODE_OCB;
+                               else xerror(NO, YES, YES, "%s: invalid mode of operation", optarg);
+                               break;
+                       case 'P':
+                               do_edcrypt = TFC_DO_PLAIN;
+                               password = YES;
+                               ctr_mode = TFC_MODE_PLAIN;
+                               break;
+                       case 'e':
+                               do_edcrypt = TFC_DO_ENCRYPT;
+                               break;
+                       case 'd':
+                               do_edcrypt = TFC_DO_DECRYPT;
+                               break;
+                       case 'D':
+                               macbits = strtoul(optarg, &stoi, 10);
+                               if (macbits == 0 || !str_empty(stoi) || macbits < 8
+                               || macbits > TF_MAX_BITS || macbits % 8)
+                                       xerror(NO, YES, YES, "%s: invalid MAC bits setting", optarg);
+                               break;
+                       case 'n':
+                               nr_turns = sksum_turns = strtoul(optarg, &stoi, 10);
+                               if (!str_empty(stoi)) xerror(NO, YES, YES, "%s: invalid number of turns", optarg);
+                               break;
+                       case 'U':
+                               if (!strcasecmp(optarg, "key"))
+                                       mackey_opt = TFC_MACKEY_RAWKEY;
+                               else if (!strcasecmp(optarg, "pwd"))
+                                       mackey_opt = TFC_MACKEY_PASSWORD;
+                               else {
+                                       mackey_opt = TFC_MACKEY_FILE;
+                                       mackeyf = optarg;
+                               }
+                               break;
+                       case 'p':
+                               password = YES;
+                               break;
+                       case 'k':
+                               rawkey = TFC_RAWKEY_KEYFILE;
+                               break;
+                       case 'z':
+                               rawkey = TFC_RAWKEY_ASKSTR;
+                               break;
+                       case 'x':
+                               rawkey = TFC_RAWKEY_ASKHEX;
+                               break;
+                       case 'K':
+                               verbose = YES;
+                               genkeyf = optarg;
+                               break;
+                       case 't':
+                               tweakf = optarg;
+                               break;
+                       case 'T':
+                               do_tfcrypt1 = YES;
+                               break;
+                       case 'l':
+                               if (maxlen != NOFSIZE) break;
+
+                               maxlen = tfc_humanfsize(optarg, &stoi);
+                               if (!str_empty(stoi)) {
+                                       maxlen = tfc_fnamesize(optarg, YES);
+                                       maxlen = tfc_modifysize(maxlen, strchr(optarg, ':'));
+                                       if (maxlen == NOFSIZE) xerror(NO, YES, YES,
+                                       "%s: invalid count value", optarg);
+                               }
+                               else maxlen = tfc_modifysize(maxlen, strchr(optarg, ':'));
+                               if (counter_opt == TFC_CTR_HEAD)
+                                       maxlen += TF_BLOCK_SIZE;
+                               break;
+                       case 'w':
+                               overwrite_source = YES;
+                               break;
+                       case 'E':
+                               if (!strcmp(optarg, "xall")) {
+                                       catch_all_errors = YES;
+                                       break;
+                               }
+                               if (!strcmp(optarg, "exit"))
+                                       error_action = TFC_ERRACT_EXIT;
+                               else if (!strncmp(optarg, "cont", 4))
+                                       error_action = TFC_ERRACT_CONT;
+                               else if (!strcmp(optarg, "sync"))
+                                       error_action = TFC_ERRACT_SYNC;
+                               else xerror(NO, YES, YES, "invalid error action %s specified", optarg);
+                               break;
+                       case 'O':
+                               s = d = optarg; t = NULL;
+                               while ((s = strtok_r(d, ",", &t))) {
+                                       if (d) d = NULL;
+                                       if (!strcmp(s, "sync"))
+                                               write_flags |= O_SYNC;
+                                       else if (!strcmp(s, "trunc"))
+                                               write_flags |= O_TRUNC;
+                                       else if (!strcmp(s, "fsync"))
+                                               do_fsync = YES;
+                                       else if (!strcmp(s, "pad"))
+                                               do_pad = YES;
+                                       else if (!strcmp(s, "xtime"))
+                                               do_preserve_time = YES;
+                                       else if (!strcmp(s, "gibsize"))
+                                               do_stats_in_gibs = YES;
+                                       else if (!strcmp(s, "plainstats"))
+                                               do_statline_dynamic = NO;
+                                       else if (!strcmp(s, "statless"))
+                                               do_less_stats = YES;
+                                       else if (!strcmp(s, "norepeat"))
+                                               no_repeat = YES;
+                                       else if (!strncmp(s, "prompt", 6) && *(s+6) == '=')
+                                               pw_prompt = s+7;
+                                       else if (!strncmp(s, "macprompt", 9) && *(s+9) == '=')
+                                               mac_pw_prompt = s+10;
+                                       else if (!strcmp(s, "shorthex"))
+                                               do_full_hexdump = NO;
+                                       else if (!strncmp(s, "iobs", 4) && *(s+4) == '=') {
+                                               s += 5;
+                                               blksize = (size_t)tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       blksize = (size_t)tfc_fnamesize(s, YES);
+                                                       blksize = (size_t)tfc_modifysize((tfc_fsize)blksize, strchr(s, ':'));
+                                                       if (blksize == NOSIZE) xerror(NO, YES, YES,
+                                                       "%s: invalid block size value", s);
+                                               }
+                                               else blksize = (size_t)tfc_modifysize((tfc_fsize)blksize, strchr(s, ':'));
+                                               if (blksize < TF_BLOCK_SIZE) xerror(NO, YES, YES,
+                                                       "%s: block size is lesser than TF_BLOCK_SIZE (%u bytes)", s, TFC_U(TF_BLOCK_SIZE));
+                                               if (blksize > TFC_BLKSIZE) xerror(NO, YES, YES,
+                                                       "%s: block size exceeds %u bytes",
+                                                       s, TFC_U(TFC_BLKSIZE));
+                                       }
+                                       else if (!strncmp(s, "xtsblocks", 9) && *(s+9) == '=') {
+                                               s += 10;
+                                               xtsblocks = (size_t)tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       xtsblocks = (size_t)tfc_fnamesize(s, YES);
+                                                       xtsblocks = (size_t)tfc_modifysize((tfc_fsize)xtsblocks, strchr(s, ':'));
+                                                       if (xtsblocks == NOSIZE) xerror(NO, YES, YES,
+                                                       "%s: invalid blocks per xts block value", s);
+                                               }
+                                               else xtsblocks = (size_t)tfc_modifysize((tfc_fsize)xtsblocks, strchr(s, ':'));
+                                               if (TFC_BLKSIZE % xtsblocks) xerror(NO, YES, YES,
+                                                       "%s: nr of blocks per xts block is not round to %u bytes",
+                                                       s, TFC_U(TFC_BLKSIZE));
+                                               if ((xtsblocks * TF_BLOCK_SIZE) > TFC_BLKSIZE) xerror(NO, YES, YES,
+                                                       "%s: nr of blocks per xts block exceeds %u bytes",
+                                                       s, TFC_U(TFC_BLKSIZE));
+                                       }
+                                       else if (!strncmp(s, "iseek", 5) && *(s+5) == '=') {
+                                               s += 6;
+                                               iseek = tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       iseek = tfc_fnamesize(s, YES);
+                                                       iseek = tfc_modifysize(iseek, strchr(s, ':'));
+                                                       if (iseek == NOFSIZE) xerror(NO, YES, YES,
+                                                       "%s: invalid iseek value", s);
+                                               }
+                                               else iseek = tfc_modifysize(iseek, strchr(s, ':'));
+                                               if (ctr_mode != TFC_MODE_PLAIN && iseek % TF_BLOCK_SIZE)
+                                                       xerror(NO, YES, YES,
+                                                               "%s: not round to TF block size "
+                                                               "of %u bytes",
+                                                               s, TFC_U(TF_BLOCK_SIZE));
+                                               iseek_blocks = iseek / TF_BLOCK_SIZE;
+                                       }
+                                       else if (!strncmp(s, "ixseek", 6) && *(s+6) == '=') {
+                                               s += 7;
+                                               iseek = tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       iseek = tfc_fnamesize(s, YES);
+                                                       iseek = tfc_modifysize(iseek, strchr(s, ':'));
+                                                       if (iseek == NOFSIZE) xerror(NO, YES, YES,
+                                                               "%s: invalid ixseek value", s);
+                                               }
+                                               else iseek = tfc_modifysize(iseek, strchr(s, ':'));
+                                       }
+                                       else if (!strncmp(s, "ictr", 4) && *(s+4) == '=') {
+                                               s += 5;
+                                               iseek_blocks = tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       iseek_blocks = tfc_fnamesize(s, YES);
+                                                       if (iseek_blocks == NOFSIZE)
+                                                               xerror(NO, YES, YES,
+                                                               "%s: invalid ictr value", s);
+                                                       iseek_blocks /= TF_BLOCK_SIZE;
+                                                       iseek_blocks = tfc_modifysize(iseek_blocks, strchr(s, ':'));
+                                               }
+                                               else iseek_blocks = tfc_modifysize(iseek_blocks, strchr(s, ':'));
+                                       }
+                                       else if (!strncmp(s, "ixctr", 5) && *(s+5) == '=') {
+                                               s += 6;
+                                               iseek_blocks = tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       iseek_blocks = tfc_fnamesize(s, YES);
+                                                       iseek_blocks = tfc_modifysize(iseek_blocks, strchr(s, ':'));
+                                                       if (iseek_blocks == NOFSIZE)
+                                                               xerror(NO, YES, YES,
+                                                               "%s: invalid ixctr value", s);
+                                               }
+                                               else iseek_blocks = tfc_modifysize(iseek_blocks, strchr(s, ':'));
+                                               if (iseek_blocks % TF_BLOCK_SIZE)
+                                                       xerror(NO, YES, YES,
+                                                       "%s: not round to TF block size "
+                                                       "of %u bytes", s, TFC_U(TF_BLOCK_SIZE));
+                                               iseek_blocks /= TF_BLOCK_SIZE;
+                                       }
+                                       else if (!strncmp(s, "oseek", 5) && *(s+5) == '=') {
+                                               s += 6;
+                                               oseek = tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       oseek = tfc_fnamesize(s, YES);
+                                                       oseek = tfc_modifysize(oseek, strchr(s, ':'));
+                                                       if (oseek == NOFSIZE) xerror(NO, YES, YES,
+                                                       "%s: invalid oseek value", s);
+                                               }
+                                               else oseek = tfc_modifysize(oseek, strchr(s, ':'));
+                                       }
+                                       else if (!strncmp(s, "count", 5) && *(s+5) == '=') {
+                                               s += 6;
+                                               maxlen = tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       maxlen = tfc_fnamesize(s, YES);
+                                                       maxlen = tfc_modifysize(maxlen, strchr(s, ':'));
+                                                       if (maxlen == NOFSIZE) xerror(NO, YES, YES,
+                                                       "%s: invalid count value", s);
+                                               }
+                                               else maxlen = tfc_modifysize(maxlen, strchr(s, ':'));
+                                               if (counter_opt == TFC_CTR_HEAD)
+                                                       maxlen += TF_BLOCK_SIZE;
+                                       }
+                                       else if (!strncmp(s, "xkey", 4) && *(s+4) == '=') {
+                                               s += 5;
+                                               maxkeylen = tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       maxkeylen = (size_t)tfc_fnamesize(s, YES);
+                                                       maxkeylen = (size_t)tfc_modifysize((tfc_fsize)maxkeylen, strchr(s, ':'));
+                                                       if (maxkeylen == NOSIZE)
+                                                               xerror(NO, YES, YES,
+                                                               "%s: invalid key length value", s);
+                                               }
+                                               else maxkeylen = (size_t)tfc_modifysize((tfc_fsize)maxkeylen, strchr(s, ':'));
+                                       }
+                                       else if (!strncmp(s, "xctr", 4) && *(s+4) == '=') {
+                                               s += 5;
+                                               ctrsz = tfc_humanfsize(s, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       ctrsz = (size_t)tfc_fnamesize(s, YES);
+                                                       ctrsz = (size_t)tfc_modifysize((tfc_fsize)ctrsz, strchr(s, ':'));
+                                                       if (ctrsz == NOSIZE)
+                                                               xerror(NO, YES, YES,
+                                                               "%s: invalid counter length value", s);
+                                               }
+                                               else ctrsz = (size_t)tfc_modifysize((tfc_fsize)ctrsz, strchr(s, ':'));
+                                               if (ctrsz > TF_BLOCK_SIZE)
+                                                       xerror(NO, YES, YES, "%s: counter size cannot exceed TF block size", s);
+                                       }
+                                       else xerror(NO, YES, YES, "invalid option %s", s);
+                               }
+                               break;
+                       case 'S':
+                               do_mac = TFC_MAC_SIGN;
+                               if (strcasecmp(optarg, "mac") != 0)
+                                       do_mac_file = optarg;
+                               break;
+                       case 'M':
+                               do_mac = TFC_MAC_VRFY;
+                               if (!strcasecmp(optarg, "drop"))
+                                       do_mac = TFC_MAC_DROP;
+                               else if (strcasecmp(optarg, "mac") != 0)
+                                       do_mac_file = optarg;
+                               break;
+                       case 'm':
+                               if (do_mac != TFC_MAC_VRFY)
+                                       xerror(NO, YES, YES, "signature source was not specified");
+                               do_mac = TFC_MAC_JUST_VRFY;
+                               break;
+                       case 'R':
+                       case 'Z':
+                               if (maxlen != NOFSIZE) {
+                                       if (c == 'Z') genzero_nr_bytes = maxlen;
+                                       else genrandom_nr_bytes = maxlen;
+                               }
+                               else {
+                                       tfc_fsize t;
+                                       if (!strcasecmp(optarg, "cbs"))
+                                               t = TF_BLOCK_SIZE;
+                                       else if (!strcasecmp(optarg, "ks"))
+                                               t = TF_FROM_BITS(TFC_KEY_BITS);
+                                       else if (!strcasecmp(optarg, "xks"))
+                                               t = TF_FROM_BITS(TFC_KEY_BITS) * 2;
+                                       else if (!strcasecmp(optarg, "iobs"))
+                                               t = blksize;
+                                       else {
+                                               t = tfc_humanfsize(optarg, &stoi);
+                                               if (!str_empty(stoi)) {
+                                                       t = tfc_fnamesize(optarg, NO);
+                                                       t = tfc_modifysize(t, strchr(optarg, ':'));
+                                               }
+                                               else t = tfc_modifysize(t, strchr(optarg, ':'));
+                                       }
+                                       if (c == 'Z') genzero_nr_bytes = maxlen = t;
+                                       else genrandom_nr_bytes = maxlen = t;
+                               }
+                               break;
+                       case 'a':
+                               do_preserve_time = YES;
+                               break;
+                       case 'A':
+                               do_outfmt = TFC_OUTFMT_B64;
+                               break;
+                       case 'W':
+                               do_outfmt = TFC_OUTFMT_RAW;
+                               break;
+                       case 'H':
+                               do_outfmt = TFC_OUTFMT_HEX;
+                               break;
+                       case 'q':
+                               quiet = YES;
+                               verbose = NO;
+                               status_timer = 0;
+                               break;
+                       case 'v':
+                               verbose = YES;
+                               break;
+                       case 'V':
+                               td = strtod(optarg, &stoi);
+                               status_timer = TFC_DTOUSECS(td);
+                               if (status_timer <= TFC_DTOUSECS(0) || !str_empty(stoi)) status_timer = 0;
+                               break;
+                       default:
+                               usage();
+                               break;
+               }
+       }
+
+       if (!strcmp(progname, "tfbench")) {
+               if (!*(argv+optind)) usage();
+
+               td = strtod(*(argv+optind), &stoi);
+               if (td <= TFC_DTOUSECS(0) || !str_empty(stoi))
+                       xerror(NO, YES, YES,
+                       "%s: invalid benchmark time in seconds", *(argv+optind));
+               bench_timer = TFC_DTOUSECS(td);
+               do_benchmark(bench_timer, td);
+       }
+       if (genrandom_nr_bytes) {
+               ctr_mode = TFC_MODE_STREAM;
+               do_edcrypt = TFC_DO_ENCRYPT;
+               gen_write_bytes(*(argv+optind), oseek, genrandom_nr_bytes);
+       }
+       if (genzero_nr_bytes) {
+               ctr_mode = TFC_MODE_PLAIN;
+               do_edcrypt = TFC_DO_PLAIN;
+               gen_write_bytes(*(argv+optind), oseek, genzero_nr_bytes);
+       }
+
+       if (rawkey && password)
+               xerror(NO, YES, YES, "Cannot use rawkey and hashing password!");
+       if (do_edcrypt == TFC_DO_ENCRYPT && do_mac >= TFC_MAC_VRFY)
+               xerror(NO, YES, YES, "Cannot encrypt and verify signature!");
+       if (do_edcrypt == TFC_DO_DECRYPT && do_mac == TFC_MAC_SIGN)
+               xerror(NO, YES, YES, "Cannot decrypt and calculate signature!");
+       if (do_edcrypt == TFC_DO_DECRYPT && counter_opt == TFC_CTR_RAND)
+               xerror(NO, YES, YES, "Cannot decrypt and embed a generated CTR into file!");
+       if (do_edcrypt == TFC_DO_ENCRYPT && counter_opt == TFC_CTR_HEAD)
+               xerror(NO, YES, YES, "Cannot encrypt and read CTR from source!");
+       if (overwrite_source && counter_opt == TFC_CTR_RAND)
+               xerror(NO, YES, YES, "Cannot embed a CTR into file when overwriting it!");
+       if (tweakf && do_tfcrypt1 == NO)
+               xerror(NO, YES, YES, "Use -T with -t tweakfile to enable old tfcrypt mode!");
+       if (ctr_mode == TFC_MODE_PLAIN
+       && (do_edcrypt || do_mac || rawkey
+       || mackey_opt || counter_opt || counter_file))
+               xerror(NO, YES, YES, "Encryption facility is disabled when in plain IO mode.");
+
+       errno = 0;
+       do_stop = NO;
+
+       if (mackey_opt == TFC_MACKEY_FILE && mackeyf) {
+               int mkfd = -1;
+               tfc_yesno do_stop;
+
+               if (!strcmp(mackeyf, "-")) mkfd = 0;
+               else mkfd = open(mackeyf, O_RDONLY | O_LARGEFILE);
+               if (mkfd == -1) xerror(NO, NO, YES, "%s", mackeyf);
+
+               skein_init(&sk, TFC_KEY_BITS);
+
+               do_stop = NO;
+               while (1) {
+                       if (do_stop) break;
+                       pblk = tmpdata;
+                       ldone = 0;
+                       lrem = lblock = sizeof(tmpdata);
+_mkragain:             lio = read(mkfd, pblk, lrem);
+                       if (lio == 0) do_stop = YES;
+                       if (lio != NOSIZE) ldone += lio;
+                       else {
+                               if (errno != EIO && catch_all_errors != YES)
+                                       xerror(NO, NO, NO, "%s", mackeyf);
+                               switch (error_action) {
+                                       case TFC_ERRACT_CONT: xerror(YES, NO, NO, "%s", mackeyf); goto _mkragain; break;
+                                       case TFC_ERRACT_SYNC:
+                                               xerror(YES, NO, NO, "%s", mackeyf);
+                                               lio = ldone = lrem = lblock;
+                                               memset(tmpdata, 0, lio);
+                                               lseek(mkfd, lio, SEEK_CUR);
+                                               break;
+                                       default: xerror(NO, NO, NO, "%s", mackeyf); break;
+                               }
+                       }
+                       if (lio && lio < lrem) {
+                               pblk += lio;
+                               lrem -= lio;
+                               goto _mkragain;
+                       }
+
+                       skein_update(&sk, tmpdata, ldone);
+               }
+
+               skein_final(mackey, &sk);
+
+               xclose(mkfd);
+       }
+       else if (mackey_opt == TFC_MACKEY_PASSWORD) {
+               memset(&getps, 0, sizeof(struct getpasswd_state));
+               getps.fd = getps.efd = -1;
+               getps.passwd = pwdask;
+               getps.pwlen = sizeof(pwdask)-1;
+               getps.echo = mac_pw_prompt ? mac_pw_prompt : "Enter MAC password: ";
+               getps.charfilter = getps_filter;
+               getps.maskchar = 'x';
+               getps.flags = GETP_WAITFILL;
+               n = xgetpasswd(&getps);
+               if (n == NOSIZE) xerror(NO, NO, YES, "getting MAC password");
+               if (n == ((size_t)-2)) xexit(1);
+               skein(mackey, TF_MAX_BITS, NULL, pwdask, n);
+               if (verbose) {
+                       skein(tmpdata, TF_MAX_BITS, NULL, mackey, TF_FROM_BITS(TF_MAX_BITS));
+                       xor_shrink(tmpdata+TF_FROM_BITS(TF_MAX_BITS), TF_SIZE_UNIT, tmpdata, TF_FROM_BITS(TF_MAX_BITS));
+                       tfc_nfsay(stderr, "MAC password hint: ");
+                       mehexdump(tmpdata+TF_FROM_BITS(TF_MAX_BITS), TF_SIZE_UNIT, TF_SIZE_UNIT, 1);
+                       memset(tmpdata, 0, sizeof(tmpdata));
+               }
+       }
+
+       
+       if ((strlen(progname) <= 9)
+       && ((!strcmp(progname, "sksum"))
+       || ((!memcmp(progname, "sk", 2))
+       && (!memcmp(progname+3, "sum", 3)
+       || !memcmp(progname+4, "sum", 3)
+       || !memcmp(progname+5, "sum", 3)
+       || !memcmp(progname+6, "sum", 3)))))
+               do_sksum(progname, argv+optind);
+       if (!strcmp(progname, "tfbase64")) do_edbase64(argv+optind);
+
+       idx = optind;
+
+       if (argv[idx]) {
+               if (password || rawkey > TFC_RAWKEY_KEYFILE) goto _nokeyfd;
+               if (!strcmp(argv[idx], "-")) kfd = 0;
+               else kfd = open(argv[idx], O_RDONLY | O_LARGEFILE);
+               if (kfd == -1) xerror(NO, NO, YES, "%s", argv[idx]);
+
+               lio = strnlen(argv[idx], PATH_MAX);
+               memset(argv[idx], '*', lio);
+
+               idx++;
+       }
+       else password = YES;
+
+       errno = 0;
+       if (do_tfcrypt1 == YES && tweakf) {
+               int twfd;
+
+               if (!strcmp(tweakf, "-")) twfd = 0;
+               else twfd = open(tweakf, O_RDONLY | O_LARGEFILE);
+               if (twfd == -1) xerror(NO, NO, YES, "%s", tweakf);
+               lio = ldone = read(twfd, key+TF_FROM_BITS(TF_MAX_BITS)+TF_SIZE_UNIT, 2*TF_SIZE_UNIT);
+               if (lio == NOSIZE) xerror(NO, NO, YES, "%s", tweakf);
+               if (ldone < 2*TF_SIZE_UNIT)
+                       xerror(NO, NO, YES, "%s: %zu bytes tweak required", tweakf, 2*TF_SIZE_UNIT);
+               xclose(twfd);
+       }
+
+_nokeyfd:
+       errno = 0;
+       if (argv[idx]) {
+               if (!strcmp(argv[idx], "-") && kfd) sfd = 0;
+               else {
+                       sfd = open(argv[idx], O_RDONLY | O_LARGEFILE);
+                       if (do_preserve_time) if (fstat(sfd, &s_stat) == -1)
+                               xerror(YES, NO, YES, "stat(%s)", argv[idx]);
+               }
+               if (sfd == -1) xerror(NO, NO, YES, "%s", argv[idx]);
+
+               if (do_edcrypt == TFC_DO_DECRYPT && do_mac != NO && maxlen != NOFSIZE) {
+                       if (verbose) tfc_esay("%s: disabling signature verification on "
+                               "requested partial decryption.", progname);
+                       do_mac = NO;
+               }
+
+               if ((do_mac >= TFC_MAC_VRFY || do_mac == TFC_MAC_DROP) && !do_mac_file) {
+                       maxlen = tfc_fdsize(sfd);
+                       if (maxlen == NOFSIZE)
+                               xerror(NO, YES, YES,
+                               "Cannot verify embedded MAC with non-seekable source!");
+                       maxlen -= TF_FROM_BITS(macbits);
+               }
+               srcfname = argv[idx];
+               idx++;
+       }
+
+       if (!do_mac_file && (do_mac >= TFC_MAC_VRFY && sfd == 0))
+               xerror(NO, YES, YES, "Cannot verify embedded MAC with non-seekable source!");
+
+       if (ctrsz == NOSIZE) ctrsz = TF_BLOCK_SIZE;
+       if (ctrsz > TF_BLOCK_SIZE) ctrsz = TF_BLOCK_SIZE;
+
+       if (ctr_mode == TFC_MODE_ECB) goto _ctrskip1;
+       errno = 0;
+       if (counter_file) {
+               int ctrfd;
+
+               if (!strcmp(counter_file, "-")) ctrfd = 0;
+               else ctrfd = open(counter_file, O_RDONLY | O_LARGEFILE);
+               if (ctrfd == -1) xerror(NO, NO, YES, "%s", counter_file);
+               lio = read(ctrfd, ctr, ctrsz);
+               if (lio == NOSIZE) xerror(NO, NO, YES, "%s", counter_file);
+               if (lio < ctrsz) xerror(NO, YES, YES, "counter file is too small (%zu)!", lio);
+               xclose(ctrfd);
+       }
+       else if (counter_opt == TFC_CTR_HEAD) {
+               pblk = ctr;
+               ldone = 0;
+               lrem = lblock = ctrsz;
+_ctrragain:    lio = read(sfd, pblk, lrem);
+               if (lio != NOSIZE) ldone += lio;
+               else {
+                       if (errno != EIO && catch_all_errors != YES)
+                               xerror(NO, NO, NO, "%s", srcfname);
+                       switch (error_action) {
+                               case TFC_ERRACT_CONT: xerror(YES, NO, NO, "%s", srcfname); goto _ctrragain; break;
+                               case TFC_ERRACT_SYNC:
+                                       xerror(YES, NO, NO, "%s", srcfname);
+                                       lio = ldone = lrem = lblock;
+                                       memset(ctr, 0, lio);
+                                       lseek(sfd, lio, SEEK_CUR);
+                                       break;
+                               default: xerror(NO, NO, NO, "%s", srcfname); break;
+                       }
+               }
+               if (lio && lio < lrem) {
+                       pblk += lio;
+                       lrem -= lio;
+                       goto _ctrragain;
+               }
+               total_processed_src += ldone;
+       }
+
+_ctrskip1:
+       if (iseek) {
+               if (counter_opt == TFC_CTR_HEAD && ctr_mode != TFC_MODE_ECB)
+                       iseek += ctrsz;
+               if (lseek(sfd, iseek, SEEK_SET) == -1)
+                       xerror(YES, NO, NO, "%s: seek failed", srcfname);
+       }
+
+       if (ctr_mode == TFC_MODE_PLAIN) goto _plain;
+
+       if (verbose) tfc_esay("%s: hashing password", progname);
+
+       if (rawkey == TFC_RAWKEY_KEYFILE) {
+               tfc_yesno xtskeyset = NO;
+
+               pblk = key;
+_xts2key:      ldone = 0;
+               lrem = lblock = TF_FROM_BITS(TFC_KEY_BITS);
+_keyragain:    lio = read(kfd, pblk, lrem);
+               if (lio != NOSIZE) ldone += lio;
+               else {
+                       if (errno != EIO && catch_all_errors != YES)
+                               xerror(NO, NO, NO, "reading key");
+                       switch (error_action) {
+                               case TFC_ERRACT_CONT: xerror(YES, NO, NO, "reading key"); goto _keyragain; break;
+                               case TFC_ERRACT_SYNC:
+                                       xerror(YES, NO, NO, "reading key");
+                                       lio = ldone = lrem = lblock;
+                                       memset(key, 0, lio);
+                                       lseek(kfd, lio, SEEK_CUR);
+                                       break;
+                               default: xerror(NO, NO, NO, "reading key"); break;
+                       }
+               }
+               if (lio && lio < lrem) {
+                       pblk += lio;
+                       lrem -= lio;
+                       goto _keyragain;
+               }
+               if (ldone < lblock) xerror(NO, YES, YES, "rawkey too small! (%zu)", ldone);
+
+               if (ctr_mode == TFC_MODE_XTS) {
+                       if (xtskeyset == NO) {
+                               pblk = xtskey;
+                               xtskeyset = YES;
+                               goto _xts2key;
+                       }
+               }
+       }
+       else if (rawkey == TFC_RAWKEY_ASKSTR) {
+               tfc_yesno xtskeyset = NO;
+
+               pblk = key; n = sizeof(key);
+_xts2keyaskstr:        memset(&getps, 0, sizeof(struct getpasswd_state));
+               getps.fd = getps.efd = -1;
+               getps.passwd = (char *)pblk;
+               getps.pwlen = n;
+               getps.echo = pw_prompt ? pw_prompt : "Enter rawkey (str): ";
+               getps.charfilter = getps_filter;
+               getps.maskchar = 'x';
+               getps.flags = GETP_WAITFILL;
+               n = xgetpasswd(&getps);
+               if (n == NOSIZE) xerror(NO, NO, YES, "getting string rawkey");
+               if (n == ((size_t)-2)) xexit(1);
+               if (ctr_mode == TFC_MODE_XTS) {
+                       if (xtskeyset == NO) {
+                               pblk = xtskey; n = sizeof(xtskey);
+                               xtskeyset = YES;
+                               goto _xts2keyaskstr;
+                       }
+               }
+       }
+       else if (rawkey == TFC_RAWKEY_ASKHEX) {
+               tfc_yesno xtskeyset = NO;
+
+               pblk = key;
+_rawkey_hex_again:
+               memset(&getps, 0, sizeof(struct getpasswd_state));
+               getps.fd = getps.efd = -1;
+               getps.passwd = pwdask;
+               getps.pwlen = (TF_FROM_BITS(TFC_KEY_BITS)*2);
+               getps.echo = pw_prompt ? pw_prompt : "Enter rawkey (hex): ";
+               getps.charfilter = getps_hex_filter;
+               getps.maskchar = 'x';
+               getps.flags = GETP_WAITFILL;
+               n = xgetpasswd(&getps);
+               if (n == NOSIZE) xerror(NO, NO, YES, "getting hex rawkey");
+               if (n == ((size_t)-2)) xexit(1);
+               if (n % 2) {
+                       tfc_esay("Please input even number of hex digits!");
+                       goto _rawkey_hex_again;
+               }
+               hex2bin(pblk, pwdask);
+               memset(pwdask, 0, sizeof(pwdask));
+               if (ctr_mode == TFC_MODE_XTS) {
+                       if (xtskeyset == NO) {
+                               pblk = xtskey;
+                               xtskeyset = YES;
+                               goto _rawkey_hex_again;
+                       }
+               }
+       }
+       else if (password) {
+_pwdagain:     memset(&getps, 0, sizeof(struct getpasswd_state));
+               getps.fd = getps.efd = -1;
+               getps.passwd = pwdask;
+               getps.pwlen = sizeof(pwdask)-1;
+               getps.echo = pw_prompt ? pw_prompt : "Enter password: ";
+               getps.charfilter = getps_filter;
+               getps.maskchar = 'x';
+               getps.flags = GETP_WAITFILL;
+               n = xgetpasswd(&getps);
+               if (n == NOSIZE) xerror(NO, NO, YES, "getting password");
+               if (n == ((size_t)-2)) xexit(1);
+               if (do_edcrypt == TFC_DO_ENCRYPT && no_repeat == NO) {
+                       getps.fd = getps.efd = -1;
+                       getps.passwd = pwdagain;
+                       getps.pwlen = sizeof(pwdagain)-1;
+                       getps.echo = "Enter it again: ";
+                       getps.flags = GETP_WAITFILL;
+                       n = xgetpasswd(&getps);
+                       if (n == NOSIZE) xerror(NO, NO, YES, "getting password again");
+                       if (n == ((size_t)-2)) xexit(1);
+                       if (strncmp(pwdask, pwdagain, sizeof(pwdagain)-1) != 0) {
+                               tfc_esay("Passwords are different, try again");
+                               goto _pwdagain;
+                       }
+               }
+               skein(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, pwdask, n);
+               memset(pwdask, 0, sizeof(pwdask));
+               memset(pwdagain, 0, sizeof(pwdagain));
+       }
+       else {
+               if (skeinfd(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, kfd, maxkeylen) != YES)
+                       xerror(NO, NO, YES, "hashing key");
+       }
+
+       if (nr_turns > 1 && rawkey == NO) {
+               for (x = 0; x < nr_turns; x++)
+                       skein(key, TFC_KEY_BITS, mackey_opt ? mackey : NULL, key, TF_FROM_BITS(TFC_KEY_BITS));
+       }
+
+       if (ctr_mode == TFC_MODE_XTS && rawkey == NO) {
+               skein(xtskey, TF_NR_KEY_BITS, mackey_opt ? mackey : NULL, key, TF_FROM_BITS(TFC_KEY_BITS));
+       }
+
+       if (genkeyf) {
+               int krfd;
+               tfc_yesno xtskeyset = NO;
+
+               pblk = key;
+               if (!strcmp(genkeyf, "-")) krfd = 1;
+               else krfd = open(genkeyf, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
+               if (krfd == -1) xerror(NO, NO, YES, "%s", genkeyf);
+_xts2genkey:   if (write(krfd, pblk, TF_FROM_BITS(TFC_KEY_BITS)) == -1) xerror(NO, NO, YES, "%s", genkeyf);
+               if (do_fsync && fsync(krfd) == -1) xerror(NO, NO, YES, "%s", genkeyf);
+               if (verbose && xtskeyset == NO) {
+                       tfc_esay("%s: password hashing done", progname);
+                       tfc_esay("%s: rawkey written to %s.", progname, genkeyf);
+                       tfc_esay("%s: Have a nice day!", progname);
+               }
+
+               if (ctr_mode == TFC_MODE_XTS) {
+                       if (xtskeyset == NO) {
+                               pblk = xtskey;
+                               xtskeyset = YES;
+                               goto _xts2genkey;
+                       }
+               }
+
+               fchmod(krfd, 0600);
+               xclose(krfd);
+               xexit(0);
+       }
+
+       if (iseek_blocks && (do_edcrypt == TFC_DO_DECRYPT && do_mac != NO)) {
+               if (verbose) tfc_esay("%s: disabling signature verification on "
+                       "requested partial decryption.", progname);
+               do_mac = NO;
+       }
+
+       if (do_mac != NO) {
+               if (mackey_opt == TFC_MACKEY_RAWKEY) skein(mackey, TF_MAX_BITS, key, key, TF_FROM_BITS(TFC_KEY_BITS));
+               if (ctr_mode < TFC_MODE_OCB) {
+                       if (verbose) tfc_esay("%s: doing MAC calculation, processing speed "
+                               "will be slower.", progname);
+                       if (mackey_opt) skein_init_key(&sk, mackey, macbits);
+                       else skein_init(&sk, macbits);
+               }
+       }
+
+       if (!counter_file && counter_opt <= TFC_CTR_SHOW && ctr_mode != TFC_MODE_ECB) {
+               skein(ctr, TF_TO_BITS(ctrsz), mackey_opt ? mackey : NULL, key, TF_FROM_BITS(TFC_KEY_BITS));
+       }
+
+       tf_convkey(key);
+       if (ctr_mode == TFC_MODE_XTS) tf_convkey(xtskey);
+       if (do_tfcrypt1 == YES) {
+               if (!tweakf) skein(key+TF_FROM_BITS(TF_MAX_BITS)+TF_SIZE_UNIT, 2*TF_UNIT_BITS, NULL, key, TF_FROM_BITS(TFC_KEY_BITS));
+               tf_key_tweak_compat(key);
+       }
+       if (ctr_mode == TFC_MODE_STREAM) tfe_init_iv(&tfe, key, ctr);
+       if (ctr_mode == TFC_MODE_ECB) goto _ctrskip2;
+       tfc_data_to_words64(&iseek_blocks, sizeof(iseek_blocks));
+       tf_ctr_set(ctr, &iseek_blocks, sizeof(iseek_blocks));
+
+       switch (counter_opt) {
+               case TFC_CTR_SHOW:
+                       switch (do_outfmt) {
+                               case TFC_OUTFMT_B64: tfc_printbase64(stderr, ctr, ctrsz, YES); break;
+                               case TFC_OUTFMT_RAW: write(2, ctr, ctrsz); break;
+                               case TFC_OUTFMT_HEX: mhexdump(ctr, ctrsz, ctrsz, YES); break;
+                       }
+                       break;
+               case TFC_CTR_RAND: tfc_getrandom(ctr, ctrsz); break;
+       }
+
+_ctrskip2:
+       if (kfd != -1) {
+               xclose(kfd);
+               kfd = -1;
+       }
+       if (verbose) tfc_esay("%s: password hashing done", progname);
+
+       if (overwrite_source && srcfname) argv[idx] = srcfname;
+
+_plain:
+       if (argv[idx]) {
+               if (!strcmp(argv[idx], "-")) dfd = 1;
+               else dfd = open(argv[idx], O_RDWR | O_LARGEFILE | write_flags, 0666);
+               if (dfd == -1) {
+                       dfd = open(argv[idx], O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
+                       if (dfd == -1) xerror(NO, NO, YES, "%s", argv[idx]);
+               }
+               dstfname = argv[idx];
+               idx++;
+       }
+
+       if (oseek) {
+               if (lseek(dfd, oseek, SEEK_SET) == -1)
+                       xerror(YES, NO, NO, "%s: seek failed", dstfname);
+       }
+
+       for (x = 1; x < NSIG; x++) signal(x, SIG_IGN);
+       memset(&sigact, 0, sizeof(sigact));
+       sigact.sa_flags = SA_RESTART;
+       sigact.sa_handler = print_crypt_status;
+       sigaction(SIGUSR1, &sigact, NULL);
+       sigaction(SIGTSTP, &sigact, NULL);
+       sigaction(SIGALRM, &sigact, NULL);
+       if (status_timer) setup_next_alarm(status_timer);
+       sigact.sa_handler = change_status_width;
+       sigaction(SIGQUIT, &sigact, NULL);
+       sigact.sa_handler = change_status_timer;
+       sigaction(SIGUSR2, &sigact, NULL);
+       if (quiet == NO) {
+               sigact.sa_handler = print_crypt_status;
+               sigaction(SIGINT, &sigact, NULL);
+               sigaction(SIGTERM, &sigact, NULL);
+       }
+       else {
+               sigact.sa_handler = exit_sigterm;
+               sigaction(SIGINT, &sigact, NULL);
+               sigaction(SIGTERM, &sigact, NULL);
+       }
+       memset(&sigact, 0, sizeof(struct sigaction));
+
+       tfc_getcurtime(&delta_time);
+
+       errno = 0;
+       if (counter_opt == TFC_CTR_RAND && ctr_mode != TFC_MODE_ECB) {
+               pblk = ctr;
+               lio = lrem = ctrsz;
+               ldone = 0;
+_ctrwagain:    lio = write(dfd, pblk, lrem);
+               if (lio != NOSIZE) ldone += lio;
+               else xerror(NO, NO, NO, "%s", dstfname);
+               if (do_fsync && fsync(dfd) == -1) xerror(NO, NO, NO, "%s", dstfname);
+               if (lio < lrem) {
+                       pblk += lio;
+                       lrem -= lio;
+                       goto _ctrwagain;
+               }
+               total_processed_dst += ldone;
+               delta_processed += ldone;
+       }
+
+       errno = 0;
+       do_stop = NO;
+       while (1) {
+               if (do_stop) break;
+               pblk = srcblk;
+               ldone = 0;
+               lrem = lblock = blk_len_adj(maxlen, total_processed_src, blksize);
+_ragain:       lio = read(sfd, pblk, lrem);
+               if (lio == 0) do_stop = TFC_STOP_BEGAN;
+               if (lio != NOSIZE) ldone += lio;
+               else {
+                       if (errno != EIO && catch_all_errors != YES)
+                               xerror(NO, NO, NO, "%s", srcfname);
+                       switch (error_action) {
+                               case TFC_ERRACT_CONT: xerror(YES, NO, NO, "%s", srcfname); goto _ragain; break;
+                               case TFC_ERRACT_SYNC:
+                                       xerror(YES, NO, NO, "%s", srcfname);
+                                       lio = ldone = lrem = lblock;
+                                       memset(srcblk, 0, lio);
+                                       lseek(sfd, lio, SEEK_CUR);
+                                       break;
+                               default: xerror(NO, NO, NO, "%s", srcfname); break;
+                       }
+               }
+               if (lio && lio < lrem) {
+                       pblk += lio;
+                       lrem -= lio;
+                       goto _ragain;
+               }
+               total_processed_src += ldone;
+
+               if (do_pad && (ldone % TF_BLOCK_SIZE)) {
+                       size_t orig = ldone;
+                       ldone += (TF_BLOCK_SIZE - (ldone % TF_BLOCK_SIZE));
+                       if (ldone > blksize) ldone = blksize;
+                       memset(srcblk+orig, 0, sizeof(srcblk)-orig);
+               }
+
+               if (do_mac == TFC_MAC_SIGN && ctr_mode < TFC_MODE_OCB)
+                       skein_update(&sk, srcblk, ldone);
+
+               if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, dstblk, srcblk, ldone);
+               else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, dstblk, srcblk, ldone);
+               else if (ctr_mode == TFC_MODE_XTS && do_edcrypt == TFC_DO_ENCRYPT)
+                       tf_xts_encrypt(key, xtskey, ctr, dstblk, srcblk, ldone, xtsblocks);
+               else if (ctr_mode == TFC_MODE_XTS && do_edcrypt == TFC_DO_DECRYPT)
+                       tf_xts_decrypt(key, xtskey, ctr, dstblk, srcblk, ldone, xtsblocks);
+               else if (ctr_mode == TFC_MODE_ECB && do_edcrypt == TFC_DO_ENCRYPT)
+                       tf_ecb_encrypt(key, dstblk, srcblk, ldone);
+               else if (ctr_mode == TFC_MODE_ECB && do_edcrypt == TFC_DO_DECRYPT)
+                       tf_ecb_decrypt(key, dstblk, srcblk, ldone);
+               else if (ctr_mode == TFC_MODE_CBC && do_edcrypt == TFC_DO_ENCRYPT)
+                       tf_cbc_encrypt(key, ctr, dstblk, srcblk, ldone);
+               else if (ctr_mode == TFC_MODE_CBC && do_edcrypt == TFC_DO_DECRYPT)
+                       tf_cbc_decrypt(key, ctr, dstblk, srcblk, ldone);
+
+               else if (ctr_mode == TFC_MODE_OCB && do_edcrypt == TFC_DO_ENCRYPT)
+                       tf_ocb_encrypt(key, ctr, dstblk, do_mac == TFC_MAC_SIGN ? macresult : NULL, srcblk, ldone, xtsblocks);
+               else if (ctr_mode == TFC_MODE_OCB && do_edcrypt == TFC_DO_DECRYPT)
+                       tf_ocb_decrypt(key, ctr, dstblk, do_mac >= TFC_MAC_VRFY ? macresult : NULL, srcblk, ldone, xtsblocks);
+
+               else if (ctr_mode == TFC_MODE_PLAIN)
+                       memcpy(dstblk, srcblk, ldone);
+
+               if (do_mac >= TFC_MAC_VRFY && ctr_mode < TFC_MODE_OCB)
+                       skein_update(&sk, dstblk, ldone);
+               if (do_mac == TFC_MAC_JUST_VRFY) goto _nowrite;
+
+               pblk = dstblk;
+               lrem = ldone;
+               ldone = 0;
+_wagain:       lio = write(dfd, pblk, lrem);
+               if (lio != NOSIZE) ldone += lio;
+               else xerror(NO, NO, NO, "%s", dstfname);
+               if (do_fsync && fsync(dfd) == -1) xerror(NO, NO, NO, "%s", dstfname);
+               if (lio < lrem) {
+                       pblk += lio;
+                       lrem -= lio;
+                       goto _wagain;
+               }
+_nowrite:      total_processed_dst += ldone;
+               delta_processed += ldone;
+
+               if (maxlen != NOFSIZE && total_processed_src >= maxlen) break;
+       }
+
+       if (do_stop == TFC_STOP_FULL) goto _nomac;
+
+       errno = 0;
+       if (do_mac >= TFC_MAC_VRFY) {
+               if (!do_mac_file) {
+                       pblk = macvrfy;
+                       ldone = 0;
+                       lrem = lblock = TF_FROM_BITS(macbits);
+_macragain:            lio = read(sfd, pblk, lrem);
+                       if (lio != NOSIZE) ldone += lio;
+                       else {
+                               if (errno != EIO && catch_all_errors != YES)
+                                       xerror(NO, NO, NO, "%s", srcfname);
+                               switch (error_action) {
+                                       case TFC_ERRACT_CONT: xerror(YES, NO, NO, "%s", srcfname); goto _macragain; break;
+                                       case TFC_ERRACT_SYNC:
+                                               xerror(YES, NO, NO, "%s", srcfname);
+                                               lio = ldone = lrem = lblock;
+                                               memset(macvrfy, 0, lio);
+                                               lseek(sfd, lio, SEEK_CUR);
+                                               break;
+                                       default: xerror(NO, NO, NO, "%s", srcfname); break;
+                               }
+                       }
+                       if (lio && lio < lrem) {
+                               pblk += lio;
+                               lrem -= lio;
+                               goto _macragain;
+                       }
+                       total_processed_src += ldone;
+               }
+               else {
+                       int mfd;
+
+                       if (!strcmp(do_mac_file, "-")) mfd = 0;
+                       else mfd = open(do_mac_file, O_RDONLY | O_LARGEFILE);
+                       if (mfd == -1) xerror(YES, NO, NO, "%s", do_mac_file);
+                       lio = ldone = read(mfd, tmpdata, sizeof(tmpdata));
+                       if (lio == NOSIZE) xerror(NO, NO, YES, "%s", do_mac_file);
+                       if (!memcmp(tmpdata, TFC_ASCII_TFC_MAC_FOURCC, TFC_ASCII_TFC_MAC_FOURCC_LEN)) {
+                               memmove(tmpdata, tmpdata+TFC_ASCII_TFC_MAC_FOURCC_LEN,
+                                       sizeof(tmpdata)-TFC_ASCII_TFC_MAC_FOURCC_LEN);
+                               lio = TF_FROM_BITS(macbits);
+                               base64_decode((char *)macvrfy, lio, (char *)tmpdata, sizeof(tmpdata));
+                       }
+                       else memcpy(macvrfy, tmpdata, TF_FROM_BITS(macbits));
+                       xclose(mfd);
+               }
+
+               if (ldone < TF_FROM_BITS(macbits)) {
+                       if (quiet == NO) tfc_esay("%s: short signature (%zu), "
+                               "not verifying", progname, ldone);
+                       exitcode = 1;
+                       goto _shortmac;
+               }
+
+               if (ctr_mode < TFC_MODE_OCB) skein_final(macresult, &sk);
+               else skein(macresult, macbits, mackey, macresult, TF_FROM_BITS(macbits));
+
+               if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits));
+               else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, tmpdata, macvrfy, TF_FROM_BITS(macbits));
+               else if (ctr_mode == TFC_MODE_XTS) tf_xts_decrypt(key, xtskey, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits), xtsblocks);
+               else if (ctr_mode == TFC_MODE_ECB) tf_ecb_decrypt(key, tmpdata, macvrfy, TF_FROM_BITS(macbits));
+               else if (ctr_mode == TFC_MODE_CBC) tf_cbc_decrypt(key, ctr, tmpdata, macvrfy, TF_FROM_BITS(macbits));
+               else if (ctr_mode == TFC_MODE_OCB) tf_ocb_decrypt(key, ctr, tmpdata, NULL, macvrfy, TF_FROM_BITS(macbits), xtsblocks);
+
+               if (!memcmp(tmpdata, macresult, TF_FROM_BITS(macbits))) {
+                       if (quiet == NO) {
+                               tfc_esay("%s: signature is good", progname);
+                               if (verbose) {
+                                       if (do_outfmt == TFC_OUTFMT_B64) tfc_printbase64(stderr, macresult, TF_FROM_BITS(macbits), YES);
+                                       else mhexdump(macresult, TF_FROM_BITS(macbits), TF_FROM_BITS(macbits), YES);
+                               }
+                       }
+               }
+               else {
+                       if (quiet == NO) tfc_esay("%s: signature is BAD: "
+                               "wrong password, key, mode, or file is not signed", progname);
+                       exitcode = 1;
+               }
+
+_shortmac:     memset(macvrfy, 0, sizeof(macvrfy));
+               memset(macresult, 0, sizeof(macresult));
+               memset(tmpdata, 0, sizeof(tmpdata));
+       }
+
+       else if (do_mac == TFC_MAC_SIGN) {
+               if (ctr_mode < TFC_MODE_OCB) skein_final(macresult, &sk);
+               else skein(macresult, macbits, mackey, macresult, TF_FROM_BITS(macbits));
+
+               if (ctr_mode == TFC_MODE_CTR) tf_ctr_crypt(key, ctr, tmpdata, macresult, TF_FROM_BITS(macbits));
+               else if (ctr_mode == TFC_MODE_STREAM) tf_stream_crypt(&tfe, tmpdata, macresult, TF_FROM_BITS(macbits));
+               else if (ctr_mode == TFC_MODE_XTS) tf_xts_encrypt(key, xtskey, ctr, tmpdata, macresult, TF_FROM_BITS(macbits), xtsblocks);
+               else if (ctr_mode == TFC_MODE_ECB) tf_ecb_encrypt(key, tmpdata, macresult, TF_FROM_BITS(macbits));
+               else if (ctr_mode == TFC_MODE_CBC) tf_cbc_encrypt(key, ctr, tmpdata, macresult, TF_FROM_BITS(macbits));
+               else if (ctr_mode == TFC_MODE_OCB) tf_ocb_encrypt(key, ctr, tmpdata, NULL, macresult, TF_FROM_BITS(macbits), xtsblocks);
+               memset(macresult, 0, sizeof(macresult));
+
+               if (!do_mac_file) {
+                       pblk = tmpdata;
+                       lio = lrem = TF_FROM_BITS(macbits);
+                       ldone = 0;
+_macwagain:            lio = write(dfd, pblk, lrem);
+                       if (lio != NOSIZE) ldone += lio;
+                       else xerror(NO, NO, NO, "%s", dstfname);
+                       if (do_fsync && fsync(dfd) == -1) xerror(NO, NO, NO, "%s", dstfname);
+                       if (lio < lrem) {
+                               pblk += lio;
+                               lrem -= lio;
+                               goto _macwagain;
+                       }
+                       total_processed_dst += ldone;
+                       delta_processed += ldone;
+               }
+               else {
+                       int mfd;
+
+                       if (!strcmp(do_mac_file, "-")) mfd = 1;
+                       else mfd = open(do_mac_file, O_WRONLY | O_CREAT | O_LARGEFILE | write_flags, 0666);
+                       if (mfd == -1) xerror(YES, NO, NO, "%s", do_mac_file);
+                       if (do_outfmt == TFC_OUTFMT_B64) {
+                               memcpy(macvrfy, tmpdata, TF_FROM_BITS(macbits));
+                               memset(tmpdata, 0, TFC_TMPSIZE);
+                               memcpy(tmpdata, TFC_ASCII_TFC_MAC_FOURCC, TFC_ASCII_TFC_MAC_FOURCC_LEN);
+                               base64_encode((char *)tmpdata+TFC_ASCII_TFC_MAC_FOURCC_LEN, (char *)macvrfy, TF_FROM_BITS(macbits));
+                               lrem = strnlen((char *)tmpdata, sizeof(tmpdata));
+                               if (lrem) {
+                                       tmpdata[lrem] = '\n';
+                                       lrem++;
+                               }
+                               lio = write(mfd, tmpdata, lrem);
+                       }
+                       else lio = write(mfd, tmpdata, TF_FROM_BITS(macbits));
+                       if (lio == NOSIZE) xerror(NO, NO, YES, "%s", do_mac_file);
+                       if (do_fsync && fsync(mfd) == -1) xerror(NO, NO, YES, "%s", do_mac_file);
+                       xclose(mfd);
+               }
+
+               memset(macvrfy, 0, sizeof(macvrfy));
+               memset(macresult, 0, sizeof(macresult));
+               memset(tmpdata, 0, sizeof(tmpdata));
+       }
+
+_nomac:
+       if (verbose || status_timer || do_stop == TFC_STOP_FULL) print_crypt_status(0);
+
+       if (do_preserve_time) fcopy_matime(dfd, &s_stat);
+       xclose(sfd);
+       xclose(dfd);
+
+       xexit(exitcode);
+       return -1;
+}
diff --git a/tfcrypt.h b/tfcrypt.h
new file mode 100644 (file)
index 0000000..9b1caf0
--- /dev/null
+++ b/tfcrypt.h
@@ -0,0 +1,215 @@
+/*
+ * tfcrypt -- high security Threefish encryption tool.
+ *
+ * tfcrypt is copyrighted:
+ * Copyright (C) 2012-2018 Andrey Rys. All rights reserved.
+ *
+ * tfcrypt is licensed to you under the terms of std. MIT/X11 license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _TFCRYPT_H
+#define _TFCRYPT_H
+
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 700
+#endif
+#ifndef _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE
+#endif
+
+#ifndef _TFCRYPT_VERSION
+#error Version number may help you to identify missing functionality.
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <stdint.h>
+
+typedef void (*sighandler_t)(int);
+
+#include "base64.h"
+#include "getpasswd.h"
+#include "tfdef.h"
+#include "skein.h"
+#include "tfe.h"
+#include "tfprng.h"
+
+typedef short tfc_yesno;
+typedef TF_BYTE_TYPE tfc_byte;
+typedef unsigned long long tfc_fsize;
+typedef unsigned long long tfc_useconds;
+
+#ifndef TFC_NR_TURNS
+#define TFC_NR_TURNS 262144
+#endif
+
+#ifndef TFC_CTR_MODE
+#define TFC_CTR_MODE TFC_MODE_XTS
+#endif
+
+#ifndef TFC_BLKSIZE
+#define TFC_BLKSIZE 65536
+#endif
+
+#ifndef TFC_XTSBLOCKS
+#define TFC_XTSBLOCKS 32
+#endif
+
+#ifndef TFC_B64_WIDTH
+#define TFC_B64_WIDTH 76
+#endif
+#define TFC_B64_EWIDTH (TFC_B64_WIDTH - (TFC_B64_WIDTH / 4))
+#define TFC_B64_DWIDTH TFC_BLKSIZE
+
+#define NOSIZE ((size_t)-1)
+#define NOFSIZE ((tfc_fsize)-1)
+#define TFC_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+#define TFC_KEY_BITS (do_tfcrypt1 == YES ? TF_MAX_BITS : TF_NR_KEY_BITS)
+
+#define TFC_ASCII_TFC_MAC_FOURCC "%TF"
+#define TFC_ASCII_TFC_MAC_FOURCC_LEN (sizeof(TFC_ASCII_TFC_MAC_FOURCC)-1)
+
+#define TFC_U(x) ((unsigned)x)
+#define TFC_DTOUSECS(x) ((x) * 1000000.0)
+#define TFC_UTODSECS(x) ((x) / 1000000.0)
+
+#define TFC_DEFAULT_RANDSOURCE "/dev/urandom"
+#define TFC_STDIN_NAME "(stdin)"
+#define TFC_STDOUT_NAME "(stdout)"
+
+#define TFC_TMPSIZE    (TF_BLOCK_SIZE * 4)
+
+int xmhexdump(int to, const void *data, size_t szdata, int hgroup, int hexstr, int newline);
+#define mhexdump(data, szdata, group, newline) xmhexdump(1, data, szdata, group, do_full_hexdump, newline)
+#define mehexdump(data, szdata, group, newline) xmhexdump(2, data, szdata, group, do_full_hexdump, newline)
+
+extern char *progname;
+extern int exitcode;
+extern size_t nr_turns;
+extern int ctr_mode;
+extern size_t macbits;
+extern tfc_byte key[TF_KEY_SIZE], ctr[TF_BLOCK_SIZE], xtskey[TF_KEY_SIZE], mackey[TF_FROM_BITS(TF_MAX_BITS)];
+extern struct skein sk;
+extern struct tfe_stream tfe;
+extern tfc_byte srcblk[TFC_BLKSIZE], dstblk[TFC_BLKSIZE], *pblk;
+extern tfc_byte macvrfy[SKEIN_DIGEST_SIZE], macresult[SKEIN_DIGEST_SIZE];
+extern tfc_byte tmpdata[TFC_TMPSIZE];
+extern char *randsource;
+extern tfc_fsize iseek_blocks, iseek, oseek, maxlen;
+extern tfc_fsize total_processed_src, total_processed_dst;
+extern tfc_fsize delta_processed;
+extern tfc_fsize genrandom_nr_bytes, genzero_nr_bytes;
+extern int sfd, kfd, dfd;
+extern struct stat s_stat;
+extern size_t blksize, xtsblocks;
+extern char pwdask[512], pwdagain[512];
+extern size_t lio, lrem, ldone, lblock;
+extern size_t maxkeylen, ctrsz;
+extern struct sigaction sigact;
+extern size_t sksum_turns;
+extern int do_edcrypt, do_stop, quiet, error_action;
+extern int counter_opt, mackey_opt, do_mac, do_outfmt, rawkey;
+extern int idx, write_flags;
+extern tfc_yesno catch_all_errors, password, overwrite_source, do_fsync, do_pad, do_tfcrypt1;
+extern tfc_yesno do_preserve_time, do_stats_in_gibs, do_statline_dynamic, do_less_stats;
+extern tfc_yesno no_repeat, do_full_hexdump, verbose, statline_was_shown;
+extern char *srcfname, *dstfname, *do_mac_file, *counter_file, *sksum_hashlist_file;
+extern char *genkeyf, *mackeyf, *tweakf;
+extern char *pw_prompt, *mac_pw_prompt;
+extern tfc_useconds status_timer, bench_timer;
+extern tfc_useconds current_time, delta_time;
+extern struct getpasswd_state getps;
+
+void xerror(tfc_yesno noexit, tfc_yesno noerrno, tfc_yesno nostats, const char *fmt, ...);
+void xexit(int status);
+void usage(void);
+
+void tfc_vfsay(FILE *where, tfc_yesno addnl, const char *fmt, va_list ap);
+void tfc_nfsay(FILE *where, const char *fmt, ...);
+void tfc_esay(const char *fmt, ...);
+void tfc_say(const char *fmt, ...);
+
+void tfc_printbase64(FILE *where, const void *p, size_t n, tfc_yesno nl);
+void tfc_data_to_words64(void *data, size_t szdata);
+tfc_fsize tfc_humanfsize(const char *s, char **stoi);
+const char *tfc_getscale(int scale);
+void tfc_describescale(tfc_fsize num, double *w, int *scale);
+size_t blk_len_adj(tfc_fsize filelen, tfc_fsize read_already, size_t blklen);
+tfc_yesno xor_shrink(void *dst, size_t szdst, const void *src, size_t szsrc);
+tfc_yesno str_empty(const char *str);
+void xclose(int fd);
+const char *tfc_modename(int mode);
+void tfc_getcurtime(tfc_useconds *tx);
+tfc_fsize tfc_fdsize(int fd);
+tfc_fsize tfc_fnamesize(char *fname, tfc_yesno noexit);
+tfc_fsize tfc_modifysize(tfc_fsize szmodify, const char *szspec);
+void fcopy_matime(int fd, const struct stat *st);
+tfc_yesno xfgets(char *s, size_t n, FILE *f);
+tfc_yesno isbase64(const char *s);
+void hex2bin(void *d, const char *s);
+void tfc_finirandom(void);
+void tfc_getrandom(void *buf, size_t sz);
+void exit_sigterm(int signal);
+void print_crypt_status(int signal);
+void change_status_width(int signal);
+void change_status_timer(int signal);
+void setup_next_alarm(tfc_useconds useconds);
+void skein(void *hash, size_t bits, const void *key, const void *data, size_t szdata);
+void tf_key_tweak_compat(void *key);
+tfc_yesno skeinfd(void *hash, size_t bits, const void *key, int fd, tfc_fsize readto);
+
+void gen_write_bytes(const char *foutname, tfc_fsize offset, tfc_fsize nrbytes);
+void do_edbase64(char **fargv);
+void do_sksum(char *spec, char **fargv);
+void do_benchmark(tfc_useconds useconds, double dseconds);
+
+enum { NO, YES };
+
+enum { TFC_ERRACT_EXIT, TFC_ERRACT_CONT, TFC_ERRACT_SYNC };
+enum { TFC_STOP_BEGAN = 1, TFC_STOP_FULL };
+enum { TFC_DO_PLAIN, TFC_DO_ENCRYPT, TFC_DO_DECRYPT };
+enum { TFC_MAC_DROP = -1, TFC_MAC_SIGN = 1, TFC_MAC_VRFY, TFC_MAC_JUST_VRFY };
+enum { TFC_MACKEY_RAWKEY = 1, TFC_MACKEY_PASSWORD, TFC_MACKEY_FILE };
+enum { TFC_RAWKEY_KEYFILE = 1, TFC_RAWKEY_ASKSTR, TFC_RAWKEY_ASKHEX };
+enum { TFC_OUTFMT_HEX = 1, TFC_OUTFMT_B64, TFC_OUTFMT_RAW };
+enum {
+       TFC_MODE_SKSUM = -2, TFC_MODE_PLAIN = -1, TFC_MODE_CTR = 1,
+       TFC_MODE_STREAM, TFC_MODE_XTS, TFC_MODE_ECB, TFC_MODE_CBC, TFC_MODE_OCB
+};
+enum { TFC_CTR_SHOW = 1, TFC_CTR_HEAD, TFC_CTR_RAND };
+
+#endif
diff --git a/tfctr.c b/tfctr.c
new file mode 100644 (file)
index 0000000..7cc79c6
--- /dev/null
+++ b/tfctr.c
@@ -0,0 +1,44 @@
+#include <string.h>
+#include "tfdef.h"
+
+void tf_ctr_crypt(const void *key, void *ctr, void *out, const void *in, size_t sz)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE *uctr = ctr;
+       const TF_UNIT_TYPE *ukey = key;
+       size_t sl = sz, i;
+
+       if (sl >= TF_BLOCK_SIZE) {
+               do {
+                       memcpy(x, uin, TF_BLOCK_SIZE);
+                       uin += TF_BLOCK_SIZE;
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+                       tf_encrypt_rawblk(y, uctr, ukey);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= x[i];
+
+                       data_to_words(y, TF_BLOCK_SIZE);
+                       memcpy(uout, y, TF_BLOCK_SIZE);
+                       uout += TF_BLOCK_SIZE;
+               } while ((sl -= TF_BLOCK_SIZE) >= TF_BLOCK_SIZE);
+       }
+
+       if (sl) {
+               memset(x, 0, TF_BLOCK_SIZE);
+               memcpy(x, uin, sl);
+               data_to_words(x, TF_BLOCK_SIZE);
+
+               ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+               tf_encrypt_rawblk(y, uctr, ukey);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= x[i];
+
+               data_to_words(y, TF_BLOCK_SIZE);
+               memcpy(uout, y, sl);
+       }
+
+       memset(x, 0, TF_BLOCK_SIZE);
+       memset(y, 0, TF_BLOCK_SIZE);
+}
diff --git a/tfctrapi.c b/tfctrapi.c
new file mode 100644 (file)
index 0000000..fcd14ee
--- /dev/null
@@ -0,0 +1,14 @@
+#include <string.h>
+#include "tfdef.h"
+
+void tf_ctr_set(void *ctr, const void *sctr, size_t sctrsz)
+{
+       TF_UNIT_TYPE usctr[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE *uctr = ctr;
+
+       memset(usctr, 0, TF_BLOCK_SIZE);
+       memcpy(usctr, sctr, sctrsz > TF_BLOCK_SIZE ? TF_BLOCK_SIZE : sctrsz);
+       ctr_add(uctr, usctr, TF_NR_BLOCK_UNITS);
+       data_to_words(uctr, TF_BLOCK_SIZE);
+       memset(usctr, 0, TF_BLOCK_SIZE);
+}
diff --git a/tfdec.c b/tfdec.c
new file mode 100644 (file)
index 0000000..7142521
--- /dev/null
+++ b/tfdec.c
@@ -0,0 +1,245 @@
+#include "tfdef.h"
+#include "tfcore.h"
+
+#if defined(TF_256BITS)
+
+#define PROCESS_BLOCKP(x,k1,k2,k3,k4,k5,k6)                                            \
+       do {                                                                            \
+               BD_MIX(Z, Y, TFS_BS06); BD_MIX(X, T, TFS_BS05);                         \
+               BD_MIX(Z, T, TFS_BS04); BD_MIX(X, Y, TFS_BS03);                         \
+               BD_MIX(Z, Y, TFS_BS02); BD_MIX(X, T, TFS_BS01);                         \
+                                                                                       \
+               KD_MIX(T, Z, k4 + x, k5 + k6, TFS_KS02);                                \
+               KD_MIX(Y, X, k1 + k2, k3, TFS_KS01);                                    \
+       } while (0)
+
+#define PROCESS_BLOCKN(x,k1,k2,k3,k4,k5,k6)                                            \
+       do {                                                                            \
+               BD_MIX(Z, Y, TFS_BS12); BD_MIX(X, T, TFS_BS11);                         \
+               BD_MIX(Z, T, TFS_BS10); BD_MIX(X, Y, TFS_BS09);                         \
+               BD_MIX(Z, Y, TFS_BS08); BD_MIX(X, T, TFS_BS07);                         \
+                                                                                       \
+               KD_MIX(T, Z, k4 + x, k5 + k6, TFS_KS04);                                \
+               KD_MIX(Y, X, k1 + k2, k3, TFS_KS03);                                    \
+       } while (0)
+
+void tf_decrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K)
+{
+       TF_UNIT_TYPE X, Y, Z, T;
+       TF_UNIT_TYPE K0, K1, K2, K3;
+       TF_UNIT_TYPE K4, T0, T1, T2;
+
+       X = I[0]; Y = I[1]; Z = I[2]; T = I[3];
+
+       K0 = K[0]; K1 = K[1]; K2 = K[2]; K3 = K[3];
+       K4 = K[4]; T0 = K[5]; T1 = K[6]; T2 = K[7];
+
+       X -= K3; Y -= K4 + T0; Z -= K0 + T1; T -= K1 + 18;
+
+       PROCESS_BLOCKN(17,K3,T2,K2,K0,K4,T0);
+       PROCESS_BLOCKP(16,K2,T1,K1,K4,K3,T2);
+
+       PROCESS_BLOCKN(15,K1,T0,K0,K3,K2,T1);
+       PROCESS_BLOCKP(14,K0,T2,K4,K2,K1,T0);
+       PROCESS_BLOCKN(13,K4,T1,K3,K1,K0,T2);
+       PROCESS_BLOCKP(12,K3,T0,K2,K0,K4,T1);
+
+       PROCESS_BLOCKN(11,K2,T2,K1,K4,K3,T0);
+       PROCESS_BLOCKP(10,K1,T1,K0,K3,K2,T2);
+       PROCESS_BLOCKN( 9,K0,T0,K4,K2,K1,T1);
+       PROCESS_BLOCKP( 8,K4,T2,K3,K1,K0,T0);
+
+       PROCESS_BLOCKN( 7,K3,T1,K2,K0,K4,T2);
+       PROCESS_BLOCKP( 6,K2,T0,K1,K4,K3,T1);
+       PROCESS_BLOCKN( 5,K1,T2,K0,K3,K2,T0);
+       PROCESS_BLOCKP( 4,K0,T1,K4,K2,K1,T2);
+
+       PROCESS_BLOCKN( 3,K4,T0,K3,K1,K0,T1);
+       PROCESS_BLOCKP( 2,K3,T2,K2,K0,K4,T0);
+       PROCESS_BLOCKN( 1,K2,T1,K1,K4,K3,T2);
+       PROCESS_BLOCKP( 0,K1,T0,K0,K3,K2,T1);
+
+       O[0] = X; O[1] = Y; O[2] = Z; O[3] = T;
+}
+
+#elif defined(TF_512BITS)
+
+#define PROCESS_BLOCKP(x,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10)                               \
+       do {                                                                            \
+               BD_MIX(E, T, TFS_BS12); BD_MIX(Z, W, TFS_BS11);                         \
+               BD_MIX(X, N, TFS_BS10); BD_MIX(V, Y, TFS_BS09);                         \
+               BD_MIX(Z, N, TFS_BS08); BD_MIX(X, W, TFS_BS07);                         \
+               BD_MIX(V, T, TFS_BS06); BD_MIX(E, Y, TFS_BS05);                         \
+               BD_MIX(X, T, TFS_BS04); BD_MIX(V, W, TFS_BS03);                         \
+               BD_MIX(E, N, TFS_BS02); BD_MIX(Z, Y, TFS_BS01);                         \
+                                                                                       \
+               KD_MIX(N, V, k8 + x, k9 + k10, TFS_KS04);                               \
+               KD_MIX(W, E, k5 + k6, k7, TFS_KS03);                                    \
+               KD_MIX(T, Z, k3, k4, TFS_KS02); KD_MIX(Y, X, k1, k2, TFS_KS01);         \
+       } while (0)
+
+#define PROCESS_BLOCKN(x,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10)                               \
+       do {                                                                            \
+               BD_MIX(E, T, TFS_BS24); BD_MIX(Z, W, TFS_BS23);                         \
+               BD_MIX(X, N, TFS_BS22); BD_MIX(V, Y, TFS_BS21);                         \
+               BD_MIX(Z, N, TFS_BS20); BD_MIX(X, W, TFS_BS19);                         \
+               BD_MIX(V, T, TFS_BS18); BD_MIX(E, Y, TFS_BS17);                         \
+               BD_MIX(X, T, TFS_BS16); BD_MIX(V, W, TFS_BS15);                         \
+               BD_MIX(E, N, TFS_BS14); BD_MIX(Z, Y, TFS_BS13);                         \
+                                                                                       \
+               KD_MIX(N, V, k8 + x, k9 + k10, TFS_KS08);                               \
+               KD_MIX(W, E, k5 + k6, k7, TFS_KS07);                                    \
+               KD_MIX(T, Z, k3, k4, TFS_KS06); KD_MIX(Y, X, k1, k2, TFS_KS05);         \
+       } while (0)
+
+void tf_decrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K)
+{
+       TF_UNIT_TYPE X, Y, Z, T;
+       TF_UNIT_TYPE E, W, V, N;
+       TF_UNIT_TYPE K0, K1, K2, K3;
+       TF_UNIT_TYPE K4, K5, K6, K7;
+       TF_UNIT_TYPE K8, T0, T1, T2;
+
+       X = I[0]; Y = I[1]; Z = I[2]; T = I[3];
+       E = I[4]; W = I[5]; V = I[6]; N = I[7];
+
+       K0 = K[ 0]; K1 = K[ 1]; K2 = K[ 2]; K3 = K[ 3];
+       K4 = K[ 4]; K5 = K[ 5]; K6 = K[ 6]; K7 = K[ 7];
+       K8 = K[ 8]; T0 = K[ 9]; T1 = K[10]; T2 = K[11];
+
+       X -= K0; Y -= K1; Z -= K2; T -= K3;
+       E -= K4; W -= K5 + T0; V -= K6 + T1; N -= K7 + 18;
+
+       PROCESS_BLOCKN(17,K0,K8,K2,K1,K4,T2,K3,K6,K5,T0);
+       PROCESS_BLOCKP(16,K8,K7,K1,K0,K3,T1,K2,K5,K4,T2);
+
+       PROCESS_BLOCKN(15,K7,K6,K0,K8,K2,T0,K1,K4,K3,T1);
+       PROCESS_BLOCKP(14,K6,K5,K8,K7,K1,T2,K0,K3,K2,T0);
+       PROCESS_BLOCKN(13,K5,K4,K7,K6,K0,T1,K8,K2,K1,T2);
+       PROCESS_BLOCKP(12,K4,K3,K6,K5,K8,T0,K7,K1,K0,T1);
+
+       PROCESS_BLOCKN(11,K3,K2,K5,K4,K7,T2,K6,K0,K8,T0);
+       PROCESS_BLOCKP(10,K2,K1,K4,K3,K6,T1,K5,K8,K7,T2);
+       PROCESS_BLOCKN( 9,K1,K0,K3,K2,K5,T0,K4,K7,K6,T1);
+       PROCESS_BLOCKP( 8,K0,K8,K2,K1,K4,T2,K3,K6,K5,T0);
+
+       PROCESS_BLOCKN( 7,K8,K7,K1,K0,K3,T1,K2,K5,K4,T2);
+       PROCESS_BLOCKP( 6,K7,K6,K0,K8,K2,T0,K1,K4,K3,T1);
+       PROCESS_BLOCKN( 5,K6,K5,K8,K7,K1,T2,K0,K3,K2,T0);
+       PROCESS_BLOCKP( 4,K5,K4,K7,K6,K0,T1,K8,K2,K1,T2);
+
+       PROCESS_BLOCKN( 3,K4,K3,K6,K5,K8,T0,K7,K1,K0,T1);
+       PROCESS_BLOCKP( 2,K3,K2,K5,K4,K7,T2,K6,K0,K8,T0);
+       PROCESS_BLOCKN( 1,K2,K1,K4,K3,K6,T1,K5,K8,K7,T2);
+       PROCESS_BLOCKP( 0,K1,K0,K3,K2,K5,T0,K4,K7,K6,T1);
+
+       O[0] = X; O[1] = Y; O[2] = Z; O[3] = T;
+       O[4] = E; O[5] = W; O[6] = V; O[7] = N;
+}
+
+#elif defined(TF_1024BITS)
+
+#define PROCESS_BLOCKP(x,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,k11,k12,k13,k14,k15,k16,k17,k18)\
+       do {                                                                            \
+               BD_MIX(A, N, TFS_BS24); BD_MIX(M, T, TFS_BS23);                         \
+               BD_MIX(P, W, TFS_BS22); BD_MIX(H, Y, TFS_BS21);                         \
+               BD_MIX(E, U, TFS_BS20); BD_MIX(V, B, TFS_BS19);                         \
+               BD_MIX(Z, Q, TFS_BS18); BD_MIX(X, L, TFS_BS17);                         \
+               BD_MIX(M, U, TFS_BS16); BD_MIX(P, Q, TFS_BS15);                         \
+               BD_MIX(H, B, TFS_BS14); BD_MIX(A, L, TFS_BS13);                         \
+               BD_MIX(V, Y, TFS_BS12); BD_MIX(E, T, TFS_BS11);                         \
+               BD_MIX(Z, W, TFS_BS10); BD_MIX(X, N, TFS_BS09);                         \
+               BD_MIX(P, Y, TFS_BS08); BD_MIX(H, W, TFS_BS07);                         \
+               BD_MIX(A, T, TFS_BS06); BD_MIX(M, N, TFS_BS05);                         \
+               BD_MIX(E, L, TFS_BS04); BD_MIX(V, Q, TFS_BS03);                         \
+               BD_MIX(Z, B, TFS_BS02); BD_MIX(X, U, TFS_BS01);                         \
+                                                                                       \
+               KD_MIX(L, H, k16 + x, k17 + k18, TFS_KS08);                             \
+               KD_MIX(B, A, k13 + k14, k15, TFS_KS07);                                 \
+               KD_MIX(Q, M, k11, k12, TFS_KS06); KD_MIX(U, P, k9, k10, TFS_KS05);      \
+               KD_MIX(N, V, k7, k8, TFS_KS04); KD_MIX(W, E, k5, k6, TFS_KS03);         \
+               KD_MIX(T, Z, k3, k4, TFS_KS02); KD_MIX(Y, X, k1, k2, TFS_KS01);         \
+       } while (0)
+
+#define PROCESS_BLOCKN(x,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,k11,k12,k13,k14,k15,k16,k17,k18)\
+       do {                                                                            \
+               BD_MIX(A, N, TFS_BS48); BD_MIX(M, T, TFS_BS47);                         \
+               BD_MIX(P, W, TFS_BS46); BD_MIX(H, Y, TFS_BS45);                         \
+               BD_MIX(E, U, TFS_BS44); BD_MIX(V, B, TFS_BS43);                         \
+               BD_MIX(Z, Q, TFS_BS42); BD_MIX(X, L, TFS_BS41);                         \
+               BD_MIX(M, U, TFS_BS40); BD_MIX(P, Q, TFS_BS39);                         \
+               BD_MIX(H, B, TFS_BS38); BD_MIX(A, L, TFS_BS37);                         \
+               BD_MIX(V, Y, TFS_BS36); BD_MIX(E, T, TFS_BS35);                         \
+               BD_MIX(Z, W, TFS_BS34); BD_MIX(X, N, TFS_BS33);                         \
+               BD_MIX(P, Y, TFS_BS32); BD_MIX(H, W, TFS_BS31);                         \
+               BD_MIX(A, T, TFS_BS30); BD_MIX(M, N, TFS_BS29);                         \
+               BD_MIX(E, L, TFS_BS28); BD_MIX(V, Q, TFS_BS27);                         \
+               BD_MIX(Z, B, TFS_BS26); BD_MIX(X, U, TFS_BS25);                         \
+                                                                                       \
+               KD_MIX(L, H, k16 + x, k17 + k18, TFS_KS16);                             \
+               KD_MIX(B, A, k13 + k14, k15, TFS_KS15);                                 \
+               KD_MIX(Q, M, k11, k12, TFS_KS14); KD_MIX(U, P, k9, k10, TFS_KS13);      \
+               KD_MIX(N, V, k7, k8, TFS_KS12); KD_MIX(W, E, k5, k6, TFS_KS11);         \
+               KD_MIX(T, Z, k3, k4, TFS_KS10); KD_MIX(Y, X, k1, k2, TFS_KS09);         \
+       } while (0)
+
+void tf_decrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K)
+{
+       TF_UNIT_TYPE X, Y, Z, T;
+       TF_UNIT_TYPE E, W, V, N;
+       TF_UNIT_TYPE P, U, M, Q;
+       TF_UNIT_TYPE A, B, H, L;
+       TF_UNIT_TYPE K0, K1, K2, K3;
+       TF_UNIT_TYPE K4, K5, K6, K7;
+       TF_UNIT_TYPE K8, K9, K10, K11;
+       TF_UNIT_TYPE K12, K13, K14, K15;
+       TF_UNIT_TYPE K16, T0, T1, T2;
+
+       X = I[ 0]; Y = I[ 1]; Z = I[ 2]; T = I[ 3];
+       E = I[ 4]; W = I[ 5]; V = I[ 6]; N = I[ 7];
+       P = I[ 8]; U = I[ 9]; M = I[10]; Q = I[11];
+       A = I[12]; B = I[13]; H = I[14]; L = I[15];
+
+       K0  = K[ 0]; K1  = K[ 1]; K2  = K[ 2]; K3  = K[ 3];
+       K4  = K[ 4]; K5  = K[ 5]; K6  = K[ 6]; K7  = K[ 7];
+       K8  = K[ 8]; K9  = K[ 9]; K10 = K[10]; K11 = K[11];
+       K12 = K[12]; K13 = K[13]; K14 = K[14]; K15 = K[15];
+       K16 = K[16]; T0  = K[17]; T1  = K[18]; T2  = K[19];
+
+       X -= K3; Y -= K4; Z -= K5; T -= K6;
+       E -= K7; W -= K8; V -= K9; N -= K10;
+       P -= K11; U -= K12; M -= K13; Q -= K14;
+       A -= K15; B -= K16 + T2; H -= K0 + T0; L -= K1 + 20;
+
+       PROCESS_BLOCKN(19, K3, K2, K5, K4, K7, K6, K9, K8,K11,K10,K13,K12,K15, T1,K14, K0,K16, T2);
+       PROCESS_BLOCKP(18, K2, K1, K4, K3, K6, K5, K8, K7,K10, K9,K12,K11,K14, T0,K13,K16,K15, T1);
+       PROCESS_BLOCKN(17, K1, K0, K3, K2, K5, K4, K7, K6, K9, K8,K11,K10,K13, T2,K12,K15,K14, T0);
+       PROCESS_BLOCKP(16, K0,K16, K2, K1, K4, K3, K6, K5, K8, K7,K10, K9,K12, T1,K11,K14,K13, T2);
+
+       PROCESS_BLOCKN(15,K16,K15, K1, K0, K3, K2, K5, K4, K7, K6, K9, K8,K11, T0,K10,K13,K12, T1);
+       PROCESS_BLOCKP(14,K15,K14, K0,K16, K2, K1, K4, K3, K6, K5, K8, K7,K10, T2, K9,K12,K11, T0);
+       PROCESS_BLOCKN(13,K14,K13,K16,K15, K1, K0, K3, K2, K5, K4, K7, K6, K9, T1, K8,K11,K10, T2);
+       PROCESS_BLOCKP(12,K13,K12,K15,K14, K0,K16, K2, K1, K4, K3, K6, K5, K8, T0, K7,K10, K9, T1);
+
+       PROCESS_BLOCKN(11,K12,K11,K14,K13,K16,K15, K1, K0, K3, K2, K5, K4, K7, T2, K6, K9, K8, T0);
+       PROCESS_BLOCKP(10,K11,K10,K13,K12,K15,K14, K0,K16, K2, K1, K4, K3, K6, T1, K5, K8, K7, T2);
+       PROCESS_BLOCKN( 9,K10, K9,K12,K11,K14,K13,K16,K15, K1, K0, K3, K2, K5, T0, K4, K7, K6, T1);
+       PROCESS_BLOCKP( 8, K9, K8,K11,K10,K13,K12,K15,K14, K0,K16, K2, K1, K4, T2, K3, K6, K5, T0);
+
+       PROCESS_BLOCKN( 7, K8, K7,K10, K9,K12,K11,K14,K13,K16,K15, K1, K0, K3, T1, K2, K5, K4, T2);
+       PROCESS_BLOCKP( 6, K7, K6, K9, K8,K11,K10,K13,K12,K15,K14, K0,K16, K2, T0, K1, K4, K3, T1);
+       PROCESS_BLOCKN( 5, K6, K5, K8, K7,K10, K9,K12,K11,K14,K13,K16,K15, K1, T2, K0, K3, K2, T0);
+       PROCESS_BLOCKP( 4, K5, K4, K7, K6, K9, K8,K11,K10,K13,K12,K15,K14, K0, T1,K16, K2, K1, T2);
+
+       PROCESS_BLOCKN( 3, K4, K3, K6, K5, K8, K7,K10, K9,K12,K11,K14,K13,K16, T0,K15, K1, K0, T1);
+       PROCESS_BLOCKP( 2, K3, K2, K5, K4, K7, K6, K9, K8,K11,K10,K13,K12,K15, T2,K14, K0,K16, T0);
+       PROCESS_BLOCKN( 1, K2, K1, K4, K3, K6, K5, K8, K7,K10, K9,K12,K11,K14, T1,K13,K16,K15, T2);
+       PROCESS_BLOCKP( 0, K1, K0, K3, K2, K5, K4, K7, K6, K9, K8,K11,K10,K13, T0,K12,K15,K14, T1);
+
+       O[0] = X; O[1] = Y; O[2] = Z; O[3] = T;
+       O[4] = E; O[5] = W; O[6] = V; O[7] = N;
+       O[8] = P; O[9] = U; O[10] = M; O[11] = Q;
+       O[12] = A; O[13] = B; O[14] = H; O[15] = L;
+}
+
+#endif
diff --git a/tfdef.h b/tfdef.h
new file mode 100644 (file)
index 0000000..5bc29cd
--- /dev/null
+++ b/tfdef.h
@@ -0,0 +1,136 @@
+#ifndef _THREEFISH_CIPHER_DEFINITIONS_HEADER
+#define _THREEFISH_CIPHER_DEFINITIONS_HEADER
+
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+
+/* config block */
+/* #define TF_256BITS */
+/* #define TF_512BITS */
+#define TF_1024BITS
+/* #define TF_NO_ENDIAN */
+/* #define TF_BIG_ENDIAN */
+
+#include <stddef.h>
+#include <stdint.h>
+#ifndef TF_NO_ENDIAN
+#include <sys/param.h>
+#else
+#undef TF_BIG_ENDIAN
+#endif
+
+#define TF_UNIT_TYPE uint64_t
+
+#ifdef TF_BIG_ENDIAN
+#define TF_SWAP_FUNC htobe64
+#else
+#define TF_SWAP_FUNC htole64
+#endif
+
+#if defined(TF_256BITS)
+#define TF_NR_BLOCK_BITS 256
+#define TF_NR_KEY_BITS 512
+#define TF_NR_BLOCK_UNITS 4
+#define TF_NR_KEY_UNITS 8
+#define IRR_POLY_CONST 0x425
+#elif defined(TF_512BITS)
+#define TF_NR_BLOCK_BITS 512
+#define TF_NR_KEY_BITS 768
+#define TF_NR_BLOCK_UNITS 8
+#define TF_NR_KEY_UNITS 12
+#define IRR_POLY_CONST 0x125
+#elif defined(TF_1024BITS)
+#define TF_NR_BLOCK_BITS 1024
+#define TF_NR_KEY_BITS 1280
+#define TF_NR_BLOCK_UNITS 16
+#define TF_NR_KEY_UNITS 20
+#define IRR_POLY_CONST 0x80043
+#else
+#error Please edit tfdef.h include file and select at least one cipher!
+#endif
+
+#define TF_BYTE_TYPE uint8_t
+#define TF_SIZE_UNIT (sizeof(TF_UNIT_TYPE))
+#define TF_BLOCK_SIZE (TF_SIZE_UNIT * TF_NR_BLOCK_UNITS)
+#define TF_KEY_SIZE (TF_SIZE_UNIT * TF_NR_KEY_UNITS)
+
+#define TF_TWEAK_WORD1 (TF_NR_KEY_UNITS-3)
+#define TF_TWEAK_WORD2 (TF_NR_KEY_UNITS-2)
+#define TF_TWEAK_WORD3 (TF_NR_KEY_UNITS-1)
+
+#define TF_TO_BITS(x) ((x) * 8)
+#define TF_FROM_BITS(x) ((x) / 8)
+#define TF_MAX_BITS TF_NR_BLOCK_BITS
+#define TF_UNIT_BITS (TF_SIZE_UNIT * 8)
+
+#define TF_TO_BLOCKS(x) ((x) / TF_BLOCK_SIZE)
+#define TF_FROM_BLOCKS(x) ((x) * TF_BLOCK_SIZE)
+#define TF_BLOCKS_TO_BYTES(x) TF_FROM_BLOCKS(x)
+#define TF_BLOCKS_FROM_BYTES(x) TF_TO_BLOCKS(x)
+
+static inline void data_to_words(void *p, size_t l)
+{
+#ifndef TF_NO_ENDIAN
+       size_t idx;
+       TF_UNIT_TYPE *P = p;
+       TF_UNIT_TYPE t;
+
+       for (idx = 0; idx < (l/sizeof(TF_UNIT_TYPE)); idx++) {
+               t = TF_SWAP_FUNC(P[idx]);
+               P[idx] = t;
+       }
+#endif
+}
+
+static inline void ctr_inc(TF_UNIT_TYPE *x, size_t l)
+{
+       size_t i;
+
+       for (i = 0; i < l; i++) {
+               x[i] = ((x[i] + (TF_UNIT_TYPE)1) & ((TF_UNIT_TYPE)~0));
+               if (x[i]) break;
+       }
+}
+
+static inline void ctr_add(TF_UNIT_TYPE *x, const TF_UNIT_TYPE *y, size_t l)
+{
+       size_t i, f = 0;
+       TF_UNIT_TYPE t;
+
+       for (i = 0; i < l; i++) {
+               t = x[i];
+               x[i] += y[i]; x[i] &= ((TF_UNIT_TYPE)~0);
+               if (x[i] < t) {
+_again:                        f++;
+                       t = x[f-i];
+                       x[f-i]++;
+                       if (x[f-i] < t) goto _again;
+                       else f = 0;
+               }
+       }
+}
+
+struct tfe_stream;
+
+#define tf_convkey(k) do { data_to_words(k, TF_KEY_SIZE); } while (0)
+
+void tf_encrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K);
+void tf_decrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K);
+
+void tf_encrypt_block(const void *key, void *out, const void *in);
+void tf_decrypt_block(const void *key, void *out, const void *in);
+
+void tf_ctr_set(void *ctr, const void *sctr, size_t sctrsz);
+void tf_ctr_crypt(const void *key, void *ctr, void *out, const void *in, size_t sz);
+void tf_stream_crypt(struct tfe_stream *tfe, void *out, const void *in, size_t sz);
+void tf_ecb_encrypt(const void *key, void *out, const void *in, size_t sz);
+void tf_ecb_decrypt(const void *key, void *out, const void *in, size_t sz);
+void tf_cbc_encrypt(const void *key, void *iv, void *out, const void *in, size_t sz);
+void tf_cbc_decrypt(const void *key, void *iv, void *out, const void *in, size_t sz);
+void tf_xts_encrypt(const void *keyx, const void *keyz, void *ctr, void *out, const void *in, size_t sz, size_t bpi);
+void tf_xts_decrypt(const void *keyx, const void *keyz, void *ctr, void *out, const void *in, size_t sz, size_t bpi);
+void tf_ocb_encrypt(const void *key, void *ctr, void *out, void *tag, const void *in, size_t sz, size_t bpi);
+void tf_ocb_decrypt(const void *key, void *ctr, void *out, void *tag, const void *in, size_t sz, size_t bpi);
+
+#endif
diff --git a/tfe.c b/tfe.c
new file mode 100644 (file)
index 0000000..544bcc7
--- /dev/null
+++ b/tfe.c
@@ -0,0 +1,63 @@
+#include <string.h>
+#include "tfdef.h"
+#include "tfe.h"
+
+void tfe_init_iv(struct tfe_stream *tfe, const void *key, const void *iv)
+{
+       memset(tfe, 0, sizeof(struct tfe_stream));
+       memcpy(tfe->key, key, TF_KEY_SIZE);
+       data_to_words(tfe->key, TF_KEY_SIZE);
+       if (iv) {
+               memcpy(tfe->iv, iv, TF_BLOCK_SIZE);
+               data_to_words(tfe->iv, TF_BLOCK_SIZE);
+       }
+       tfe->carry_bytes = 0;
+}
+
+void tfe_init(struct tfe_stream *tfe, const void *key)
+{
+       tfe_init_iv(tfe, key, NULL);
+}
+
+void tfe_emit(void *dst, size_t szdst, struct tfe_stream *tfe)
+{
+       TF_BYTE_TYPE *udst = dst;
+       size_t sz = szdst;
+
+       if (!dst && szdst == 0) {
+               memset(tfe, 0, sizeof(struct tfe_stream));
+               return;
+       }
+
+       if (tfe->carry_bytes > 0) {
+               if (tfe->carry_bytes > szdst) {
+                       memcpy(udst, tfe->carry_block, szdst);
+                       memmove(tfe->carry_block, tfe->carry_block+szdst, tfe->carry_bytes-szdst);
+                       tfe->carry_bytes -= szdst;
+                       return;
+               }
+
+               memcpy(udst, tfe->carry_block, tfe->carry_bytes);
+               udst += tfe->carry_bytes;
+               sz -= tfe->carry_bytes;
+               tfe->carry_bytes = 0;
+       }
+
+       if (sz >= TF_BLOCK_SIZE) {
+               do {
+                       tf_encrypt_rawblk(tfe->iv, tfe->iv, tfe->key);
+                       memcpy(udst, tfe->iv, TF_BLOCK_SIZE);
+                       data_to_words(udst, TF_BLOCK_SIZE);
+                       udst += TF_BLOCK_SIZE;
+               } while ((sz -= TF_BLOCK_SIZE) >= TF_BLOCK_SIZE);
+       }
+
+       if (sz) {
+               tf_encrypt_rawblk(tfe->iv, tfe->iv, tfe->key);
+               memcpy(udst, tfe->iv, sz);
+               data_to_words(udst, TF_BLOCK_SIZE);
+               udst = (TF_BYTE_TYPE *)tfe->iv;
+               tfe->carry_bytes = TF_BLOCK_SIZE-sz;
+               memcpy(tfe->carry_block, udst+sz, tfe->carry_bytes);
+       }
+}
diff --git a/tfe.h b/tfe.h
new file mode 100644 (file)
index 0000000..f5793b1
--- /dev/null
+++ b/tfe.h
@@ -0,0 +1,17 @@
+#ifndef _TF_STREAM_CIPHER_DEFS
+#define _TF_STREAM_CIPHER_DEFS
+
+#include "tfdef.h"
+
+struct tfe_stream {
+       TF_UNIT_TYPE key[TF_NR_KEY_UNITS];
+       TF_UNIT_TYPE iv[TF_NR_BLOCK_UNITS];
+       TF_BYTE_TYPE carry_block[TF_BLOCK_SIZE];
+       size_t carry_bytes;
+};
+
+void tfe_init(struct tfe_stream *tfe, const void *key);
+void tfe_init_iv(struct tfe_stream *tfe, const void *key, const void *iv);
+void tfe_emit(void *dst, size_t szdst, struct tfe_stream *tfe);
+
+#endif
diff --git a/tfecb.c b/tfecb.c
new file mode 100644 (file)
index 0000000..0d24782
--- /dev/null
+++ b/tfecb.c
@@ -0,0 +1,80 @@
+#include <string.h>
+#include "tfdef.h"
+
+void tf_ecb_encrypt(const void *key, void *out, const void *in, size_t sz)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS];
+       const TF_UNIT_TYPE *ukey = key;
+       size_t sl = sz, i;
+
+       if (sl >= TF_BLOCK_SIZE) {
+               do {
+                       memcpy(x, uin, TF_BLOCK_SIZE);
+                       uin += TF_BLOCK_SIZE;
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       tf_encrypt_rawblk(y, x, ukey);
+
+                       data_to_words(y, TF_BLOCK_SIZE);
+                       memcpy(uout, y, TF_BLOCK_SIZE);
+                       uout += TF_BLOCK_SIZE;
+               } while ((sl -= TF_BLOCK_SIZE) >= TF_BLOCK_SIZE);
+       }
+
+       if (sl) {
+               memset(x, 0, TF_BLOCK_SIZE);
+               memcpy(x, uin, sl);
+               data_to_words(x, TF_BLOCK_SIZE);
+
+               memset(y, 0, TF_BLOCK_SIZE);
+               tf_encrypt_rawblk(y, y, ukey);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= x[i];
+
+               data_to_words(y, TF_BLOCK_SIZE);
+               memcpy(uout, y, sl);
+       }
+
+       memset(x, 0, TF_BLOCK_SIZE);
+       memset(y, 0, TF_BLOCK_SIZE);
+}
+
+void tf_ecb_decrypt(const void *key, void *out, const void *in, size_t sz)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS];
+       const TF_UNIT_TYPE *ukey = key;
+       size_t sl = sz, i;
+
+       if (sl >= TF_BLOCK_SIZE) {
+               do {
+                       memcpy(x, uin, TF_BLOCK_SIZE);
+                       uin += TF_BLOCK_SIZE;
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       tf_decrypt_rawblk(y, x, ukey);
+
+                       data_to_words(y, TF_BLOCK_SIZE);
+                       memcpy(uout, y, TF_BLOCK_SIZE);
+                       uout += TF_BLOCK_SIZE;
+               } while ((sl -= TF_BLOCK_SIZE) >= TF_BLOCK_SIZE);
+       }
+
+       if (sl) {
+               memset(x, 0, TF_BLOCK_SIZE);
+               memcpy(x, uin, sl);
+               data_to_words(x, TF_BLOCK_SIZE);
+
+               memset(y, 0, TF_BLOCK_SIZE);
+               tf_decrypt_rawblk(y, y, ukey);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= x[i];
+
+               data_to_words(y, TF_BLOCK_SIZE);
+               memcpy(uout, y, sl);
+       }
+
+       memset(x, 0, TF_BLOCK_SIZE);
+       memset(y, 0, TF_BLOCK_SIZE);
+}
diff --git a/tfenc.c b/tfenc.c
new file mode 100644 (file)
index 0000000..bd492a2
--- /dev/null
+++ b/tfenc.c
@@ -0,0 +1,235 @@
+#include "tfdef.h"
+#include "tfcore.h"
+
+#if defined(TF_256BITS)
+
+#define PROCESS_BLOCKP(x,k1,k2,k3,k4,k5,k6)                                            \
+       do {                                                                            \
+               KE_MIX(Y, X, k1 + k2, k3, TFS_KS01);                                    \
+               KE_MIX(T, Z, k4 + x, k5 + k6, TFS_KS02);                                \
+                                                                                       \
+               BE_MIX(X, T, TFS_BS01); BE_MIX(Z, Y, TFS_BS02);                         \
+               BE_MIX(X, Y, TFS_BS03); BE_MIX(Z, T, TFS_BS04);                         \
+               BE_MIX(X, T, TFS_BS05); BE_MIX(Z, Y, TFS_BS06);                         \
+       } while (0)
+
+#define PROCESS_BLOCKN(x,k1,k2,k3,k4,k5,k6)                                            \
+       do {                                                                            \
+               KE_MIX(Y, X, k1 + k2, k3, TFS_KS03);                                    \
+               KE_MIX(T, Z, k4 + x, k5 + k6, TFS_KS04);                                \
+                                                                                       \
+               BE_MIX(X, T, TFS_BS07); BE_MIX(Z, Y, TFS_BS08);                         \
+               BE_MIX(X, Y, TFS_BS09); BE_MIX(Z, T, TFS_BS10);                         \
+               BE_MIX(X, T, TFS_BS11); BE_MIX(Z, Y, TFS_BS12);                         \
+       } while (0)
+
+void tf_encrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K)
+{
+       TF_UNIT_TYPE X, Y, Z, T;
+       TF_UNIT_TYPE K0, K1, K2, K3;
+       TF_UNIT_TYPE K4, T0, T1, T2;
+
+       X = I[0]; Y = I[1]; Z = I[2]; T = I[3];
+
+       K0 = K[0]; K1 = K[1]; K2 = K[2]; K3 = K[3];
+       K4 = K[4]; T0 = K[5]; T1 = K[6]; T2 = K[7];
+
+       PROCESS_BLOCKP( 0,K1,T0,K0,K3,K2,T1);
+       PROCESS_BLOCKN( 1,K2,T1,K1,K4,K3,T2);
+       PROCESS_BLOCKP( 2,K3,T2,K2,K0,K4,T0);
+       PROCESS_BLOCKN( 3,K4,T0,K3,K1,K0,T1);
+
+       PROCESS_BLOCKP( 4,K0,T1,K4,K2,K1,T2);
+       PROCESS_BLOCKN( 5,K1,T2,K0,K3,K2,T0);
+       PROCESS_BLOCKP( 6,K2,T0,K1,K4,K3,T1);
+       PROCESS_BLOCKN( 7,K3,T1,K2,K0,K4,T2);
+
+       PROCESS_BLOCKP( 8,K4,T2,K3,K1,K0,T0);
+       PROCESS_BLOCKN( 9,K0,T0,K4,K2,K1,T1);
+       PROCESS_BLOCKP(10,K1,T1,K0,K3,K2,T2);
+       PROCESS_BLOCKN(11,K2,T2,K1,K4,K3,T0);
+
+       PROCESS_BLOCKP(12,K3,T0,K2,K0,K4,T1);
+       PROCESS_BLOCKN(13,K4,T1,K3,K1,K0,T2);
+       PROCESS_BLOCKP(14,K0,T2,K4,K2,K1,T0);
+       PROCESS_BLOCKN(15,K1,T0,K0,K3,K2,T1);
+
+       PROCESS_BLOCKP(16,K2,T1,K1,K4,K3,T2);
+       PROCESS_BLOCKN(17,K3,T2,K2,K0,K4,T0);
+
+       O[0] = X + K3; O[1] = Y + K4 + T0; O[2] = Z + K0 + T1; O[3] = T + K1 + 18;
+}
+
+#elif defined(TF_512BITS)
+
+#define PROCESS_BLOCKP(x,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10)                               \
+       do {                                                                            \
+               KE_MIX(Y, X, k1, k2, TFS_KS01); KE_MIX(T, Z, k3, k4, TFS_KS02);         \
+               KE_MIX(W, E, k5 + k6, k7, TFS_KS03);                                    \
+               KE_MIX(N, V, k8 + x, k9 + k10, TFS_KS04);                               \
+                                                                                       \
+               BE_MIX(Z, Y, TFS_BS01); BE_MIX(E, N, TFS_BS02);                         \
+               BE_MIX(V, W, TFS_BS03); BE_MIX(X, T, TFS_BS04);                         \
+               BE_MIX(E, Y, TFS_BS05); BE_MIX(V, T, TFS_BS06);                         \
+               BE_MIX(X, W, TFS_BS07); BE_MIX(Z, N, TFS_BS08);                         \
+               BE_MIX(V, Y, TFS_BS09); BE_MIX(X, N, TFS_BS10);                         \
+               BE_MIX(Z, W, TFS_BS11); BE_MIX(E, T, TFS_BS12);                         \
+       } while (0)
+
+#define PROCESS_BLOCKN(x,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10)                               \
+       do {                                                                            \
+               KE_MIX(Y, X, k1, k2, TFS_KS05); KE_MIX(T, Z, k3, k4, TFS_KS06);         \
+               KE_MIX(W, E, k5 + k6, k7, TFS_KS07);                                    \
+               KE_MIX(N, V, k8 + x, k9 + k10, TFS_KS08);                               \
+                                                                                       \
+               BE_MIX(Z, Y, TFS_BS13); BE_MIX(E, N, TFS_BS14);                         \
+               BE_MIX(V, W, TFS_BS15); BE_MIX(X, T, TFS_BS16);                         \
+               BE_MIX(E, Y, TFS_BS17); BE_MIX(V, T, TFS_BS18);                         \
+               BE_MIX(X, W, TFS_BS19); BE_MIX(Z, N, TFS_BS20);                         \
+               BE_MIX(V, Y, TFS_BS21); BE_MIX(X, N, TFS_BS22);                         \
+               BE_MIX(Z, W, TFS_BS23); BE_MIX(E, T, TFS_BS24);                         \
+       } while (0)
+
+void tf_encrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K)
+{
+       TF_UNIT_TYPE X, Y, Z, T;
+       TF_UNIT_TYPE E, W, V, N;
+       TF_UNIT_TYPE K0, K1, K2, K3;
+       TF_UNIT_TYPE K4, K5, K6, K7;
+       TF_UNIT_TYPE K8, T0, T1, T2;
+
+       X = I[0]; Y = I[1]; Z = I[2]; T = I[3];
+       E = I[4]; W = I[5]; V = I[6]; N = I[7];
+
+       K0 = K[ 0]; K1 = K[ 1]; K2 = K[ 2]; K3 = K[ 3];
+       K4 = K[ 4]; K5 = K[ 5]; K6 = K[ 6]; K7 = K[ 7];
+       K8 = K[ 8]; T0 = K[ 9]; T1 = K[10]; T2 = K[11];
+
+       PROCESS_BLOCKP( 0,K1,K0,K3,K2,K5,T0,K4,K7,K6,T1);
+       PROCESS_BLOCKN( 1,K2,K1,K4,K3,K6,T1,K5,K8,K7,T2);
+       PROCESS_BLOCKP( 2,K3,K2,K5,K4,K7,T2,K6,K0,K8,T0);
+       PROCESS_BLOCKN( 3,K4,K3,K6,K5,K8,T0,K7,K1,K0,T1);
+
+       PROCESS_BLOCKP( 4,K5,K4,K7,K6,K0,T1,K8,K2,K1,T2);
+       PROCESS_BLOCKN( 5,K6,K5,K8,K7,K1,T2,K0,K3,K2,T0);
+       PROCESS_BLOCKP( 6,K7,K6,K0,K8,K2,T0,K1,K4,K3,T1);
+       PROCESS_BLOCKN( 7,K8,K7,K1,K0,K3,T1,K2,K5,K4,T2);
+
+       PROCESS_BLOCKP( 8,K0,K8,K2,K1,K4,T2,K3,K6,K5,T0);
+       PROCESS_BLOCKN( 9,K1,K0,K3,K2,K5,T0,K4,K7,K6,T1);
+       PROCESS_BLOCKP(10,K2,K1,K4,K3,K6,T1,K5,K8,K7,T2);
+       PROCESS_BLOCKN(11,K3,K2,K5,K4,K7,T2,K6,K0,K8,T0);
+
+       PROCESS_BLOCKP(12,K4,K3,K6,K5,K8,T0,K7,K1,K0,T1);
+       PROCESS_BLOCKN(13,K5,K4,K7,K6,K0,T1,K8,K2,K1,T2);
+       PROCESS_BLOCKP(14,K6,K5,K8,K7,K1,T2,K0,K3,K2,T0);
+       PROCESS_BLOCKN(15,K7,K6,K0,K8,K2,T0,K1,K4,K3,T1);
+
+       PROCESS_BLOCKP(16,K8,K7,K1,K0,K3,T1,K2,K5,K4,T2);
+       PROCESS_BLOCKN(17,K0,K8,K2,K1,K4,T2,K3,K6,K5,T0);
+
+       O[0] = X + K0; O[1] = Y + K1; O[2] = Z + K2; O[3] = T + K3;
+       O[4] = E + K4; O[5] = W + K5 + T0; O[6] = V + K6 + T1; O[7] = N + K7 + 18;
+}
+
+#elif defined(TF_1024BITS)
+
+#define PROCESS_BLOCKP(x,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,k11,k12,k13,k14,k15,k16,k17,k18)\
+       do {                                                                            \
+               KE_MIX(Y, X, k1, k2, TFS_KS01); KE_MIX(T, Z, k3, k4, TFS_KS02);         \
+               KE_MIX(W, E, k5, k6, TFS_KS03); KE_MIX(N, V, k7, k8, TFS_KS04);         \
+               KE_MIX(U, P, k9, k10, TFS_KS05); KE_MIX(Q, M, k11, k12, TFS_KS06);      \
+               KE_MIX(B, A, k13 + k14, k15, TFS_KS07);                                 \
+               KE_MIX(L, H, k16 + x, k17 + k18, TFS_KS08);                             \
+                                                                                       \
+               BE_MIX(X, U, TFS_BS01); BE_MIX(Z, B, TFS_BS02);                         \
+               BE_MIX(V, Q, TFS_BS03); BE_MIX(E, L, TFS_BS04);                         \
+               BE_MIX(M, N, TFS_BS05); BE_MIX(A, T, TFS_BS06);                         \
+               BE_MIX(H, W, TFS_BS07); BE_MIX(P, Y, TFS_BS08);                         \
+               BE_MIX(X, N, TFS_BS09); BE_MIX(Z, W, TFS_BS10);                         \
+               BE_MIX(E, T, TFS_BS11); BE_MIX(V, Y, TFS_BS12);                         \
+               BE_MIX(A, L, TFS_BS13); BE_MIX(H, B, TFS_BS14);                         \
+               BE_MIX(P, Q, TFS_BS15); BE_MIX(M, U, TFS_BS16);                         \
+               BE_MIX(X, L, TFS_BS17); BE_MIX(Z, Q, TFS_BS18);                         \
+               BE_MIX(V, B, TFS_BS19); BE_MIX(E, U, TFS_BS20);                         \
+               BE_MIX(H, Y, TFS_BS21); BE_MIX(P, W, TFS_BS22);                         \
+               BE_MIX(M, T, TFS_BS23); BE_MIX(A, N, TFS_BS24);                         \
+       } while (0)
+
+#define PROCESS_BLOCKN(x,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,k11,k12,k13,k14,k15,k16,k17,k18)\
+       do {                                                                            \
+               KE_MIX(Y, X, k1, k2, TFS_KS09); KE_MIX(T, Z, k3, k4, TFS_KS10);         \
+               KE_MIX(W, E, k5, k6, TFS_KS11); KE_MIX(N, V, k7, k8, TFS_KS12);         \
+               KE_MIX(U, P, k9, k10, TFS_KS13); KE_MIX(Q, M, k11, k12, TFS_KS14);      \
+               KE_MIX(B, A, k13 + k14, k15, TFS_KS15);                                 \
+               KE_MIX(L, H, k16 + x, k17 + k18, TFS_KS16);                             \
+                                                                                       \
+               BE_MIX(X, U, TFS_BS25); BE_MIX(Z, B, TFS_BS26);                         \
+               BE_MIX(V, Q, TFS_BS27); BE_MIX(E, L, TFS_BS28);                         \
+               BE_MIX(M, N, TFS_BS29); BE_MIX(A, T, TFS_BS30);                         \
+               BE_MIX(H, W, TFS_BS31); BE_MIX(P, Y, TFS_BS32);                         \
+               BE_MIX(X, N, TFS_BS33); BE_MIX(Z, W, TFS_BS34);                         \
+               BE_MIX(E, T, TFS_BS35); BE_MIX(V, Y, TFS_BS36);                         \
+               BE_MIX(A, L, TFS_BS37); BE_MIX(H, B, TFS_BS38);                         \
+               BE_MIX(P, Q, TFS_BS39); BE_MIX(M, U, TFS_BS40);                         \
+               BE_MIX(X, L, TFS_BS41); BE_MIX(Z, Q, TFS_BS42);                         \
+               BE_MIX(V, B, TFS_BS43); BE_MIX(E, U, TFS_BS44);                         \
+               BE_MIX(H, Y, TFS_BS45); BE_MIX(P, W, TFS_BS46);                         \
+               BE_MIX(M, T, TFS_BS47); BE_MIX(A, N, TFS_BS48);                         \
+       } while (0)
+
+void tf_encrypt_rawblk(TF_UNIT_TYPE *O, const TF_UNIT_TYPE *I, const TF_UNIT_TYPE *K)
+{
+       TF_UNIT_TYPE X, Y, Z, T;
+       TF_UNIT_TYPE E, W, V, N;
+       TF_UNIT_TYPE P, U, M, Q;
+       TF_UNIT_TYPE A, B, H, L;
+       TF_UNIT_TYPE K0, K1, K2, K3;
+       TF_UNIT_TYPE K4, K5, K6, K7;
+       TF_UNIT_TYPE K8, K9, K10, K11;
+       TF_UNIT_TYPE K12, K13, K14, K15;
+       TF_UNIT_TYPE K16, T0, T1, T2;
+
+       X = I[ 0]; Y = I[ 1]; Z = I[ 2]; T = I[ 3];
+       E = I[ 4]; W = I[ 5]; V = I[ 6]; N = I[ 7];
+       P = I[ 8]; U = I[ 9]; M = I[10]; Q = I[11];
+       A = I[12]; B = I[13]; H = I[14]; L = I[15];
+
+       K0  = K[ 0]; K1  = K[ 1]; K2  = K[ 2]; K3  = K[ 3];
+       K4  = K[ 4]; K5  = K[ 5]; K6  = K[ 6]; K7  = K[ 7];
+       K8  = K[ 8]; K9  = K[ 9]; K10 = K[10]; K11 = K[11];
+       K12 = K[12]; K13 = K[13]; K14 = K[14]; K15 = K[15];
+       K16 = K[16]; T0  = K[17]; T1  = K[18]; T2  = K[19];
+
+       PROCESS_BLOCKP( 0, K1, K0, K3, K2, K5, K4, K7, K6, K9, K8,K11,K10,K13, T0,K12,K15,K14, T1);
+       PROCESS_BLOCKN( 1, K2, K1, K4, K3, K6, K5, K8, K7,K10, K9,K12,K11,K14, T1,K13,K16,K15, T2);
+       PROCESS_BLOCKP( 2, K3, K2, K5, K4, K7, K6, K9, K8,K11,K10,K13,K12,K15, T2,K14, K0,K16, T0);
+       PROCESS_BLOCKN( 3, K4, K3, K6, K5, K8, K7,K10, K9,K12,K11,K14,K13,K16, T0,K15, K1, K0, T1);
+
+       PROCESS_BLOCKP( 4, K5, K4, K7, K6, K9, K8,K11,K10,K13,K12,K15,K14, K0, T1,K16, K2, K1, T2);
+       PROCESS_BLOCKN( 5, K6, K5, K8, K7,K10, K9,K12,K11,K14,K13,K16,K15, K1, T2, K0, K3, K2, T0);
+       PROCESS_BLOCKP( 6, K7, K6, K9, K8,K11,K10,K13,K12,K15,K14, K0,K16, K2, T0, K1, K4, K3, T1);
+       PROCESS_BLOCKN( 7, K8, K7,K10, K9,K12,K11,K14,K13,K16,K15, K1, K0, K3, T1, K2, K5, K4, T2);
+
+       PROCESS_BLOCKP( 8, K9, K8,K11,K10,K13,K12,K15,K14, K0,K16, K2, K1, K4, T2, K3, K6, K5, T0);
+       PROCESS_BLOCKN( 9,K10, K9,K12,K11,K14,K13,K16,K15, K1, K0, K3, K2, K5, T0, K4, K7, K6, T1);
+       PROCESS_BLOCKP(10,K11,K10,K13,K12,K15,K14, K0,K16, K2, K1, K4, K3, K6, T1, K5, K8, K7, T2);
+       PROCESS_BLOCKN(11,K12,K11,K14,K13,K16,K15, K1, K0, K3, K2, K5, K4, K7, T2, K6, K9, K8, T0);
+
+       PROCESS_BLOCKP(12,K13,K12,K15,K14, K0,K16, K2, K1, K4, K3, K6, K5, K8, T0, K7,K10, K9, T1);
+       PROCESS_BLOCKN(13,K14,K13,K16,K15, K1, K0, K3, K2, K5, K4, K7, K6, K9, T1, K8,K11,K10, T2);
+       PROCESS_BLOCKP(14,K15,K14, K0,K16, K2, K1, K4, K3, K6, K5, K8, K7,K10, T2, K9,K12,K11, T0);
+       PROCESS_BLOCKN(15,K16,K15, K1, K0, K3, K2, K5, K4, K7, K6, K9, K8,K11, T0,K10,K13,K12, T1);
+
+       PROCESS_BLOCKP(16, K0,K16, K2, K1, K4, K3, K6, K5, K8, K7,K10, K9,K12, T1,K11,K14,K13, T2);
+       PROCESS_BLOCKN(17, K1, K0, K3, K2, K5, K4, K7, K6, K9, K8,K11,K10,K13, T2,K12,K15,K14, T0);
+       PROCESS_BLOCKP(18, K2, K1, K4, K3, K6, K5, K8, K7,K10, K9,K12,K11,K14, T0,K13,K16,K15, T1);
+       PROCESS_BLOCKN(19, K3, K2, K5, K4, K7, K6, K9, K8,K11,K10,K13,K12,K15, T1,K14, K0,K16, T2);
+
+       O[0] = X + K3; O[1] = Y + K4; O[2] = Z + K5; O[3] = T + K6;
+       O[4] = E + K7; O[5] = W + K8; O[6] = V + K9; O[7] = N + K10;
+       O[8] = P + K11; O[9] = U + K12; O[10] = M + K13; O[11] = Q + K14;
+       O[12] = A + K15; O[13] = B + K16 + T2; O[14] = H + K0 + T0; O[15] = L + K1 + 20;
+}
+
+#endif
diff --git a/tfocb.c b/tfocb.c
new file mode 100644 (file)
index 0000000..6498d27
--- /dev/null
+++ b/tfocb.c
@@ -0,0 +1,187 @@
+#include <string.h>
+#include "tfdef.h"
+
+static inline void ocb_block(TF_UNIT_TYPE *x, int tag)
+{
+       TF_UNIT_TYPE c = (x[0] >> (TF_UNIT_BITS-1));
+       size_t i;
+
+       if (tag) goto _tag;
+       for (i = 0; i < TF_NR_BLOCK_UNITS-1; i++)
+               x[i] = ((x[i] << 1) | (x[i+1] >> (TF_UNIT_BITS-1)));
+       x[TF_NR_BLOCK_UNITS-1] = ((x[i-1] << 1) ^ (c*IRR_POLY_CONST));
+       return;
+
+_tag:  for (i = 0; i < TF_NR_BLOCK_UNITS-1; i++)
+               x[i] ^= ((x[i] << 1) | (x[i+1] >> (TF_UNIT_BITS-1)));
+       x[TF_NR_BLOCK_UNITS-1] ^= ((x[i-1] << 1) ^ (c*IRR_POLY_CONST));
+}
+
+static void ocb_encrypt(const void *key, void *ctr, void *out, void *tag, const void *in, size_t sz)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out, *s, *d;
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE tctr[TF_NR_BLOCK_UNITS], c[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE *uctr = ctr, *utag = tag;
+       const TF_UNIT_TYPE *ukey = key;
+       size_t sl = sz, i;
+
+       tf_encrypt_rawblk(tctr, uctr, ukey);
+       if (tag) {
+               memcpy(c, tag, TF_BLOCK_SIZE);
+               data_to_words(c, TF_BLOCK_SIZE);
+       }
+
+       if (sl >= TF_BLOCK_SIZE) {
+               do {
+                       memcpy(x, uin, TF_BLOCK_SIZE);
+                       uin += TF_BLOCK_SIZE;
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+                       ocb_block(tctr, 0);
+                       if (tag) for (i = 0; i < TF_NR_BLOCK_UNITS; i++) c[i] ^= x[i];
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+                       tf_encrypt_rawblk(y, x, ukey);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= tctr[i];
+
+                       data_to_words(y, TF_BLOCK_SIZE);
+                       memcpy(uout, y, TF_BLOCK_SIZE);
+                       uout += TF_BLOCK_SIZE;
+               } while ((sl -= TF_BLOCK_SIZE) >= TF_BLOCK_SIZE);
+       }
+
+       if (sl) {
+               ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+               ocb_block(tctr, 0);
+               memset(x, 0, TF_BLOCK_SIZE);
+               x[TF_NR_BLOCK_UNITS-1] = (TF_TO_BITS(sl));
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+               tf_encrypt_rawblk(y, x, ukey);
+
+               memcpy(x, uin, sl);
+               data_to_words(x, sl);
+               s = (TF_BYTE_TYPE *)x; d = (TF_BYTE_TYPE *)y;
+               memcpy(s+sl, d+sl, TF_BLOCK_SIZE-sl);
+               if (tag) for (i = 0; i < TF_NR_BLOCK_UNITS; i++) c[i] ^= x[i];
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= y[i];
+
+               data_to_words(x, sl);
+               memcpy(uout, x, sl);
+       }
+
+       if (!tag) goto _done;
+
+       ocb_block(tctr, 1);
+       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] = tctr[i] ^ c[i];
+       tf_encrypt_rawblk(y, x, ukey);
+       data_to_words(y, TF_BLOCK_SIZE);
+       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) utag[i] ^= y[i];
+
+_done: memset(tctr, 0, TF_BLOCK_SIZE);
+       memset(c, 0, TF_BLOCK_SIZE);
+       memset(x, 0, TF_BLOCK_SIZE);
+       memset(y, 0, TF_BLOCK_SIZE);
+}
+
+void tf_ocb_encrypt(const void *key, void *ctr, void *out, void *tag, const void *in, size_t sz, size_t bpi)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       size_t sl = sz, sx = TF_BLOCKS_TO_BYTES(bpi);
+
+       if (sl >= sx) {
+               do {
+                       ocb_encrypt(key, ctr, uout, tag, uin, sx);
+                       uout += sx;
+                       uin += sx;
+               } while ((sl -= sx) >= sx);
+       }
+
+       if (sl) ocb_encrypt(key, ctr, uout, tag, uin, sl);
+}
+
+static void ocb_decrypt(const void *key, void *ctr, void *out, void *tag, const void *in, size_t sz)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE tctr[TF_NR_BLOCK_UNITS], c[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE *uctr = ctr, *utag = tag;
+       const TF_UNIT_TYPE *ukey = key;
+       size_t sl = sz, i;
+
+       tf_encrypt_rawblk(tctr, uctr, ukey);
+       if (tag) {
+               memcpy(c, tag, TF_BLOCK_SIZE);
+               data_to_words(c, TF_BLOCK_SIZE);
+       }
+
+       if (sl >= TF_BLOCK_SIZE) {
+               do {
+                       memcpy(x, uin, TF_BLOCK_SIZE);
+                       uin += TF_BLOCK_SIZE;
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+                       ocb_block(tctr, 0);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+                       tf_decrypt_rawblk(y, x, ukey);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= tctr[i];
+                       if (tag) for (i = 0; i < TF_NR_BLOCK_UNITS; i++) c[i] ^= y[i];
+
+                       data_to_words(y, TF_BLOCK_SIZE);
+                       memcpy(uout, y, TF_BLOCK_SIZE);
+                       uout += TF_BLOCK_SIZE;
+               } while ((sl -= TF_BLOCK_SIZE) >= TF_BLOCK_SIZE);
+       }
+
+       if (sl) {
+               ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+               ocb_block(tctr, 0);
+               memset(x, 0, TF_BLOCK_SIZE);
+               x[TF_NR_BLOCK_UNITS-1] = (TF_TO_BITS(sl));
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+               tf_encrypt_rawblk(y, x, ukey);
+
+               memset(x, 0, TF_BLOCK_SIZE);
+               memcpy(x, uin, sl);
+               data_to_words(x, sl);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= y[i];
+               if (tag) for (i = 0; i < TF_NR_BLOCK_UNITS; i++) c[i] ^= x[i];
+
+               data_to_words(x, sl);
+               memcpy(uout, x, sl);
+       }
+
+       if (!tag) goto _done;
+
+       ocb_block(tctr, 1);
+       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] = tctr[i] ^ c[i];
+       tf_encrypt_rawblk(y, x, ukey);
+       data_to_words(y, TF_BLOCK_SIZE);
+       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) utag[i] ^= y[i];
+
+_done: memset(tctr, 0, TF_BLOCK_SIZE);
+       memset(c, 0, TF_BLOCK_SIZE);
+       memset(x, 0, TF_BLOCK_SIZE);
+       memset(y, 0, TF_BLOCK_SIZE);
+}
+
+void tf_ocb_decrypt(const void *key, void *ctr, void *out, void *tag, const void *in, size_t sz, size_t bpi)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       size_t sl = sz, sx = TF_BLOCKS_TO_BYTES(bpi);
+
+       if (sl >= sx) {
+               do {
+                       ocb_decrypt(key, ctr, uout, tag, uin, sx);
+                       uout += sx;
+                       uin += sx;
+               } while ((sl -= sx) >= sx);
+       }
+
+       if (sl) ocb_decrypt(key, ctr, uout, tag, uin, sl);
+}
diff --git a/tfprng.c b/tfprng.c
new file mode 100644 (file)
index 0000000..934f38e
--- /dev/null
+++ b/tfprng.c
@@ -0,0 +1,104 @@
+#include <string.h>
+#include "tfe.h"
+#include "tfprng.h"
+
+struct tf_prng_data {
+       struct tfe_stream tfe;
+       short init;
+};
+
+struct tf_prng_data tf_prng_sdata;
+
+size_t tf_prng_datasize(void)
+{
+       return sizeof(struct tf_prng_data);
+}
+
+void tf_prng_seedkey_r(void *sdata, const void *skey)
+{
+       TF_UNIT_TYPE k[TF_NR_KEY_UNITS];
+       struct tf_prng_data *rprng = sdata;
+
+       memset(rprng, 0, sizeof(struct tf_prng_data));
+       if (!skey) return;
+
+       memcpy(k, skey, TF_KEY_SIZE);
+       tfe_init(&rprng->tfe, k);
+       rprng->init = 1;
+
+       memset(k, 0, TF_KEY_SIZE);
+}
+
+void tf_prng_seedkey(const void *skey)
+{
+       tf_prng_seedkey_r(&tf_prng_sdata, skey);
+}
+
+void tf_prng_genrandom_r(void *sdata, void *result, size_t need)
+{
+       struct tf_prng_data *rprng = sdata;
+       memset(result, 0, need);
+       tfe_emit(result, need, &rprng->tfe);
+}
+
+void tf_prng_genrandom(void *result, size_t need)
+{
+       tf_prng_genrandom_r(&tf_prng_sdata, result, need);
+}
+
+void tf_prng_seed_r(void *sdata, TF_UNIT_TYPE seed)
+{
+       TF_UNIT_TYPE k[TF_NR_KEY_UNITS];
+       struct tf_prng_data *rprng = sdata;
+       size_t x;
+
+       memset(rprng, 0, sizeof(struct tf_prng_data));
+       for (x = 0; x < TF_NR_KEY_UNITS; x++) k[x] = seed;
+       tfe_init(&rprng->tfe, k);
+       rprng->init = 1;
+
+       memset(k, 0, TF_KEY_SIZE);
+}
+
+void tf_prng_seed(TF_UNIT_TYPE seed)
+{
+       tf_prng_seed_r(&tf_prng_sdata, seed);
+}
+
+TF_UNIT_TYPE tf_prng_random_r(void *sdata)
+{
+       struct tf_prng_data *rprng = sdata;
+       TF_UNIT_TYPE r;
+
+       if (!rprng->init) return 0;
+
+       tfe_emit(&r, sizeof(r), &rprng->tfe);
+       return r;
+}
+
+TF_UNIT_TYPE tf_prng_random(void)
+{
+       return tf_prng_random_r(&tf_prng_sdata);
+}
+
+TF_UNIT_TYPE tf_prng_range_r(void *sdata, TF_UNIT_TYPE s, TF_UNIT_TYPE d)
+{
+       TF_UNIT_TYPE c = tf_prng_random_r(sdata);
+       if (d <= s) return s;
+       return s + c / ((TF_UNIT_TYPE)~0 / (d - s + 1) + 1);
+}
+
+TF_UNIT_TYPE tf_prng_range(TF_UNIT_TYPE s, TF_UNIT_TYPE d)
+{
+       return tf_prng_range_r(&tf_prng_sdata, s, d);
+}
+
+void tf_prng_srand(unsigned seed)
+{
+       tf_prng_seed((TF_UNIT_TYPE)seed);
+}
+
+int tf_prng_rand(void)
+{
+       return (int)tf_prng_range(0, (TF_UNIT_TYPE)TF_PRNG_LEGACY_RAND_MAX);
+}
diff --git a/tfprng.h b/tfprng.h
new file mode 100644 (file)
index 0000000..c5e84cb
--- /dev/null
+++ b/tfprng.h
@@ -0,0 +1,26 @@
+#ifndef _TF_PRNG_DEFINITIONS_HEADER
+#define _TF_PRNG_DEFINITIONS_HEADER
+
+#include <stdlib.h>
+#include "tfdef.h"
+
+#define TF_PRNG_KEY_SIZE TF_KEY_SIZE
+#define TF_PRNG_SIZE_UNIT TF_SIZE_UNIT
+
+#define TF_PRNG_LEGACY_RAND_MAX RAND_MAX
+
+size_t tf_prng_datasize(void);
+void tf_prng_seedkey_r(void *sdata, const void *skey);
+void tf_prng_seedkey(const void *skey);
+void tf_prng_genrandom_r(void *sdata, void *result, size_t need);
+void tf_prng_genrandom(void *result, size_t need);
+void tf_prng_seed_r(void *sdata, TF_UNIT_TYPE seed);
+void tf_prng_seed(TF_UNIT_TYPE seed);
+TF_UNIT_TYPE tf_prng_random_r(void *sdata);
+TF_UNIT_TYPE tf_prng_random(void);
+TF_UNIT_TYPE tf_prng_range_r(void *sdata, TF_UNIT_TYPE s, TF_UNIT_TYPE d);
+TF_UNIT_TYPE tf_prng_range(TF_UNIT_TYPE s, TF_UNIT_TYPE d);
+void tf_prng_srand(unsigned seed);
+int tf_prng_rand(void);
+
+#endif
diff --git a/tfstream.c b/tfstream.c
new file mode 100644 (file)
index 0000000..b64d4d9
--- /dev/null
@@ -0,0 +1,22 @@
+#include <string.h>
+#include "tfdef.h"
+#include "tfe.h"
+
+void tf_stream_crypt(struct tfe_stream *tfe, void *out, const void *in, size_t sz)
+{
+       const TF_UNIT_TYPE *uin = in;
+       TF_UNIT_TYPE *uout = out;
+       const TF_BYTE_TYPE *uuin = in;
+       TF_BYTE_TYPE *uuout = out;
+       size_t n, z, x;
+
+       switch (TF_SIZE_UNIT) {
+               case 2: n = 1; break;
+               case 4: n = 2; break;
+               case 8: n = 3; break;
+       }
+
+       tfe_emit(out, sz, tfe);
+       for (z = 0; z < (sz >> n); z++) uout[z] ^= uin[z];
+       if (sz - (z << n)) for (x = (z << n); x < sz; x++) uuout[x] ^= uuin[x];
+}
diff --git a/tfxts.c b/tfxts.c
new file mode 100644 (file)
index 0000000..cf5d423
--- /dev/null
+++ b/tfxts.c
@@ -0,0 +1,219 @@
+#include <string.h>
+#include "tfdef.h"
+
+static inline void xts_mult_x(TF_UNIT_TYPE *x)
+{
+       size_t i, t, tt;
+
+       for (i = t = 0; i < TF_NR_BLOCK_UNITS; i++) {
+               tt = x[i] >> (TF_UNIT_BITS-1);
+               x[i] = ((x[i] << 1) | t) & ((TF_UNIT_TYPE)~0);
+               t = tt;
+       }
+       if (tt) x[0] ^= IRR_POLY_CONST;
+}
+
+static void xts_encrypt(const void *keyx, const void *keyz, void *ctr, void *out, const void *in, size_t sz)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE tctr[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE *uctr = ctr;
+       const TF_UNIT_TYPE *ukeyx = keyx, *ukeyz = keyz;
+       size_t sl = sz, i;
+
+       tf_encrypt_rawblk(tctr, uctr, ukeyz);
+
+       if (sl >= (TF_BLOCK_SIZE * 2)) {
+               do {
+_last:                 memcpy(x, uin, TF_BLOCK_SIZE);
+                       uin += TF_BLOCK_SIZE;
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] = x[i] ^ tctr[i];
+                       tf_encrypt_rawblk(x, y, ukeyx);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+
+                       xts_mult_x(tctr);
+
+                       data_to_words(x, TF_BLOCK_SIZE);
+                       memcpy(uout, x, TF_BLOCK_SIZE);
+                       uout += TF_BLOCK_SIZE;
+               } while ((sl -= TF_BLOCK_SIZE) >= (TF_BLOCK_SIZE * 2));
+       }
+
+       if (sl) {
+               if (sl-TF_BLOCK_SIZE == 0) goto _last;
+               if (sl < TF_BLOCK_SIZE) {
+                       memset(x, 0, TF_BLOCK_SIZE);
+                       memcpy(x, uin, sl);
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+                       tf_encrypt_rawblk(y, uctr, ukeyx);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= x[i];
+
+                       data_to_words(y, TF_BLOCK_SIZE);
+                       memcpy(uout, y, sl);
+
+                       goto _done;
+               }
+
+               memcpy(x, uin, TF_BLOCK_SIZE);
+               uin += TF_BLOCK_SIZE;
+               data_to_words(x, TF_BLOCK_SIZE);
+
+               ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] = x[i] ^ tctr[i];
+               tf_encrypt_rawblk(x, y, ukeyx);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+
+               memcpy(y, x, TF_BLOCK_SIZE);
+               sl -= TF_BLOCK_SIZE;
+
+               xts_mult_x(tctr);
+
+               tf_encrypt_rawblk(tctr, uctr, ukeyz);
+
+               memcpy(x, uin, sl);
+               data_to_words(x, sl);
+
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+               tf_encrypt_rawblk(x, x, ukeyx);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+
+               data_to_words(x, TF_BLOCK_SIZE);
+               memcpy(uout, x, TF_BLOCK_SIZE);
+               uout += TF_BLOCK_SIZE;
+
+               data_to_words(y, TF_BLOCK_SIZE);
+               memcpy(uout, y, sl);
+       }
+
+_done: memset(tctr, 0, TF_BLOCK_SIZE);
+       memset(x, 0, TF_BLOCK_SIZE);
+       memset(y, 0, TF_BLOCK_SIZE);
+}
+
+void tf_xts_encrypt(const void *keyx, const void *keyz, void *ctr, void *out, const void *in, size_t sz, size_t bpi)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       size_t sl = sz, sx = TF_BLOCKS_TO_BYTES(bpi);
+
+       if (sl >= sx) {
+               do {
+                       xts_encrypt(keyx, keyz, ctr, uout, uin, sx);
+                       uout += sx;
+                       uin += sx;
+               } while ((sl -= sx) >= sx);
+       }
+
+       if (sl) xts_encrypt(keyx, keyz, ctr, uout, uin, sl);
+}
+
+static void xts_decrypt(const void *keyx, const void *keyz, void *ctr, void *out, const void *in, size_t sz)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out, *s, *d;
+       TF_UNIT_TYPE x[TF_NR_BLOCK_UNITS], y[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE tctr[TF_NR_BLOCK_UNITS], zctr[TF_NR_BLOCK_UNITS];
+       TF_UNIT_TYPE *uctr = ctr;
+       const TF_UNIT_TYPE *ukeyx = keyx, *ukeyz = keyz;
+       size_t sl = sz, i;
+
+       tf_encrypt_rawblk(tctr, uctr, ukeyz);
+
+       if (sl >= (TF_BLOCK_SIZE * 2)) {
+               do {
+_last:                 memcpy(x, uin, TF_BLOCK_SIZE);
+                       uin += TF_BLOCK_SIZE;
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] = x[i] ^ tctr[i];
+                       tf_decrypt_rawblk(x, y, ukeyx);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+
+                       xts_mult_x(tctr);
+
+                       data_to_words(x, TF_BLOCK_SIZE);
+                       memcpy(uout, x, TF_BLOCK_SIZE);
+                       uout += TF_BLOCK_SIZE;
+               } while ((sl -= TF_BLOCK_SIZE) >= (TF_BLOCK_SIZE * 2));
+       }
+
+       if (sl) {
+               if (sl-TF_BLOCK_SIZE == 0) goto _last;
+               if (sl < TF_BLOCK_SIZE) {
+                       memset(x, 0, TF_BLOCK_SIZE);
+                       memcpy(x, uin, sl);
+                       data_to_words(x, TF_BLOCK_SIZE);
+
+                       ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+                       tf_encrypt_rawblk(y, uctr, ukeyx);
+                       for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= x[i];
+
+                       data_to_words(y, TF_BLOCK_SIZE);
+                       memcpy(uout, y, sl);
+
+                       goto _done;
+               }
+
+               memcpy(x, uin, TF_BLOCK_SIZE);
+               uin += TF_BLOCK_SIZE;
+               data_to_words(x, TF_BLOCK_SIZE);
+
+               ctr_inc(uctr, TF_NR_BLOCK_UNITS);
+               memcpy(zctr, tctr, TF_BLOCK_SIZE);
+               xts_mult_x(tctr);
+
+               tf_encrypt_rawblk(tctr, uctr, ukeyz);
+
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+               tf_decrypt_rawblk(x, x, ukeyx);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) x[i] ^= tctr[i];
+
+               sl -= TF_BLOCK_SIZE;
+               memcpy(y, uin, sl);
+               data_to_words(y, sl);
+
+               s = (TF_BYTE_TYPE *)y;
+               d = (TF_BYTE_TYPE *)x;
+               memcpy(s+sl, d+sl, TF_BLOCK_SIZE-sl);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= zctr[i];
+               tf_decrypt_rawblk(y, y, ukeyx);
+               for (i = 0; i < TF_NR_BLOCK_UNITS; i++) y[i] ^= zctr[i];
+
+               data_to_words(y, TF_BLOCK_SIZE);
+               memcpy(uout, y, TF_BLOCK_SIZE);
+               uout += TF_BLOCK_SIZE;
+
+               data_to_words(x, TF_BLOCK_SIZE);
+               memcpy(uout, x, sl);
+       }
+
+_done: memset(tctr, 0, TF_BLOCK_SIZE);
+       memset(zctr, 0, TF_BLOCK_SIZE);
+       memset(x, 0, TF_BLOCK_SIZE);
+       memset(y, 0, TF_BLOCK_SIZE);
+}
+
+void tf_xts_decrypt(const void *keyx, const void *keyz, void *ctr, void *out, const void *in, size_t sz, size_t bpi)
+{
+       const TF_BYTE_TYPE *uin = in;
+       TF_BYTE_TYPE *uout = out;
+       size_t sl = sz, sx = TF_BLOCKS_TO_BYTES(bpi);
+
+       if (sl >= sx) {
+               do {
+                       xts_decrypt(keyx, keyz, ctr, uout, uin, sx);
+                       uout += sx;
+                       uin += sx;
+               } while ((sl -= sx) >= sx);
+       }
+
+       if (sl) xts_decrypt(keyx, keyz, ctr, uout, uin, sl);
+}