From efa545d64b910923248233618e774ca3b87efebb Mon Sep 17 00:00:00 2001 From: Andrey Rys Date: Mon, 12 Nov 2018 12:58:34 +0700 Subject: [PATCH] tfcrypt 1. --- .gitignore | 13 + COPYRIGHT | 23 + Makefile | 36 ++ README | 65 +++ VERSION | 1 + base64.c | 247 +++++++++++ base64.h | 35 ++ getpasswd.c | 179 ++++++++ getpasswd.h | 57 +++ mhexdump.c | 125 ++++++ skein.c | 131 ++++++ skein.h | 29 ++ tfc_base64.c | 174 ++++++++ tfc_bench.c | 91 ++++ tfc_conv.c | 163 +++++++ tfc_error.c | 260 +++++++++++ tfc_misc.c | 234 ++++++++++ tfc_random.c | 162 +++++++ tfc_say.c | 68 +++ tfc_signal.c | 163 +++++++ tfc_skein.c | 299 +++++++++++++ tfc_vars.c | 75 ++++ tfcbc.c | 88 ++++ tfcore.h | 86 ++++ tfcrypt.c | 1177 ++++++++++++++++++++++++++++++++++++++++++++++++++ tfcrypt.h | 215 +++++++++ tfctr.c | 44 ++ tfctrapi.c | 14 + tfdec.c | 245 +++++++++++ tfdef.h | 136 ++++++ tfe.c | 63 +++ tfe.h | 17 + tfecb.c | 80 ++++ tfenc.c | 235 ++++++++++ tfocb.c | 187 ++++++++ tfprng.c | 104 +++++ tfprng.h | 26 ++ tfstream.c | 22 + tfxts.c | 219 ++++++++++ 39 files changed, 5588 insertions(+) create mode 100644 .gitignore create mode 100644 COPYRIGHT create mode 100644 Makefile create mode 100644 README create mode 100644 VERSION create mode 100644 base64.c create mode 100644 base64.h create mode 100644 getpasswd.c create mode 100644 getpasswd.h create mode 100644 mhexdump.c create mode 100644 skein.c create mode 100644 skein.h create mode 100644 tfc_base64.c create mode 100644 tfc_bench.c create mode 100644 tfc_conv.c create mode 100644 tfc_error.c create mode 100644 tfc_misc.c create mode 100644 tfc_random.c create mode 100644 tfc_say.c create mode 100644 tfc_signal.c create mode 100644 tfc_skein.c create mode 100644 tfc_vars.c create mode 100644 tfcbc.c create mode 100644 tfcore.h create mode 100644 tfcrypt.c create mode 100644 tfcrypt.h create mode 100644 tfctr.c create mode 100644 tfctrapi.c create mode 100644 tfdec.c create mode 100644 tfdef.h create mode 100644 tfe.c create mode 100644 tfe.h create mode 100644 tfecb.c create mode 100644 tfenc.c create mode 100644 tfocb.c create mode 100644 tfprng.c create mode 100644 tfprng.h create mode 100644 tfstream.c create mode 100644 tfxts.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..923d987 --- /dev/null +++ b/.gitignore @@ -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 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 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 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 , 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 index 0000000..d00491f --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1 diff --git a/base64.c b/base64.c new file mode 100644 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 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 +#include + +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 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 index 0000000..633b3fd --- /dev/null +++ b/getpasswd.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000..a6dbd56 --- /dev/null +++ b/getpasswd.h @@ -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 index 0000000..5d927f7 --- /dev/null +++ b/mhexdump.c @@ -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 +#include + +#include +#include +#include + +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 index 0000000..b1da775 --- /dev/null +++ b/skein.c @@ -0,0 +1,131 @@ +#include +#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 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 index 0000000..b92ac96 --- /dev/null +++ b/tfc_base64.c @@ -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 index 0000000..595009e --- /dev/null +++ b/tfc_bench.c @@ -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 index 0000000..045c06d --- /dev/null +++ b/tfc_conv.c @@ -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 index 0000000..7c001da --- /dev/null +++ b/tfc_error.c @@ -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 ] [-U ] [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 : read hashes list from file and check them."); + tfc_say(" -U : 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 : 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 : 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(" : 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 : 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/: 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(" : write a detached MAC signature into separate ,"); + 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(" : write a detached MAC signature into separate ,"); + 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 index 0000000..d1bb783 --- /dev/null +++ b/tfc_misc.c @@ -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 index 0000000..4b82aee --- /dev/null +++ b/tfc_random.c @@ -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 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 index 0000000..3cb10b8 --- /dev/null +++ b/tfc_signal.c @@ -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(¤t_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 index 0000000..369fc23 --- /dev/null +++ b/tfc_skein.c @@ -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 index 0000000..7f78b84 --- /dev/null +++ b/tfc_vars.c @@ -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 index 0000000..2d47fe8 --- /dev/null +++ b/tfcbc.c @@ -0,0 +1,88 @@ +#include +#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 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 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 index 0000000..7cc79c6 --- /dev/null +++ b/tfctr.c @@ -0,0 +1,44 @@ +#include +#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 index 0000000..fcd14ee --- /dev/null +++ b/tfctrapi.c @@ -0,0 +1,14 @@ +#include +#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 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 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 +#include +#ifndef TF_NO_ENDIAN +#include +#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 index 0000000..544bcc7 --- /dev/null +++ b/tfe.c @@ -0,0 +1,63 @@ +#include +#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 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 index 0000000..0d24782 --- /dev/null +++ b/tfecb.c @@ -0,0 +1,80 @@ +#include +#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 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 index 0000000..6498d27 --- /dev/null +++ b/tfocb.c @@ -0,0 +1,187 @@ +#include +#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 index 0000000..934f38e --- /dev/null +++ b/tfprng.c @@ -0,0 +1,104 @@ +#include +#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 index 0000000..c5e84cb --- /dev/null +++ b/tfprng.h @@ -0,0 +1,26 @@ +#ifndef _TF_PRNG_DEFINITIONS_HEADER +#define _TF_PRNG_DEFINITIONS_HEADER + +#include +#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 index 0000000..b64d4d9 --- /dev/null +++ b/tfstream.c @@ -0,0 +1,22 @@ +#include +#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 index 0000000..cf5d423 --- /dev/null +++ b/tfxts.c @@ -0,0 +1,219 @@ +#include +#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); +} -- 2.31.1