From: Andrey Rys Date: Mon, 12 Nov 2018 05:58:34 +0000 (+0700) Subject: tfcrypt 1. X-Git-Url: https://jxself.org/git/?p=tfcrypt.git;a=commitdiff_plain;h=efa545d64b910923248233618e774ca3b87efebb tfcrypt 1. --- efa545d64b910923248233618e774ca3b87efebb 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); +}