diff --git a/CMakeLists.txt b/CMakeLists.txt index 1092e46..753e3c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,7 +96,7 @@ add_library(n2n STATIC src/sn_utils.c src/wire.c src/minilzo.c - src/twofish.c + src/tf.c src/transform_null.c src/transform_tf.c src/transform_aes.c diff --git a/include/n2n.h b/include/n2n.h index 8c0e4fa..dc08248 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -406,7 +406,7 @@ typedef struct n2n_sn /* ************************************** */ #include "header_encryption.h" -#include "twofish.h" +#include "tf.h" #ifndef TRACE_ERROR #define TRACE_ERROR 0, __FILE__, __LINE__ @@ -420,7 +420,7 @@ typedef struct n2n_sn /* Transop Init Functions */ int n2n_transop_null_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); -int n2n_transop_twofish_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); +int n2n_transop_tf_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); #ifdef N2N_HAVE_AES int n2n_transop_aes_cbc_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt); #endif diff --git a/include/tf.h b/include/tf.h new file mode 100644 index 0000000..f4ea3cc --- /dev/null +++ b/include/tf.h @@ -0,0 +1,82 @@ +/** + * (C) 2007-20 - ntop.org and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not see see + * + */ + + +// taken (and modified) from github/fudanchii/twofish as of August 2020 +// which itself is a modified copy of Andrew T. Csillag's implementation +// published on github/drewcsillag/twofish + + +/* +The MIT License (MIT) + +Copyright (c) 2015 Andrew T. Csillag + +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 TF_H +#define TF_H + +#include +#include +#include + + +#define TF_BLOCK_SIZE 16 +#define TF_IV_SIZE (TF_BLOCK_SIZE) + + +typedef struct tf_context_t { + int N; + uint32_t K[40]; + uint32_t QF[4][256]; +} tf_context_t; + + +int tf_ecb_decrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx); + +int tf_ecb_encrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx); + +int tf_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, tf_context_t *ctx); + +int tf_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, tf_context_t *ctx); + +int tf_init (const unsigned char *key, size_t key_size, tf_context_t **ctx); + + +#endif // TF_H diff --git a/include/twofish.h b/include/twofish.h deleted file mode 100644 index d42e640..0000000 --- a/include/twofish.h +++ /dev/null @@ -1,284 +0,0 @@ -/* $Id: twofish.h,v 2.0 2002/08/11 22:32:25 fknobbe Exp $ - * - * - * Copyright (C) 1997-2000 The Cryptix Foundation Limited. - * Copyright (C) 2000 Farm9. - * Copyright (C) 2001 Frank Knobbe. - * All rights reserved. - * - * For Cryptix code: - * Use, modification, copying and distribution of this software is subject - * the terms and conditions of the Cryptix General Licence. You should have - * received a copy of the Cryptix General Licence along with this library; - * if not, you can download a copy from http://www.cryptix.org/ . - * - * For Farm9: - * --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and - * ciphertext stealing technique, added AsciiTwofish class for easy encryption - * decryption of text strings - * - * Frank Knobbe : - * --- April 2001, converted from C++ to C, prefixed global variables - * with TwoFish, substituted some defines, changed functions to make use of - * variables supplied in a struct, modified and added routines for modular calls. - * Cleaned up the code so that defines are used instead of fixed 16's and 32's. - * Created two general purpose crypt routines for one block and multiple block - * encryption using Joh's CBC code. - * Added crypt routines that use a header (with a magic and data length). - * (Basically a major rewrite). - * - * Note: Routines labeled _TwoFish are private and should not be used - * (or with extreme caution). - * - */ - -#ifndef __TWOFISH_LIBRARY_HEADER__ -#define __TWOFISH_LIBRARY_HEADER__ - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE !FALSE -#endif -#ifndef bool -#define bool int -#endif - -#ifdef WIN32 -#include "win32/n2n_win32.h" -#endif - -#ifndef _MSC_VER -/* Not shipped with Visual Studio (as stated by the stdint.h wikipedia page) */ -#include /* defines uintN_t types */ -#endif - -#ifdef __sun__ /* Should be HAVE_SYS_TYPES */ -/* The following are redefinitions if sys/types.h has been included too.*/ -typedef uint32_t uint32_t; -typedef uint8_t uint8_t; -#endif /* #ifdef __sun__ */ - -/* Constants */ - -#define TwoFish_DEFAULT_PW_LEN 32 -#define TwoFish_MAGIC "TwoFish" /* to indentify a successful decryption */ - -enum -{ TwoFish_KEY_SIZE = 256, /* Valid values: 64, 128, 192, 256 */ - /* User 256, other key sizes have not been tested. */ - /* (But should work. I substitutes as much as */ - /* I could with this define.) */ - TwoFish_ROUNDS = 16, - TwoFish_BLOCK_SIZE = 16, /* bytes in a data-block */ - TwoFish_KEY_LENGTH = TwoFish_KEY_SIZE/8, /* 32= 256-bit key */ - TwoFish_TOTAL_SUBKEYS = 4+4+2*TwoFish_ROUNDS, - TwoFish_MAGIC_LEN = TwoFish_BLOCK_SIZE-8, - TwoFish_SK_BUMP = 0x01010101, - TwoFish_SK_ROTL = 9, - TwoFish_P_00 = 1, - TwoFish_P_01 = 0, - TwoFish_P_02 = 0, - TwoFish_P_03 = TwoFish_P_01 ^ 1, - TwoFish_P_04 = 1, - TwoFish_P_10 = 0, - TwoFish_P_11 = 0, - TwoFish_P_12 = 1, - TwoFish_P_13 = TwoFish_P_11 ^ 1, - TwoFish_P_14 = 0, - TwoFish_P_20 = 1, - TwoFish_P_21 = 1, - TwoFish_P_22 = 0, - TwoFish_P_23 = TwoFish_P_21 ^ 1, - TwoFish_P_24 = 0, - TwoFish_P_30 = 0, - TwoFish_P_31 = 1, - TwoFish_P_32 = 1, - TwoFish_P_33 = TwoFish_P_31 ^ 1, - TwoFish_P_34 = 1, - TwoFish_GF256_FDBK = 0x169, - TwoFish_GF256_FDBK_2 = 0x169 / 2, - TwoFish_GF256_FDBK_4 = 0x169 / 4, - TwoFish_RS_GF_FDBK = 0x14D, /* field generator */ - TwoFish_MDS_GF_FDBK = 0x169 /* primitive polynomial for GF(256) */ -}; - - -/* Global data structure for callers */ - -typedef struct -{ - uint32_t sBox[4 * 256]; /* Key dependent S-box */ - uint32_t subKeys[TwoFish_TOTAL_SUBKEYS]; /* Subkeys */ - uint8_t key[TwoFish_KEY_LENGTH]; /* Encryption Key */ - uint8_t *output; /* Pointer to output buffer */ - uint8_t qBlockPlain[TwoFish_BLOCK_SIZE]; /* Used by CBC */ - uint8_t qBlockCrypt[TwoFish_BLOCK_SIZE]; - uint8_t prevCipher[TwoFish_BLOCK_SIZE]; - struct /* Header for crypt functions. Has to be at least one block long. */ - { uint32_t salt; /* Random salt in first block (will salt the rest through CBC) */ - uint8_t length[4]; /* The amount of data following the header */ - uint8_t magic[TwoFish_MAGIC_LEN]; /* Magic to identify successful decryption */ - } header; - bool qBlockDefined; - bool dontflush; -} TWOFISH; - -/**** Public Functions ****/ - -/* TwoFish Initialization - * - * This routine generates a global data structure for use with TwoFish, - * initializes important values (such as subkeys, sBoxes), generates subkeys - * and precomputes the MDS matrix if not already done. - * - * Input: User supplied key of correct length (TwoFish_KEY_LENGTH, 256 bits = 32 bytes by default) - * - * Output: Pointer to TWOFISH structure. This data structure contains key dependent data. - * This pointer is used with all other crypt functions. - */ -TWOFISH *TwoFishInit(const uint8_t *userkey); - - -/* TwoFish Destroy - * - * Nothing else but a free... - * - * Input: Pointer to the TwoFish structure. - * - */ -void TwoFishDestroy(TWOFISH *tfdata); - - -/* TwoFish Alloc - * - * Allocates enough memory for the output buffer as required. - * - * Input: Length of the plaintext. - * Boolean flag for BinHex Output. - * Pointer to the TwoFish structure. - * - * Output: Returns a pointer to the memory allocated. - */ -void *TwoFishAlloc(uint32_t len,bool binhex,bool decrypt,TWOFISH *tfdata); - - -/* TwoFish Free - * - * Free's the allocated buffer. - * - * Input: Pointer to the TwoFish structure - * - * Output: (none) - */ -void TwoFishFree(TWOFISH *tfdata); - - -/* TwoFish Set Output - * - * If you want to allocate the output buffer yourself, - * then you can set it with this function. - * - * Input: Pointer to your output buffer - * Pointer to the TwoFish structure - * - * Output: (none) - */ -void TwoFishSetOutput(uint8_t *outp,TWOFISH *tfdata); - - -/* TwoFish Raw Encryption - * - * Does not use header, but does use CBC (if more than one block has to be encrypted). - * - * Input: Pointer to the buffer of the plaintext to be encrypted. - * Pointer to the buffer receiving the ciphertext. - * The length of the plaintext buffer. - * The TwoFish structure. - * - * Output: The amount of bytes encrypted if successful, otherwise 0. - */ -uint32_t TwoFishEncryptRaw(uint8_t *in,uint8_t *out,uint32_t len,TWOFISH *tfdata); - -/* TwoFish Raw Decryption - * - * Does not use header, but does use CBC (if more than one block has to be decrypted). - * - * Input: Pointer to the buffer of the ciphertext to be decrypted. - * Pointer to the buffer receiving the plaintext. - * The length of the ciphertext buffer (at least one cipher block). - * The TwoFish structure. - * - * Output: The amount of bytes decrypted if successful, otherwise 0. - */ -uint32_t TwoFishDecryptRaw(uint8_t *in,uint8_t *out,uint32_t len,TWOFISH *tfdata); - - -/* TwoFish Encryption - * - * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, - * this routine will alloc the memory. In addition, it will include a small 'header' - * containing the magic and some salt. That way the decrypt routine can check if the - * packet got decrypted successfully, and return 0 instead of garbage. - * - * Input: Pointer to the buffer of the plaintext to be encrypted. - * Pointer to the pointer to the buffer receiving the ciphertext. - * The pointer either points to user allocated output buffer space, or to NULL, in which case - * this routine will set the pointer to the buffer allocated through the struct. - * The length of the plaintext buffer. - * Can be -1 if the input is a null terminated string, in which case we'll count for you. - * Boolean flag for BinHex Output (if used, output will be twice as large as input). - * Note: BinHex conversion overwrites (converts) input buffer! - * The TwoFish structure. - * - * Output: The amount of bytes encrypted if successful, otherwise 0. - */ -uint32_t TwoFishEncrypt(uint8_t *in,uint8_t **out,signed long len,bool binhex,TWOFISH *tfdata); - - -/* TwoFish Decryption - * - * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, - * this routine will alloc the memory. In addition, it will check the small 'header' - * containing the magic. If magic does not match we return 0. Otherwise we return the - * amount of bytes decrypted (should be the same as the length in the header). - * - * Input: Pointer to the buffer of the ciphertext to be decrypted. - * Pointer to the pointer to the buffer receiving the plaintext. - * The pointer either points to user allocated output buffer space, or to NULL, in which case - * this routine will set the pointer to the buffer allocated through the struct. - * The length of the ciphertext buffer. - * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you. - * Boolean flag for BinHex Input (if used, plaintext will be half as large as input). - * Note: BinHex conversion overwrites (converts) input buffer! - * The TwoFish structure. - * - * Output: The amount of bytes decrypted if successful, otherwise 0. - */ -uint32_t TwoFishDecrypt(uint8_t *in,uint8_t **out,signed long len,bool binhex,TWOFISH *tfdata); - - -/**** Private Functions ****/ - -uint8_t TwoFish__b(uint32_t x,int n); -void _TwoFish_BinHex(uint8_t *buf,uint32_t len,bool bintohex); -uint32_t _TwoFish_CryptRawCBC(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata); -uint32_t _TwoFish_CryptRaw16(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata); -uint32_t _TwoFish_CryptRaw(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata); -void _TwoFish_PrecomputeMDSmatrix(void); -void _TwoFish_MakeSubKeys(TWOFISH *tfdata); -void _TwoFish_qBlockPush(uint8_t *p,uint8_t *c,TWOFISH *tfdata); -void _TwoFish_qBlockPop(uint8_t *p,uint8_t *c,TWOFISH *tfdata); -void _TwoFish_ResetCBC(TWOFISH *tfdata); -void _TwoFish_FlushOutput(uint8_t *b,uint32_t len,TWOFISH *tfdata); -void _TwoFish_BlockCrypt(uint8_t *in,uint8_t *out,uint32_t size,int decrypt,TWOFISH *tfdata); -void _TwoFish_BlockCrypt16(uint8_t *in,uint8_t *out,bool decrypt,TWOFISH *tfdata); -uint32_t _TwoFish_RS_MDS_Encode(uint32_t k0,uint32_t k1); -uint32_t _TwoFish_F32(uint32_t k64Cnt,uint32_t x,uint32_t *k32); -uint32_t _TwoFish_Fe320(uint32_t *lsBox,uint32_t x); -uint32_t _TwoFish_Fe323(uint32_t *lsBox,uint32_t x); -uint32_t _TwoFish_Fe32(uint32_t *lsBox,uint32_t x,uint32_t R); - - -#endif diff --git a/src/edge_utils.c b/src/edge_utils.c index bbd9dc4..7217499 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -219,7 +219,7 @@ n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) { /* Set active transop */ switch(transop_id) { case N2N_TRANSFORM_ID_TWOFISH: - rc = n2n_transop_twofish_init(&eee->conf, &eee->transop); + rc = n2n_transop_tf_init(&eee->conf, &eee->transop); break; #ifdef N2N_HAVE_AES case N2N_TRANSFORM_ID_AESCBC: diff --git a/src/tf.c b/src/tf.c new file mode 100644 index 0000000..59fdadc --- /dev/null +++ b/src/tf.c @@ -0,0 +1,505 @@ +/** + * (C) 2007-20 - ntop.org and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not see see + * + */ + + +// taken (and modified) from github/fudanchii/twofish as of August 2020 +// which itself is a modified copy of Andrew T. Csillag's implementation +// published on github/drewcsillag/twofish + + +/* +The MIT License (MIT) + +Copyright (c) 2015 Andrew T. Csillag + +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 "tf.h" + + +const uint8_t RS[4][8] = { { 0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, }, + { 0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5, }, + { 0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19, }, + { 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03 } }; + +const uint8_t Q0[] = { 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, + 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, + 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, + 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, + 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, + 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, + 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, + 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, + 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, + 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, + 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0 }; + +const uint8_t Q1[] = { 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, + 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, + 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, + 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, + 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, + 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, + 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, + 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, + 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, + 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, + 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 }; + +const uint8_t mult5B[] = { 0x00, 0x5B, 0xB6, 0xED, 0x05, 0x5E, 0xB3, 0xE8, 0x0A, 0x51, 0xBC, 0xE7, 0x0F, 0x54, 0xB9, 0xE2, + 0x14, 0x4F, 0xA2, 0xF9, 0x11, 0x4A, 0xA7, 0xFC, 0x1E, 0x45, 0xA8, 0xF3, 0x1B, 0x40, 0xAD, 0xF6, + 0x28, 0x73, 0x9E, 0xC5, 0x2D, 0x76, 0x9B, 0xC0, 0x22, 0x79, 0x94, 0xCF, 0x27, 0x7C, 0x91, 0xCA, + 0x3C, 0x67, 0x8A, 0xD1, 0x39, 0x62, 0x8F, 0xD4, 0x36, 0x6D, 0x80, 0xDB, 0x33, 0x68, 0x85, 0xDE, + 0x50, 0x0B, 0xE6, 0xBD, 0x55, 0x0E, 0xE3, 0xB8, 0x5A, 0x01, 0xEC, 0xB7, 0x5F, 0x04, 0xE9, 0xB2, + 0x44, 0x1F, 0xF2, 0xA9, 0x41, 0x1A, 0xF7, 0xAC, 0x4E, 0x15, 0xF8, 0xA3, 0x4B, 0x10, 0xFD, 0xA6, + 0x78, 0x23, 0xCE, 0x95, 0x7D, 0x26, 0xCB, 0x90, 0x72, 0x29, 0xC4, 0x9F, 0x77, 0x2C, 0xC1, 0x9A, + 0x6C, 0x37, 0xDA, 0x81, 0x69, 0x32, 0xDF, 0x84, 0x66, 0x3D, 0xD0, 0x8B, 0x63, 0x38, 0xD5, 0x8E, + 0xA0, 0xFB, 0x16, 0x4D, 0xA5, 0xFE, 0x13, 0x48, 0xAA, 0xF1, 0x1C, 0x47, 0xAF, 0xF4, 0x19, 0x42, + 0xB4, 0xEF, 0x02, 0x59, 0xB1, 0xEA, 0x07, 0x5C, 0xBE, 0xE5, 0x08, 0x53, 0xBB, 0xE0, 0x0D, 0x56, + 0x88, 0xD3, 0x3E, 0x65, 0x8D, 0xD6, 0x3B, 0x60, 0x82, 0xD9, 0x34, 0x6F, 0x87, 0xDC, 0x31, 0x6A, + 0x9C, 0xC7, 0x2A, 0x71, 0x99, 0xC2, 0x2F, 0x74, 0x96, 0xCD, 0x20, 0x7B, 0x93, 0xC8, 0x25, 0x7E, + 0xF0, 0xAB, 0x46, 0x1D, 0xF5, 0xAE, 0x43, 0x18, 0xFA, 0xA1, 0x4C, 0x17, 0xFF, 0xA4, 0x49, 0x12, + 0xE4, 0xBF, 0x52, 0x09, 0xE1, 0xBA, 0x57, 0x0C, 0xEE, 0xB5, 0x58, 0x03, 0xEB, 0xB0, 0x5D, 0x06, + 0xD8, 0x83, 0x6E, 0x35, 0xDD, 0x86, 0x6B, 0x30, 0xD2, 0x89, 0x64, 0x3F, 0xD7, 0x8C, 0x61, 0x3A, + 0xCC, 0x97, 0x7A, 0x21, 0xC9, 0x92, 0x7F, 0x24, 0xC6, 0x9D, 0x70, 0x2B, 0xC3, 0x98, 0x75, 0x2E }; + +const uint8_t multEF[] = { 0x00, 0xEF, 0xB7, 0x58, 0x07, 0xE8, 0xB0, 0x5F, 0x0E, 0xE1, 0xB9, 0x56, 0x09, 0xE6, 0xBE, 0x51, + 0x1C, 0xF3, 0xAB, 0x44, 0x1B, 0xF4, 0xAC, 0x43, 0x12, 0xFD, 0xA5, 0x4A, 0x15, 0xFA, 0xA2, 0x4D, + 0x38, 0xD7, 0x8F, 0x60, 0x3F, 0xD0, 0x88, 0x67, 0x36, 0xD9, 0x81, 0x6E, 0x31, 0xDE, 0x86, 0x69, + 0x24, 0xCB, 0x93, 0x7C, 0x23, 0xCC, 0x94, 0x7B, 0x2A, 0xC5, 0x9D, 0x72, 0x2D, 0xC2, 0x9A, 0x75, + 0x70, 0x9F, 0xC7, 0x28, 0x77, 0x98, 0xC0, 0x2F, 0x7E, 0x91, 0xC9, 0x26, 0x79, 0x96, 0xCE, 0x21, + 0x6C, 0x83, 0xDB, 0x34, 0x6B, 0x84, 0xDC, 0x33, 0x62, 0x8D, 0xD5, 0x3A, 0x65, 0x8A, 0xD2, 0x3D, + 0x48, 0xA7, 0xFF, 0x10, 0x4F, 0xA0, 0xF8, 0x17, 0x46, 0xA9, 0xF1, 0x1E, 0x41, 0xAE, 0xF6, 0x19, + 0x54, 0xBB, 0xE3, 0x0C, 0x53, 0xBC, 0xE4, 0x0B, 0x5A, 0xB5, 0xED, 0x02, 0x5D, 0xB2, 0xEA, 0x05, + 0xE0, 0x0F, 0x57, 0xB8, 0xE7, 0x08, 0x50, 0xBF, 0xEE, 0x01, 0x59, 0xB6, 0xE9, 0x06, 0x5E, 0xB1, + 0xFC, 0x13, 0x4B, 0xA4, 0xFB, 0x14, 0x4C, 0xA3, 0xF2, 0x1D, 0x45, 0xAA, 0xF5, 0x1A, 0x42, 0xAD, + 0xD8, 0x37, 0x6F, 0x80, 0xDF, 0x30, 0x68, 0x87, 0xD6, 0x39, 0x61, 0x8E, 0xD1, 0x3E, 0x66, 0x89, + 0xC4, 0x2B, 0x73, 0x9C, 0xC3, 0x2C, 0x74, 0x9B, 0xCA, 0x25, 0x7D, 0x92, 0xCD, 0x22, 0x7A, 0x95, + 0x90, 0x7F, 0x27, 0xC8, 0x97, 0x78, 0x20, 0xCF, 0x9E, 0x71, 0x29, 0xC6, 0x99, 0x76, 0x2E, 0xC1, + 0x8C, 0x63, 0x3B, 0xD4, 0x8B, 0x64, 0x3C, 0xD3, 0x82, 0x6D, 0x35, 0xDA, 0x85, 0x6A, 0x32, 0xDD, + 0xA8, 0x47, 0x1F, 0xF0, 0xAF, 0x40, 0x18, 0xF7, 0xA6, 0x49, 0x11, 0xFE, 0xA1, 0x4E, 0x16, 0xF9, + 0xB4, 0x5B, 0x03, 0xEC, 0xB3, 0x5C, 0x04, 0xEB, 0xBA, 0x55, 0x0D, 0xE2, 0xBD, 0x52, 0x0A, 0xE5 }; + +#define RS_MOD 0x14D +#define RHO 0x01010101L + +#define ROL(x,n) (((x) << ((n) & 0x1F)) | ((x) >> (32-((n) & 0x1F)))) +#define ROR(x,n) (((x) >> ((n) & 0x1F)) | ((x) << (32-((n) & 0x1F)))) + +#define _b(x, N) (((x) >> (N*8)) & 0xFF) + +#define b0(x) ((uint8_t)(x)) +#define b1(x) ((uint8_t)((x) >> 8)) +#define b2(x) ((uint8_t)((x) >> 16)) +#define b3(x) ((uint8_t)((x) >> 24)) + +#define U8ARRAY_TO_U32(r) ((r[0] << 24) ^ (r[1] << 16) ^ (r[2] << 8) ^ r[3]) +#define U8S_TO_U32(r0, r1, r2, r3) ((r0 << 24) ^ (r1 << 16) ^ (r2 << 8) ^ r3) + + +/* multiply two polynomials represented as u32's, actually called with bytes */ +uint32_t polyMult(uint32_t a, uint32_t b) { + + uint32_t t=0; + + while(a) { + if(a&1) t^=b; + b <<= 1; + a >>= 1; + } + + return t; +} + + +/* take the polynomial t and return the t % modulus in GF(256) */ +uint32_t gfMod(uint32_t t, uint32_t modulus) { + + int i; + uint32_t tt; + + modulus <<= 7; + for(i = 0; i < 8; i++) { + tt = t ^ modulus; + if(tt < t) t = tt; + modulus >>= 1; + } + + return t; +} + + +/*multiply a and b and return the modulus */ +#define gfMult(a, b, modulus) gfMod(polyMult(a, b), modulus) + + +/* return a u32 containing the result of multiplying the RS Code matrix by the sd matrix */ +uint32_t RSMatrixMultiply(uint8_t sd[8]) { + + int j, k; + uint8_t t; + uint8_t result[4]; + + for(j = 0; j < 4; j++) { + t = 0; + for(k = 0; k < 8; k++) { + t ^= gfMult(RS[j][k], sd[k], RS_MOD); + } + result[3-j] = t; + } + + return U8ARRAY_TO_U32(result); +} + + +/* the Zero-keyed h function (used by the key setup routine) */ +uint32_t h(uint32_t X, uint32_t L[4], int k) { + + uint8_t y0, y1, y2, y3; + uint8_t z0, z1, z2, z3; + + y0 = b0(X); + y1 = b1(X); + y2 = b2(X); + y3 = b3(X); + + switch(k) { + case 4: + y0 = Q1[y0] ^ b0(L[3]); + y1 = Q0[y1] ^ b1(L[3]); + y2 = Q0[y2] ^ b2(L[3]); + y3 = Q1[y3] ^ b3(L[3]); + case 3: + y0 = Q1[y0] ^ b0(L[2]); + y1 = Q1[y1] ^ b1(L[2]); + y2 = Q0[y2] ^ b2(L[2]); + y3 = Q0[y3] ^ b3(L[2]); + case 2: + y0 = Q1[ Q0 [ Q0[y0] ^ b0(L[1]) ] ^ b0(L[0]) ]; + y1 = Q0[ Q0 [ Q1[y1] ^ b1(L[1]) ] ^ b1(L[0]) ]; + y2 = Q1[ Q1 [ Q0[y2] ^ b2(L[1]) ] ^ b2(L[0]) ]; + y3 = Q0[ Q1 [ Q1[y3] ^ b3(L[1]) ] ^ b3(L[0]) ]; + } + + /* inline the MDS matrix multiply */ + z0 = multEF[y0] ^ y1 ^ multEF[y2] ^ mult5B[y3]; + z1 = multEF[y0] ^ mult5B[y1] ^ y2 ^ multEF[y3]; + z2 = mult5B[y0] ^ multEF[y1] ^ multEF[y2] ^ y3; + z3 = y0 ^ multEF[y1] ^ mult5B[y2] ^ mult5B[y3]; + + return U8S_TO_U32(z0, z1, z2, z3); +} + + +/* given the Sbox keys, create the fully keyed QF */ +void fullKey(uint32_t L[4], int k, uint32_t QF[4][256]) { + + uint8_t y0, y1, y2, y3; + int i; + + /* for all input values to the Q permutations */ + for(i=0; i<256; i++) { + /* run the Q permutations */ + y0 = i; y1=i; y2=i; y3=i; + switch(k) { + case 4: + y0 = Q1[y0] ^ b0(L[3]); + y1 = Q0[y1] ^ b1(L[3]); + y2 = Q0[y2] ^ b2(L[3]); + y3 = Q1[y3] ^ b3(L[3]); + case 3: + y0 = Q1[y0] ^ b0(L[2]); + y1 = Q1[y1] ^ b1(L[2]); + y2 = Q0[y2] ^ b2(L[2]); + y3 = Q0[y3] ^ b3(L[2]); + case 2: + y0 = Q1[ Q0 [ Q0[y0] ^ b0(L[1]) ] ^ b0(L[0]) ]; + y1 = Q0[ Q0 [ Q1[y1] ^ b1(L[1]) ] ^ b1(L[0]) ]; + y2 = Q1[ Q1 [ Q0[y2] ^ b2(L[1]) ] ^ b2(L[0]) ]; + y3 = Q0[ Q1 [ Q1[y3] ^ b3(L[1]) ] ^ b3(L[0]) ]; + } + + /* now do the partial MDS matrix multiplies */ + QF[0][i] = ((multEF[y0] << 24) + | (multEF[y0] << 16) + | (mult5B[y0] << 8) + | y0); + QF[1][i] = ((y1 << 24) + | (mult5B[y1] << 16) + | (multEF[y1] << 8) + | multEF[y1]); + QF[2][i] = ((multEF[y2] << 24) + | (y2 << 16) + | (multEF[y2] << 8) + | mult5B[y2]); + QF[3][i] = ((mult5B[y3] << 24) + | (multEF[y3] << 16) + | (y3 << 8) + | mult5B[y3]); + } +} + +// ------------------------------------------------------------------------------------- + +/* fully keyed h (aka g) function */ +#define fkh(X) (S[0][b0(X)]^S[1][b1(X)]^S[2][b2(X)]^S[3][b3(X)]) + +// ------------------------------------------------------------------------------------- + +/* one encryption round */ +#define ENC_ROUND(R0, R1, R2, R3, round) \ + T0 = fkh(R0); \ + T1 = fkh(ROL(R1, 8)); \ + R2 = ROR(R2 ^ (T1 + T0 + K[2*round+8]), 1); \ + R3 = ROL(R3, 1) ^ (2*T1 + T0 + K[2*round+9]); + + +void twofish_internal_encrypt(uint32_t K[40], uint32_t S[4][256], uint8_t PT[16]) { + + uint32_t R0, R1, R2, R3; + uint32_t T0, T1; + + /* load/byteswap/whiten input */ + R3 = K[3] ^ le32toh(((uint32_t*)PT)[3]); + R2 = K[2] ^ le32toh(((uint32_t*)PT)[2]); + R1 = K[1] ^ le32toh(((uint32_t*)PT)[1]); + R0 = K[0] ^ le32toh(((uint32_t*)PT)[0]); + + ENC_ROUND(R0, R1, R2, R3, 0); + ENC_ROUND(R2, R3, R0, R1, 1); + ENC_ROUND(R0, R1, R2, R3, 2); + ENC_ROUND(R2, R3, R0, R1, 3); + ENC_ROUND(R0, R1, R2, R3, 4); + ENC_ROUND(R2, R3, R0, R1, 5); + ENC_ROUND(R0, R1, R2, R3, 6); + ENC_ROUND(R2, R3, R0, R1, 7); + ENC_ROUND(R0, R1, R2, R3, 8); + ENC_ROUND(R2, R3, R0, R1, 9); + ENC_ROUND(R0, R1, R2, R3, 10); + ENC_ROUND(R2, R3, R0, R1, 11); + ENC_ROUND(R0, R1, R2, R3, 12); + ENC_ROUND(R2, R3, R0, R1, 13); + ENC_ROUND(R0, R1, R2, R3, 14); + ENC_ROUND(R2, R3, R0, R1, 15); + + /* load/byteswap/whiten output */ + ((uint32_t*)PT)[3] = htole32(R1 ^ K[7]); + ((uint32_t*)PT)[2] = htole32(R0 ^ K[6]); + ((uint32_t*)PT)[1] = htole32(R3 ^ K[5]); + ((uint32_t*)PT)[0] = htole32(R2 ^ K[4]); +} + +// ------------------------------------------------------------------------------------- + +/* one decryption round */ +#define DEC_ROUND(R0, R1, R2, R3, round) \ + T0 = fkh(R0); \ + T1 = fkh(ROL(R1, 8)); \ + R2 = ROL(R2, 1) ^ (T0 + T1 + K[2*round+8]); \ + R3 = ROR(R3 ^ (T0 + 2*T1 + K[2*round+9]), 1); + + +void twofish_internal_decrypt(uint32_t K[40], uint32_t S[4][256], uint8_t PT[16], const uint8_t CT[16]) { + + uint32_t T0, T1; + uint32_t R0, R1, R2, R3; + + /* load/byteswap/whiten input */ + R3 = K[7] ^ le32toh(((uint32_t*)CT)[3]); + R2 = K[6] ^ le32toh(((uint32_t*)CT)[2]); + R1 = K[5] ^ le32toh(((uint32_t*)CT)[1]); + R0 = K[4] ^ le32toh(((uint32_t*)CT)[0]); + + DEC_ROUND(R0, R1, R2, R3, 15); + DEC_ROUND(R2, R3, R0, R1, 14); + DEC_ROUND(R0, R1, R2, R3, 13); + DEC_ROUND(R2, R3, R0, R1, 12); + DEC_ROUND(R0, R1, R2, R3, 11); + DEC_ROUND(R2, R3, R0, R1, 10); + DEC_ROUND(R0, R1, R2, R3, 9); + DEC_ROUND(R2, R3, R0, R1, 8); + DEC_ROUND(R0, R1, R2, R3, 7); + DEC_ROUND(R2, R3, R0, R1, 6); + DEC_ROUND(R0, R1, R2, R3, 5); + DEC_ROUND(R2, R3, R0, R1, 4); + DEC_ROUND(R0, R1, R2, R3, 3); + DEC_ROUND(R2, R3, R0, R1, 2); + DEC_ROUND(R0, R1, R2, R3, 1); + DEC_ROUND(R2, R3, R0, R1, 0); + + /* load/byteswap/whiten output */ + ((uint32_t*)PT)[3] = htole32(R1 ^ K[3]); + ((uint32_t*)PT)[2] = htole32(R0 ^ K[2]); + ((uint32_t*)PT)[1] = htole32(R3 ^ K[1]); + ((uint32_t*)PT)[0] = htole32(R2 ^ K[0]); +} + +// ------------------------------------------------------------------------------------- + +/* the key schedule routine */ +void keySched(const uint8_t M[], int N, uint32_t **S, uint32_t K[40], int *k) { + + uint32_t Mo[4], Me[4]; + int i, j; + uint8_t vector[8]; + uint32_t A, B; + + *k = (N + 63) / 64; + *S = (uint32_t*)malloc(sizeof(uint32_t) * (*k)); + + for(i = 0; i < *k; i++) { + Me[i] = le32toh(((uint32_t*)M)[2*i]); + Mo[i] = le32toh(((uint32_t*)M)[2*i+1]); + } + + for(i = 0; i < *k; i++) { + for(j = 0; j < 4; j++) + vector[j] = _b(Me[i], j); + for(j = 0; j < 4; j++) + vector[j+4] = _b(Mo[i], j); + (*S)[(*k)-i-1] = RSMatrixMultiply(vector); + } + for(i = 0; i < 20; i++) { + A = h(2*i*RHO, Me, *k); + B = ROL(h(2*i*RHO + RHO, Mo, *k), 8); + K[2*i] = A+B; + K[2*i+1] = ROL(A + 2*B, 9); + } +} + +// ------------------------------------------------------------------------------------- + +// test field +//#define fix_xor(target, source) for (int _i = 0; _i < 16; _i++) { (target)[_i] = (target)[_i] ^ (source)[_i]; } +//#define fix_xor(target, source) for (int _i = 0; _i < 16; _i+=4) { *(uint32_t*)&(target)[_i] = *(uint32_t*)&(target)[_i] ^ *(uint32_t*)&(source)[_i]; } +#define fix_xor(target, source) *(uint32_t*)&(target)[0] = *(uint32_t*)&(target)[0] ^ *(uint32_t*)&(source)[0]; *(uint32_t*)&(target)[4] = *(uint32_t*)&(target)[4] ^ *(uint32_t*)&(source)[4]; \ + *(uint32_t*)&(target)[8] = *(uint32_t*)&(target)[8] ^ *(uint32_t*)&(source)[8]; *(uint32_t*)&(target)[12] = *(uint32_t*)&(target)[12] ^ *(uint32_t*)&(source)[12]; +//#define fix_xor(target, source) *(uint64_t*)&(target)[0] = *(uint64_t*)&(target)[0] ^ *(uint64_t*)&(source)[0]; *(uint64_t*)&(target)[8] = *(uint64_t*)&(target)[8] ^ *(uint64_t*)&(source)[8]; +//#include +//#define fix_xor(target, source) __m128i target128 = _mm_loadu_si128((__m128i*)target); __m128i source128 = _mm_loadu_si128((__m128i*)source); target128 = _mm_xor_si128(target128, source128); _mm_storeu_si128((__m128i*)(target), target128); + +// ------------------------------------------------------------------------------------- + + +/** public API **/ + + +int tf_ecb_decrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx) { + + twofish_internal_decrypt(ctx->K, ctx->QF, out, in); + return TF_BLOCK_SIZE; +} + +// not used +int tf_ecb_encrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx) { + + memcpy (out, in, TF_BLOCK_SIZE); + twofish_internal_encrypt(ctx->K, ctx->QF, out); + return TF_BLOCK_SIZE; +} + + +int tf_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, tf_context_t *ctx) { + + uint8_t tmp[TF_BLOCK_SIZE]; + size_t i; + size_t n; + + memcpy(tmp, iv, TF_BLOCK_SIZE); + + n = in_len / TF_BLOCK_SIZE; + for(i=0; i < n; i++) { + fix_xor(tmp, &in[i * TF_BLOCK_SIZE]); + twofish_internal_encrypt(ctx->K, ctx->QF, tmp); + memcpy(&out[i * TF_BLOCK_SIZE], tmp, TF_BLOCK_SIZE); + } + return n * TF_BLOCK_SIZE; +} + + +int tf_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, + const unsigned char *iv, tf_context_t *ctx) { + + uint8_t tmp[TF_BLOCK_SIZE]; + uint8_t old[TF_BLOCK_SIZE]; + size_t i; + size_t n; + + memcpy(tmp, iv, TF_BLOCK_SIZE); + + n = in_len / TF_BLOCK_SIZE; + for(i=0; i < n; i++) { + memcpy(old, &in[i * TF_BLOCK_SIZE], TF_BLOCK_SIZE); + twofish_internal_decrypt(ctx->K, ctx->QF, &out[i * TF_BLOCK_SIZE], &in[i * TF_BLOCK_SIZE]); + fix_xor(&out[i * TF_BLOCK_SIZE], tmp); + memcpy(tmp, old, TF_BLOCK_SIZE); + } + + return n * TF_BLOCK_SIZE; +} + +/** + * By definition twofish can only accept key up to 256 bit + * we wont do any checking here and will assume user already + * know about it. Twofish is undefined for key larger than 256 bit + */ +int tf_init (const unsigned char *key, size_t key_size, tf_context_t **ctx) { + + int k; + uint32_t *S; + + *ctx = calloc(1, sizeof(tf_context_t)); + if(!(*ctx)) { + return -1; + } + (*ctx)->N = key_size; + keySched(key, key_size, &S, (*ctx)->K, &k); + fullKey(S, k, (*ctx)->QF); + free(S); // allocated in keySched(...) + + return 0; +} diff --git a/src/transform_tf.c b/src/transform_tf.c index c583cc1..e40c1d8 100644 --- a/src/transform_tf.c +++ b/src/transform_tf.c @@ -16,158 +16,219 @@ * */ + #include "n2n.h" +// size of random value prepended to plaintext defaults to TF_BLOCK_SIZE; +// gradually abandoning security, lower values could be chosen; +// however, minimum transmission size with cipher text stealing scheme is one +// block; as network packets should be longer anyway, only low level programmer +// might encounter an issue with lower values here +#define TF_PREAMBLE_SIZE (TF_BLOCK_SIZE) + +// cbc mode is being used with random value prepended to plaintext +// instead of iv so, actual iv is null_iv +const uint8_t null_iv[TF_IV_SIZE] = {0}; + typedef struct transop_tf { - TWOFISH* enc_tf; /* tx state */ - TWOFISH* dec_tf; /* rx state */ + tf_context_t *ctx; } transop_tf_t; -static int transop_deinit_twofish( n2n_trans_op_t * arg ) { +/* ****************************************************** */ + +static int transop_deinit_tf(n2n_trans_op_t *arg) { transop_tf_t *priv = (transop_tf_t *)arg->priv; - if(priv) { - TwoFishDestroy(priv->enc_tf); /* deallocate TWOFISH */ - TwoFishDestroy(priv->dec_tf); /* deallocate TWOFISH */ - free(priv); - } + if(priv->ctx) free(priv->ctx); + + if(priv) free(priv); return 0; } -#define TRANSOP_TF_NONCE_SIZE 4 +/* ****************************************************** */ + +// the Twofish packet format consists of +// +// - a random TF_PREAMBLE_SIZE-sized value prepended to plaintext +// encrypted together with the... +// - ... payload data +// +// [VV|DDDDDDDDDDDDDDDDDDDDD] +// | <---- encrypted ----> | +// +static int transop_encode_tf(n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len, + const uint8_t * peer_mac) { -/** The twofish packet format consists of: - * - * - ciphertext encrypted from a 32-bit nonce followed by the payload. - * - * [nnnnDDDDDDDDDDDDDDDDDDDDD] - * |<------ encrypted ------>| - */ -static int transop_encode_twofish( n2n_trans_op_t * arg, - uint8_t * outbuf, - size_t out_len, - const uint8_t * inbuf, - size_t in_len, - const uint8_t * peer_mac) -{ - int len=-1; transop_tf_t * priv = (transop_tf_t *)arg->priv; - uint8_t assembly[N2N_PKT_BUF_SIZE]; - uint32_t * pnonce; - - if ( (in_len + TRANSOP_TF_NONCE_SIZE) <= N2N_PKT_BUF_SIZE ) - { - if ( (in_len + TRANSOP_TF_NONCE_SIZE) <= out_len ) - { - traceEvent(TRACE_DEBUG, "encode_twofish %lu", in_len); - - /* The assembly buffer is a source for encrypting data. The nonce is - * written in first followed by the packet payload. The whole - * contents of assembly are encrypted. */ - pnonce = (uint32_t *)assembly; - *pnonce = n2n_rand(); - memcpy( assembly + TRANSOP_TF_NONCE_SIZE, inbuf, in_len ); - - /* Encrypt the assembly contents and write the ciphertext after the SA. */ - len = TwoFishEncryptRaw( assembly, /* source */ - outbuf, - in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */ - priv->enc_tf); - if ( len <= 0 ) - { - traceEvent( TRACE_ERROR, "encode_twofish encryption failed." ); - } + // the assembly buffer is a source for encrypting data + // the whole contents of assembly are encrypted + uint8_t assembly[N2N_PKT_BUF_SIZE]; + size_t idx = 0; + int padded_len; + uint8_t padding; + uint8_t buf[TF_BLOCK_SIZE]; + + if(in_len <= N2N_PKT_BUF_SIZE) { + if((in_len + TF_PREAMBLE_SIZE + TF_BLOCK_SIZE) <= out_len) { + + traceEvent(TRACE_DEBUG, "transop_encode_tf %lu bytes plaintext", in_len); + + // full block sized random value (128 bit) + // !!! replace with 2 calls to encode_uint64(...) as as available + // !!! which is still under consideration in pull request 'revAes' + encode_uint32(assembly, &idx, n2n_rand()); + encode_uint32(assembly, &idx, n2n_rand()); + encode_uint32(assembly, &idx, n2n_rand()); + encode_uint32(assembly, &idx, n2n_rand()); + + // adjust for maybe differently chosen TF_PREAMBLE_SIZE + idx = TF_PREAMBLE_SIZE; + + // the plaintext data + encode_buf(assembly, &idx, inbuf, in_len); + + // round up to next whole TF block size + padded_len = (((idx - 1) / TF_BLOCK_SIZE) + 1) * TF_BLOCK_SIZE; + padding = (padded_len-idx); + // pad the following bytes with zero, fixed length (TF_BLOCK_SIZE) seems to compile + // to slightly faster code than run-time dependant 'padding' + memset (assembly + idx, 0, TF_BLOCK_SIZE); + tf_cbc_encrypt(outbuf, assembly, padded_len, null_iv, priv->ctx); + + if(padding) { + // exchange last two cipher blocks + memcpy (buf, outbuf + padded_len - TF_BLOCK_SIZE, TF_BLOCK_SIZE); + memcpy (outbuf + padded_len - TF_BLOCK_SIZE, outbuf + padded_len - 2 * TF_BLOCK_SIZE, TF_BLOCK_SIZE); + memcpy (outbuf + padded_len - 2 * TF_BLOCK_SIZE, buf, TF_BLOCK_SIZE); } - else - { - traceEvent( TRACE_ERROR, "encode_twofish outbuf too small." ); - } - } - else - { - traceEvent( TRACE_ERROR, "encode_twofish inbuf too big to encrypt." ); - } + } else + traceEvent(TRACE_ERROR, "transop_encode_tf outbuf too small"); + } else + traceEvent(TRACE_ERROR, "transop_encode_tf inbuf too big to encrypt"); - return len; + return idx; } +/* ****************************************************** */ + +// see transop_encode_tf for packet format +static int transop_decode_tf(n2n_trans_op_t * arg, + uint8_t * outbuf, + size_t out_len, + const uint8_t * inbuf, + size_t in_len, + const uint8_t * peer_mac) { -static int transop_decode_twofish( n2n_trans_op_t * arg, - uint8_t * outbuf, - size_t out_len, - const uint8_t * inbuf, - size_t in_len, - const uint8_t * peer_mac) -{ - int len=0; transop_tf_t * priv = (transop_tf_t *)arg->priv; uint8_t assembly[N2N_PKT_BUF_SIZE]; - if ( ( in_len <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */ - && (in_len >= TRANSOP_TF_NONCE_SIZE ) /* Has at least nonce */ - ) { + uint8_t rest; + size_t penultimate_block; + uint8_t buf[TF_BLOCK_SIZE]; + int len=-1; - traceEvent(TRACE_DEBUG, "decode_twofish %lu", in_len); + if( ((in_len - TF_PREAMBLE_SIZE) <= N2N_PKT_BUF_SIZE) // cipher text fits in assembly + && (in_len >= TF_PREAMBLE_SIZE) // has at least random number + && (in_len >= TF_BLOCK_SIZE) // minimum size requirement for cipher text stealing + ) { + + traceEvent(TRACE_DEBUG, "transop_decode_tf %lu bytes ciphertext", in_len); + + rest = in_len % TF_BLOCK_SIZE; + if(rest) { + // cipher text stealing + penultimate_block = ((in_len / TF_BLOCK_SIZE) - 1) * TF_BLOCK_SIZE; + // everything normal up to penultimate block + memcpy(assembly, inbuf, penultimate_block); + // prepare new penultimate block in buf + tf_ecb_decrypt(buf, inbuf + penultimate_block, priv->ctx); + memcpy(buf, inbuf + in_len - rest, rest); + // former penultimate block becomes new ultimate block + memcpy(assembly + penultimate_block + TF_BLOCK_SIZE, inbuf + penultimate_block, TF_BLOCK_SIZE); + // write new penultimate block from buf + memcpy(assembly + penultimate_block, buf, TF_BLOCK_SIZE); + // regular cbc decryption on the re-arranged ciphertext + + tf_cbc_decrypt(assembly, assembly, in_len + TF_BLOCK_SIZE - rest, null_iv, priv->ctx); + + // check for expected zero padding and give a warning otherwise + if (memcmp(assembly + in_len, null_iv, TF_BLOCK_SIZE - rest)) { + traceEvent(TRACE_WARNING, "transop_decode_tf payload decryption failed with unexpected cipher text stealing padding"); + return -1; + } + } else { + // regular cbc decryption on multiple block-sized payload + tf_cbc_decrypt(assembly, inbuf, in_len, null_iv, priv->ctx); + } + len = in_len - TF_PREAMBLE_SIZE; + memcpy(outbuf, + assembly + TF_PREAMBLE_SIZE, + len); + } else + traceEvent(TRACE_ERROR, "transop_decode_tf inbuf wrong size (%ul) to decrypt", in_len); - len = TwoFishDecryptRaw( (void *)inbuf, - assembly, /* destination */ - in_len, - priv->dec_tf); + return len; +} - if(len > 0) { - /* Step over 4-byte random nonce value */ - len -= TRANSOP_TF_NONCE_SIZE; /* size of ethernet packet */ +/* ****************************************************** */ - memcpy( outbuf, - assembly + TRANSOP_TF_NONCE_SIZE, - len ); - } else - traceEvent(TRACE_ERROR, "decode_twofish decryption failed"); - } else - traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len ); +static int setup_tf_key(transop_tf_t *priv, const uint8_t *password, ssize_t password_len) { - return len; + unsigned char key[32]; // tf key length, equals hash length + size_t key_size; + + // the input password always gets hashed to make a more unpredictable use of the key space + // just think of usually reset MSB of ASCII coded password bytes + pearson_hash_256(key, password, password_len); + + key_size = 32; // 256 bit + + // setup the key and have corresponding context created + if (tf_init (key, key_size * 8, &(priv->ctx))) { + traceEvent(TRACE_ERROR, "setup_tf_key %u-bit key setup unsuccessful", + key_size * 8); + return -1; + } + + traceEvent(TRACE_DEBUG, "setup_tf_key %u-bit key setup completed", + key_size * 8); + return 0; } -static void transop_tick_twofish( n2n_trans_op_t * arg, time_t now ) {} +/* ****************************************************** */ -/* Twofish initialization function */ -int n2n_transop_twofish_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) { +static void transop_tick_tf(n2n_trans_op_t * arg, time_t now) { ; } + +/* ****************************************************** */ + +// Twofish initialization function +int n2n_transop_tf_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) { transop_tf_t *priv; const u_char *encrypt_key = (const u_char *)conf->encrypt_key; size_t encrypt_key_len = strlen(conf->encrypt_key); - uint8_t key_hash[32]; memset(ttt, 0, sizeof(*ttt)); ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH; - ttt->tick = transop_tick_twofish; - ttt->deinit = transop_deinit_twofish; - ttt->fwd = transop_encode_twofish; - ttt->rev = transop_decode_twofish; + ttt->tick = transop_tick_tf; + ttt->deinit = transop_deinit_tf; + ttt->fwd = transop_encode_tf; + ttt->rev = transop_decode_tf; priv = (transop_tf_t*) calloc(1, sizeof(transop_tf_t)); if(!priv) { - traceEvent(TRACE_ERROR, "cannot allocate transop_tf_t memory"); + traceEvent(TRACE_ERROR, "n2n_transop_tf_cbc_init cannot allocate transop_tf_t memory"); return(-1); } ttt->priv = priv; - /* This is a preshared key setup. Both Tx and Rx are using the same security association. */ - pearson_hash_256 (key_hash, encrypt_key, encrypt_key_len); - priv->enc_tf = TwoFishInit(key_hash); - priv->dec_tf = TwoFishInit(key_hash); - - if((!priv->enc_tf) || (!priv->dec_tf)) { - if(priv->enc_tf) TwoFishDestroy(priv->enc_tf); - if(priv->dec_tf) TwoFishDestroy(priv->dec_tf); - free(priv); - traceEvent(TRACE_ERROR, "TwoFishInit failed"); - return(-2); - } - - return(0); + // setup the cipher and key + return(setup_tf_key(priv, encrypt_key, encrypt_key_len)); } diff --git a/src/twofish.c b/src/twofish.c deleted file mode 100644 index ebda2e6..0000000 --- a/src/twofish.c +++ /dev/null @@ -1,1002 +0,0 @@ -/* $Id: twofish.c,v 2.0 2002/08/11 22:32:25 fknobbe Exp $ - * - * - * Copyright (C) 1997-2000 The Cryptix Foundation Limited. - * Copyright (C) 2000 Farm9. - * Copyright (C) 2001 Frank Knobbe. - * All rights reserved. - * - * For Cryptix code: - * Use, modification, copying and distribution of this software is subject - * the terms and conditions of the Cryptix General Licence. You should have - * received a copy of the Cryptix General Licence along with this library; - * if not, you can download a copy from http://www.cryptix.org/ . - * - * For Farm9: - * --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and - * ciphertext stealing technique, added AsciiTwofish class for easy encryption - * decryption of text strings - * - * Frank Knobbe : - * --- April 2001, converted from C++ to C, prefixed global variables - * with TwoFish, substituted some defines, changed functions to make use of - * variables supplied in a struct, modified and added routines for modular calls. - * Cleaned up the code so that defines are used instead of fixed 16's and 32's. - * Created two general purpose crypt routines for one block and multiple block - * encryption using Joh's CBC code. - * Added crypt routines that use a header (with a magic and data length). - * (Basically a major rewrite). - * - * Note: Routines labeled _TwoFish are private and should not be used - * (or with extreme caution). - * - */ - -#ifndef __TWOFISH_LIBRARY_SOURCE__ -#define __TWOFISH_LIBRARY_SOURCE__ - -#include "n2n.h" - -/* Fixed 8x8 permutation S-boxes */ -static const uint8_t TwoFish_P[2][256] = - { - { /* p0 */ - 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78, - 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, - 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30, - 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, - 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE, - 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, - 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45, - 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, - 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF, - 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, - 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED, - 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, - 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B, - 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, - 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F, - 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, - 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17, - 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, - 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, - 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, - 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, - 0x4A, 0x5E, 0xC1, 0xE0 - }, - { /* p1 */ - 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, - 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, - 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B, - 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, - 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54, - 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, - 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7, - 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, - 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF, - 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, - 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D, - 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, - 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21, - 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, - 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E, - 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, - 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44, - 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, - 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B, - 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, - 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, - 0x55, 0x09, 0xBE, 0x91 - } - }; - -static bool TwoFish_MDSready=FALSE; -static uint32_t TwoFish_MDS[4][256]; /* TwoFish_MDS matrix */ - - -#define TwoFish_LFSR1(x) (((x)>>1)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/2:0)) -#define TwoFish_LFSR2(x) (((x)>>2)^(((x)&0x02)?TwoFish_MDS_GF_FDBK/2:0)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/4:0)) - -#define TwoFish_Mx_1(x) ((uint32_t)(x)) /* force result to dword so << will work */ -#define TwoFish_Mx_X(x) ((uint32_t)((x)^TwoFish_LFSR2(x))) /* 5B */ -#define TwoFish_Mx_Y(x) ((uint32_t)((x)^TwoFish_LFSR1(x)^TwoFish_LFSR2(x))) /* EF */ -#define TwoFish_RS_rem(x) { uint8_t b=(uint8_t)(x>>24); uint32_t g2=((b<<1)^((b&0x80)?TwoFish_RS_GF_FDBK:0))&0xFF; uint32_t g3=((b>>1)&0x7F)^((b&1)?TwoFish_RS_GF_FDBK>>1:0)^g2; x=(x<<8)^(g3<<24)^(g2<<16)^(g3<<8)^b; } - -/*#define TwoFish__b(x,N) (((uint8_t *)&x)[((N)&3)^TwoFish_ADDR_XOR])*/ /* pick bytes out of a dword */ - -#define TwoFish_b0(x) TwoFish__b(x,0) /* extract LSB of uint32_t */ -#define TwoFish_b1(x) TwoFish__b(x,1) -#define TwoFish_b2(x) TwoFish__b(x,2) -#define TwoFish_b3(x) TwoFish__b(x,3) /* extract MSB of uint32_t */ - -uint8_t TwoFish__b(uint32_t x,int n) -{ n&=3; - while(n-->0) - x>>=8; - return (uint8_t)x; -} - - -/* TwoFish Initialization - * - * This routine generates a global data structure for use with TwoFish, - * initializes important values (such as subkeys, sBoxes), generates subkeys - * and precomputes the MDS matrix if not already done. - * - * Input: User supplied key of correct length (TwoFish_KEY_LENGTH, 256 bits = 32 bytes by default) - * - * Output: Pointer to TWOFISH structure. This data structure contains key dependent data. - * This pointer is used with all other crypt functions. - */ - -TWOFISH *TwoFishInit(const uint8_t *userkey) -{ TWOFISH *tfdata; - - tfdata=(TWOFISH *)malloc(sizeof(TWOFISH)); /* allocate the TwoFish structure */ - if(tfdata!=NULL) - { - memcpy(tfdata->key, userkey, TwoFish_KEY_LENGTH); - - if(!TwoFish_MDSready) - _TwoFish_PrecomputeMDSmatrix(); /* "Wake Up, Neo" */ - _TwoFish_MakeSubKeys(tfdata); /* generate subkeys */ - _TwoFish_ResetCBC(tfdata); /* reset the CBC */ - tfdata->output=NULL; /* nothing to output yet */ - tfdata->dontflush=FALSE; /* reset decrypt skip block flag */ - } - return tfdata; /* return the data pointer */ -} - - -void TwoFishDestroy(TWOFISH *tfdata) -{ if(tfdata!=NULL) - free(tfdata); -} - - -/* en/decryption with CBC mode */ -uint32_t _TwoFish_CryptRawCBC(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata) -{ uint32_t rl; - - rl=len; /* remember how much data to crypt. */ - while(len>TwoFish_BLOCK_SIZE) /* and now we process block by block. */ - { _TwoFish_BlockCrypt(in,out,TwoFish_BLOCK_SIZE,decrypt,tfdata); /* de/encrypt it. */ - in+=TwoFish_BLOCK_SIZE; /* adjust pointers. */ - out+=TwoFish_BLOCK_SIZE; - len-=TwoFish_BLOCK_SIZE; - } - if(len>0) /* if we have less than a block left... */ - _TwoFish_BlockCrypt(in,out,len,decrypt,tfdata); /* ...then we de/encrypt that too. */ - if(tfdata->qBlockDefined && !tfdata->dontflush) /* in case len was exactly one block... */ - _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); /* ...we need to write the... */ - /* ...remaining bytes of the buffer */ - return rl; -} - -/* en/decryption on one block only */ -uint32_t _TwoFish_CryptRaw16(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata) -{ /* qBlockPlain already zero'ed through ResetCBC */ - memcpy(tfdata->qBlockPlain,in,len); /* toss the data into it. */ - _TwoFish_BlockCrypt16(tfdata->qBlockPlain,tfdata->qBlockCrypt,decrypt,tfdata); /* encrypt just that block without CBC. */ - memcpy(out,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE); /* and return what we got */ - return TwoFish_BLOCK_SIZE; -} - -/* en/decryption without reset of CBC and output assignment */ -uint32_t _TwoFish_CryptRaw(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata) -{ - if(in!=NULL && out!=NULL && len>0 && tfdata!=NULL) /* if we have valid data, then... */ - { if(len>TwoFish_BLOCK_SIZE) /* ...check if we have more than one block. */ - return _TwoFish_CryptRawCBC(in,out,len,decrypt,tfdata); /* if so, use the CBC routines... */ - else - return _TwoFish_CryptRaw16(in,out,len,decrypt,tfdata); /* ...otherwise just do one block. */ - } - return 0; -} - - -/* TwoFish Raw Encryption - * - * Does not use header, but does use CBC (if more than one block has to be encrypted). - * - * Input: Pointer to the buffer of the plaintext to be encrypted. - * Pointer to the buffer receiving the ciphertext. - * The length of the plaintext buffer. - * The TwoFish structure. - * - * Output: The amount of bytes encrypted if successful, otherwise 0. - */ - -uint32_t TwoFishEncryptRaw(uint8_t *in, - uint8_t *out, - uint32_t len, - TWOFISH *tfdata) -{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */ - tfdata->output=out; /* output straight into output buffer. */ - return _TwoFish_CryptRaw(in,out,len,FALSE,tfdata); /* and go for it. */ -} - -/* TwoFish Raw Decryption - * - * Does not use header, but does use CBC (if more than one block has to be decrypted). - * - * Input: Pointer to the buffer of the ciphertext to be decrypted. - * Pointer to the buffer receiving the plaintext. - * The length of the ciphertext buffer (at least one cipher block). - * The TwoFish structure. - * - * Output: The amount of bytes decrypted if successful, otherwise 0. - */ - -uint32_t TwoFishDecryptRaw(uint8_t *in, - uint8_t *out, - uint32_t len, - TWOFISH *tfdata) -{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */ - tfdata->output=out; /* output straight into output buffer. */ - return _TwoFish_CryptRaw(in,out,len,TRUE,tfdata); /* and go for it. */ -} - -/* TwoFish Free - * - * Free's the allocated buffer. - * - * Input: Pointer to the TwoFish structure - * - * Output: (none) - */ - -void TwoFishFree(TWOFISH *tfdata) -{ if(tfdata->output!=NULL) /* if a valid buffer is present... */ - { free(tfdata->output); /* ...then we free it for you... */ - tfdata->output=NULL; /* ...and mark as such. */ - } -} - -/* TwoFish Set Output - * - * If you want to allocate the output buffer yourself, - * then you can set it with this function. - * - * Input: Pointer to your output buffer - * Pointer to the TwoFish structure - * - * Output: (none) - */ - -void TwoFishSetOutput(uint8_t *outp,TWOFISH *tfdata) -{ tfdata->output=outp; /* (do we really need a function for this?) */ -} - -/* TwoFish Alloc - * - * Allocates enough memory for the output buffer that would be required - * - * Input: Length of the plaintext. - * Boolean flag for BinHex Output. - * Pointer to the TwoFish structure. - * - * Output: Returns a pointer to the memory allocated. - */ - -void *TwoFishAlloc(uint32_t len,bool binhex,bool decrypt,TWOFISH *tfdata) -{ - /* TwoFishFree(tfdata); */ /* (don't for now) discard whatever was allocated earlier. */ - if(decrypt) /* if decrypting... */ - { if(binhex) /* ...and input is binhex encoded... */ - len/=2; /* ...use half as much for output. */ - len-=TwoFish_BLOCK_SIZE; /* Also, subtract the size of the header. */ - } - else - { len+=TwoFish_BLOCK_SIZE; /* the size is just increased by the header... */ - if(binhex) - len*=2; /* ...and doubled if output is to be binhexed. */ - } - tfdata->output=malloc(len+TwoFish_BLOCK_SIZE);/* grab some memory...plus some extra (it's running over somewhere, crashes without extra padding) */ - - return tfdata->output; /* ...and return to caller. */ -} - -/* bin2hex and hex2bin conversion */ -void _TwoFish_BinHex(uint8_t *buf,uint32_t len,bool bintohex) -{ uint8_t *pi,*po,c; - - if(bintohex) - { for(pi=buf+len-1,po=buf+(2*len)-1;len>0;pi--,po--,len--) /* let's start from the end of the bin block. */ - { c=*pi; /* grab value. */ - c&=15; /* use lower 4 bits. */ - if(c>9) /* convert to ascii. */ - c+=('a'-10); - else - c+='0'; - *po--=c; /* set the lower nibble. */ - c=*pi; /* grab value again. */ - c>>=4; /* right shift 4 bits. */ - c&=15; /* make sure we only have 4 bits. */ - if(c>9) /* convert to ascii. */ - c+=('a'-10); - else - c+='0'; - *po=c; /* set the higher nibble. */ - } /* and keep going. */ - } - else - { for(pi=buf,po=buf;len>0;pi++,po++,len-=2) /* let's start from the beginning of the hex block. */ - { c=tolower(*pi++)-'0'; /* grab higher nibble. */ - if(c>9) /* convert to value. */ - c-=('0'-9); - *po=c<<4; /* left shit 4 bits. */ - c=tolower(*pi)-'0'; /* grab lower nibble. */ - if(c>9) /* convert to value. */ - c-=('0'-9); - *po|=c; /* and add to value. */ - } - } -} - - -/* TwoFish Encryption - * - * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, - * this routine will alloc the memory. In addition, it will include a small 'header' - * containing the magic and some salt. That way the decrypt routine can check if the - * packet got decrypted successfully, and return 0 instead of garbage. - * - * Input: Pointer to the buffer of the plaintext to be encrypted. - * Pointer to the pointer to the buffer receiving the ciphertext. - * The pointer either points to user allocated output buffer space, or to NULL, in which case - * this routine will set the pointer to the buffer allocated through the struct. - * The length of the plaintext buffer. - * Can be -1 if the input is a null terminated string, in which case we'll count for you. - * Boolean flag for BinHex Output (if used, output will be twice as large as input). - * Note: BinHex conversion overwrites (converts) input buffer! - * The TwoFish structure. - * - * Output: The amount of bytes encrypted if successful, otherwise 0. - */ - -uint32_t TwoFishEncrypt(uint8_t *in, - uint8_t **out, - signed long len, - bool binhex, - TWOFISH *tfdata) -{ uint32_t ilen,olen; - - -#if 0 -/* This is so broken it doesn't deserve to live. */ - if(len== -1) /* if we got -1 for len, we'll assume IN is a... */ - ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */ - else - ilen=len; /* ...otherwise we trust you supply a correct length. */ -#endif - - ilen = len; - - if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */ - { if(*out==NULL) /* if OUT points to a NULL pointer... */ - *out=TwoFishAlloc(ilen,binhex,FALSE,tfdata); /* ...we'll (re-)allocate buffer space. */ - if(*out!=NULL) - { tfdata->output=*out; /* set output buffer. */ - tfdata->header.salt=n2n_rand()*65536+n2n_rand(); /* toss in some salt. */ - tfdata->header.length[0]= (uint8_t)(ilen); - tfdata->header.length[1]= (uint8_t)(ilen>>8); - tfdata->header.length[2]= (uint8_t)(ilen>>16); - tfdata->header.length[3]= (uint8_t)(ilen>>24); - memcpy(tfdata->header.magic,TwoFish_MAGIC,TwoFish_MAGIC_LEN); /* set the magic. */ - olen=TwoFish_BLOCK_SIZE; /* set output counter. */ - _TwoFish_ResetCBC(tfdata); /* reset the CBC flag */ - _TwoFish_BlockCrypt((uint8_t *)&(tfdata->header),*out,olen,FALSE,tfdata); /* encrypt first block (without flush on 16 byte boundary). */ - olen+=_TwoFish_CryptRawCBC(in,*out+TwoFish_BLOCK_SIZE,ilen,FALSE,tfdata); /* and encrypt the rest (we do not reset the CBC flag). */ - if(binhex) /* if binhex... */ - { _TwoFish_BinHex(*out,olen,TRUE); /* ...convert output to binhex... */ - olen*=2; /* ...and size twice as large. */ - } - tfdata->output=*out; - return olen; - } - } - return 0; -} - -/* TwoFish Decryption - * - * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc, - * this routine will alloc the memory. In addition, it will check the small 'header' - * containing the magic. If magic does not match we return 0. Otherwise we return the - * amount of bytes decrypted (should be the same as the length in the header). - * - * Input: Pointer to the buffer of the ciphertext to be decrypted. - * Pointer to the pointer to the buffer receiving the plaintext. - * The pointer either points to user allocated output buffer space, or to NULL, in which case - * this routine will set the pointer to the buffer allocated through the struct. - * The length of the ciphertext buffer. - * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you. - * Boolean flag for BinHex Input (if used, plaintext will be half as large as input). - * Note: BinHex conversion overwrites (converts) input buffer! - * The TwoFish structure. - * - * Output: The amount of bytes decrypted if successful, otherwise 0. - */ - -uint32_t TwoFishDecrypt(uint8_t *in, - uint8_t **out, - signed long len, - bool binhex, - TWOFISH *tfdata) -{ uint32_t ilen,elen,olen; - const uint8_t cmagic[TwoFish_MAGIC_LEN]=TwoFish_MAGIC; - uint8_t *tbuf; - - - -#if 0 -/* This is so broken it doesn't deserve to live. */ - if(len== -1) /* if we got -1 for len, we'll assume IN is a... */ - ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */ - else - ilen=len; /* ...otherwise we trust you supply a correct length. */ -#endif - - ilen = len; - - if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */ - { if(*out==NULL) /* if OUT points to a NULL pointer... */ - *out=TwoFishAlloc(ilen,binhex,TRUE,tfdata); /* ...we'll (re-)allocate buffer space. */ - if(*out!=NULL) - { if(binhex) /* if binhex... */ - { _TwoFish_BinHex(in,ilen,FALSE); /* ...convert input to values... */ - ilen/=2; /* ...and size half as much. */ - } - _TwoFish_ResetCBC(tfdata); /* reset the CBC flag. */ - - tbuf=(uint8_t *)malloc(ilen+TwoFish_BLOCK_SIZE); /* get memory for data and header. */ - if(tbuf==NULL) - return 0; - tfdata->output=tbuf; /* set output to temp buffer. */ - - olen=_TwoFish_CryptRawCBC(in,tbuf,ilen,TRUE,tfdata)-TwoFish_BLOCK_SIZE; /* decrypt the whole thing. */ - memcpy(&(tfdata->header),tbuf,TwoFish_BLOCK_SIZE); /* copy first block into header. */ - tfdata->output=*out; - for(elen=0;elenheader.magic[elen]!=cmagic[elen]) - break; - if(elen==TwoFish_MAGIC_LEN) /* if magic matches then... */ - { elen=(tfdata->header.length[0]) | - (tfdata->header.length[1])<<8 | - (tfdata->header.length[2])<<16 | - (tfdata->header.length[3])<<24; /* .. we know how much to expect. */ - if(elen>olen) /* adjust if necessary. */ - elen=olen; - memcpy(*out,tbuf+TwoFish_BLOCK_SIZE,elen); /* copy data into intended output. */ - free(tbuf); - return elen; - } - free(tbuf); - } - } - return 0; -} - -void _TwoFish_PrecomputeMDSmatrix(void) /* precompute the TwoFish_MDS matrix */ -{ uint32_t m1[2]; - uint32_t mX[2]; - uint32_t mY[2]; - uint32_t i, j; - - for (i = 0; i < 256; i++) - { j = TwoFish_P[0][i] & 0xFF; /* compute all the matrix elements */ - m1[0] = j; - mX[0] = TwoFish_Mx_X( j ) & 0xFF; - mY[0] = TwoFish_Mx_Y( j ) & 0xFF; - - j = TwoFish_P[1][i] & 0xFF; - m1[1] = j; - mX[1] = TwoFish_Mx_X( j ) & 0xFF; - mY[1] = TwoFish_Mx_Y( j ) & 0xFF; - - TwoFish_MDS[0][i] = m1[TwoFish_P_00] | /* fill matrix w/ above elements */ - mX[TwoFish_P_00] << 8 | - mY[TwoFish_P_00] << 16 | - mY[TwoFish_P_00] << 24; - TwoFish_MDS[1][i] = mY[TwoFish_P_10] | - mY[TwoFish_P_10] << 8 | - mX[TwoFish_P_10] << 16 | - m1[TwoFish_P_10] << 24; - TwoFish_MDS[2][i] = mX[TwoFish_P_20] | - mY[TwoFish_P_20] << 8 | - m1[TwoFish_P_20] << 16 | - mY[TwoFish_P_20] << 24; - TwoFish_MDS[3][i] = mX[TwoFish_P_30] | - m1[TwoFish_P_30] << 8 | - mY[TwoFish_P_30] << 16 | - mX[TwoFish_P_30] << 24; - } - TwoFish_MDSready=TRUE; -} - - -void _TwoFish_MakeSubKeys(TWOFISH *tfdata) /* Expand a user-supplied key material into a session key. */ -{ uint32_t k64Cnt = TwoFish_KEY_LENGTH / 8; - uint32_t k32e[4]; /* even 32-bit entities */ - uint32_t k32o[4]; /* odd 32-bit entities */ - uint32_t sBoxKey[4]; - uint32_t offset,i,j; - uint32_t A, B, q=0; - uint32_t k0,k1,k2,k3; - uint32_t b0,b1,b2,b3; - - /* split user key material into even and odd 32-bit entities and */ - /* compute S-box keys using (12, 8) Reed-Solomon code over GF(256) */ - - - for (offset=0,i=0,j=k64Cnt-1;i<4 && offsetkey[offset++]; - k32e[i]|= tfdata->key[offset++]<<8; - k32e[i]|= tfdata->key[offset++]<<16; - k32e[i]|= tfdata->key[offset++]<<24; - k32o[i] = tfdata->key[offset++]; - k32o[i]|= tfdata->key[offset++]<<8; - k32o[i]|= tfdata->key[offset++]<<16; - k32o[i]|= tfdata->key[offset++]<<24; - sBoxKey[j] = _TwoFish_RS_MDS_Encode( k32e[i], k32o[i] ); /* reverse order */ - } - - /* compute the round decryption subkeys for PHT. these same subkeys */ - /* will be used in encryption but will be applied in reverse order. */ - i=0; - while(i < TwoFish_TOTAL_SUBKEYS) - { A = _TwoFish_F32( k64Cnt, q, k32e ); /* A uses even key entities */ - q += TwoFish_SK_BUMP; - - B = _TwoFish_F32( k64Cnt, q, k32o ); /* B uses odd key entities */ - q += TwoFish_SK_BUMP; - - B = B << 8 | B >> 24; - - A += B; - tfdata->subKeys[i++] = A; /* combine with a PHT */ - - A += B; - tfdata->subKeys[i++] = A << TwoFish_SK_ROTL | A >> (32-TwoFish_SK_ROTL); - } - - /* fully expand the table for speed */ - k0 = sBoxKey[0]; - k1 = sBoxKey[1]; - k2 = sBoxKey[2]; - k3 = sBoxKey[3]; - - for (i = 0; i < 256; i++) - { b0 = b1 = b2 = b3 = i; - switch (k64Cnt & 3) - { case 1: /* 64-bit keys */ - tfdata->sBox[ 2*i ] = TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0]) ^ TwoFish_b0(k0)]; - tfdata->sBox[ 2*i+1] = TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1]) ^ TwoFish_b1(k0)]; - tfdata->sBox[0x200+2*i ] = TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2]) ^ TwoFish_b2(k0)]; - tfdata->sBox[0x200+2*i+1] = TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3]) ^ TwoFish_b3(k0)]; - break; - case 0: /* 256-bit keys (same as 4) */ - b0 = (TwoFish_P[TwoFish_P_04][b0]) ^ TwoFish_b0(k3); - b1 = (TwoFish_P[TwoFish_P_14][b1]) ^ TwoFish_b1(k3); - b2 = (TwoFish_P[TwoFish_P_24][b2]) ^ TwoFish_b2(k3); - b3 = (TwoFish_P[TwoFish_P_34][b3]) ^ TwoFish_b3(k3); - case 3: /* 192-bit keys */ - b0 = (TwoFish_P[TwoFish_P_03][b0]) ^ TwoFish_b0(k2); - b1 = (TwoFish_P[TwoFish_P_13][b1]) ^ TwoFish_b1(k2); - b2 = (TwoFish_P[TwoFish_P_23][b2]) ^ TwoFish_b2(k2); - b3 = (TwoFish_P[TwoFish_P_33][b3]) ^ TwoFish_b3(k2); - case 2: /* 128-bit keys */ - tfdata->sBox[ 2*i ]= - TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0]) ^ - TwoFish_b0(k1)]) ^ TwoFish_b0(k0)]; - - tfdata->sBox[ 2*i+1]= - TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1]) ^ - TwoFish_b1(k1)]) ^ TwoFish_b1(k0)]; - - tfdata->sBox[0x200+2*i ]= - TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2]) ^ - TwoFish_b2(k1)]) ^ TwoFish_b2(k0)]; - - tfdata->sBox[0x200+2*i+1]= - TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3]) ^ - TwoFish_b3(k1)]) ^ TwoFish_b3(k0)]; - } - } -} - - -/** - * Encrypt or decrypt exactly one block of plaintext in CBC mode. - * Use "ciphertext stealing" technique described on pg. 196 - * of "Applied Cryptography" to encrypt the final partial - * (i.e. <16 byte) block if necessary. - * - * jojo: the "ciphertext stealing" requires we read ahead and have - * special handling for the last two blocks. Because of this, the - * output from the TwoFish algorithm is handled internally here. - * It would be better to have a higher level handle this as well as - * CBC mode. Unfortunately, I've mixed the two together, which is - * pretty crappy... The Java version separates these out correctly. - * - * fknobbe: I have reduced the CBC mode to work on memory buffer only. - * Higher routines should use an intermediate buffer and handle - * their output seperately (mainly so the data can be flushed - * in one chunk, not seperate 16 byte blocks...) - * - * @param in The plaintext. - * @param out The ciphertext - * @param size how much to encrypt - * @param tfdata: Pointer to the global data structure containing session keys. - * @return none - */ -void _TwoFish_BlockCrypt(uint8_t *in,uint8_t *out,uint32_t size,int decrypt,TWOFISH *tfdata) -{ uint8_t PnMinusOne[TwoFish_BLOCK_SIZE]; - uint8_t CnMinusOne[TwoFish_BLOCK_SIZE]; - uint8_t CBCplusCprime[TwoFish_BLOCK_SIZE]; - uint8_t Pn[TwoFish_BLOCK_SIZE]; - uint8_t *p,*pout; - uint32_t i; - - /* here is where we implement CBC mode and cipher block stealing */ - if(size==TwoFish_BLOCK_SIZE) - { /* if we are encrypting, CBC means we XOR the plain text block with the */ - /* previous cipher text block before encrypting */ - if(!decrypt && tfdata->qBlockDefined) - { for(p=in,i=0;iqBlockCrypt[i]; /* FK: I'm copying the xor'ed input into Pn... */ - } - else - memcpy(Pn,in,TwoFish_BLOCK_SIZE); /* FK: same here. we work of Pn all the time. */ - - /* TwoFish block level encryption or decryption */ - _TwoFish_BlockCrypt16(Pn,out,decrypt,tfdata); - - /* if we are decrypting, CBC means we XOR the result of the decryption */ - /* with the previous cipher text block to get the resulting plain text */ - if(decrypt && tfdata->qBlockDefined) - { for (p=out,i=0;iqBlockPlain[i]; - } - - /* save the input and output blocks, since CBC needs these for XOR */ - /* operations */ - _TwoFish_qBlockPush(Pn,out,tfdata); - } - else - { /* cipher block stealing, we are at Pn, */ - /* but since Cn-1 must now be replaced with CnC' */ - /* we pop it off, and recalculate Cn-1 */ - - if(decrypt) - { /* We are on an odd block, and had to do cipher block stealing, */ - /* so the PnMinusOne has to be derived differently. */ - - /* First we decrypt it into CBC and C' */ - _TwoFish_qBlockPop(CnMinusOne,PnMinusOne,tfdata); - _TwoFish_BlockCrypt16(CnMinusOne,CBCplusCprime,decrypt,tfdata); - - /* we then xor the first few bytes with the "in" bytes (Cn) */ - /* to recover Pn, which we put in out */ - for(p=in,pout=out,i=0;iprevCipher[i]; - - /* So at this point, out has PnMinusOne */ - _TwoFish_qBlockPush(CnMinusOne,PnMinusOne,tfdata); - _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); - _TwoFish_FlushOutput(out,size,tfdata); - } - else - { _TwoFish_qBlockPop(PnMinusOne,CnMinusOne,tfdata); - memset(Pn,0,TwoFish_BLOCK_SIZE); - memcpy(Pn,in,size); - for(i=0;iqBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); - _TwoFish_FlushOutput(CnMinusOne,size,tfdata); /* old Cn-1 becomes new partial Cn */ - } - tfdata->qBlockDefined=FALSE; - } -} - -void _TwoFish_qBlockPush(uint8_t *p,uint8_t *c,TWOFISH *tfdata) -{ if(tfdata->qBlockDefined) - _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); - memcpy(tfdata->prevCipher,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE); - memcpy(tfdata->qBlockPlain,p,TwoFish_BLOCK_SIZE); - memcpy(tfdata->qBlockCrypt,c,TwoFish_BLOCK_SIZE); - tfdata->qBlockDefined=TRUE; -} - -void _TwoFish_qBlockPop(uint8_t *p,uint8_t *c,TWOFISH *tfdata) -{ memcpy(p,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE ); - memcpy(c,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE ); - tfdata->qBlockDefined=FALSE; -} - -/* Reset's the CBC flag and zero's PrevCipher (through qBlockPlain) (important) */ -void _TwoFish_ResetCBC(TWOFISH *tfdata) -{ tfdata->qBlockDefined=FALSE; - memset(tfdata->qBlockPlain,0,TwoFish_BLOCK_SIZE); -} - -void _TwoFish_FlushOutput(uint8_t *b,uint32_t len,TWOFISH *tfdata) -{ uint32_t i; - - for(i=0;idontflush;i++) - *tfdata->output++ = *b++; - tfdata->dontflush=FALSE; -} - -void _TwoFish_BlockCrypt16(uint8_t *in,uint8_t *out,bool decrypt,TWOFISH *tfdata) -{ uint32_t x0,x1,x2,x3; - uint32_t k,t0,t1,R; - - - x0=*in++; - x0|=(*in++ << 8 ); - x0|=(*in++ << 16); - x0|=(*in++ << 24); - x1=*in++; - x1|=(*in++ << 8 ); - x1|=(*in++ << 16); - x1|=(*in++ << 24); - x2=*in++; - x2|=(*in++ << 8 ); - x2|=(*in++ << 16); - x2|=(*in++ << 24); - x3=*in++; - x3|=(*in++ << 8 ); - x3|=(*in++ << 16); - x3|=(*in++ << 24); - - if(decrypt) - { x0 ^= tfdata->subKeys[4]; /* swap input and output whitening keys when decrypting */ - x1 ^= tfdata->subKeys[5]; - x2 ^= tfdata->subKeys[6]; - x3 ^= tfdata->subKeys[7]; - - k = 7+(TwoFish_ROUNDS*2); - for (R = 0; R < TwoFish_ROUNDS; R += 2) - { t0 = _TwoFish_Fe320( tfdata->sBox, x0); - t1 = _TwoFish_Fe323( tfdata->sBox, x1); - x3 ^= t0 + (t1<<1) + tfdata->subKeys[k--]; - x3 = x3 >> 1 | x3 << 31; - x2 = x2 << 1 | x2 >> 31; - x2 ^= t0 + t1 + tfdata->subKeys[k--]; - - t0 = _TwoFish_Fe320( tfdata->sBox, x2); - t1 = _TwoFish_Fe323( tfdata->sBox, x3); - x1 ^= t0 + (t1<<1) + tfdata->subKeys[k--]; - x1 = x1 >> 1 | x1 << 31; - x0 = x0 << 1 | x0 >> 31; - x0 ^= t0 + t1 + tfdata->subKeys[k--]; - } - - x2 ^= tfdata->subKeys[0]; - x3 ^= tfdata->subKeys[1]; - x0 ^= tfdata->subKeys[2]; - x1 ^= tfdata->subKeys[3]; - } - else - { x0 ^= tfdata->subKeys[0]; - x1 ^= tfdata->subKeys[1]; - x2 ^= tfdata->subKeys[2]; - x3 ^= tfdata->subKeys[3]; - - k = 8; - for (R = 0; R < TwoFish_ROUNDS; R += 2) - { t0 = _TwoFish_Fe320( tfdata->sBox, x0); - t1 = _TwoFish_Fe323( tfdata->sBox, x1); - x2 ^= t0 + t1 + tfdata->subKeys[k++]; - x2 = x2 >> 1 | x2 << 31; - x3 = x3 << 1 | x3 >> 31; - x3 ^= t0 + (t1<<1) + tfdata->subKeys[k++]; - - t0 = _TwoFish_Fe320( tfdata->sBox, x2); - t1 = _TwoFish_Fe323( tfdata->sBox, x3); - x0 ^= t0 + t1 + tfdata->subKeys[k++]; - x0 = x0 >> 1 | x0 << 31; - x1 = x1 << 1 | x1 >> 31; - x1 ^= t0 + (t1<<1) + tfdata->subKeys[k++]; - } - - x2 ^= tfdata->subKeys[4]; - x3 ^= tfdata->subKeys[5]; - x0 ^= tfdata->subKeys[6]; - x1 ^= tfdata->subKeys[7]; - } - - *out++ = (uint8_t)(x2 ); - *out++ = (uint8_t)(x2 >> 8); - *out++ = (uint8_t)(x2 >> 16); - *out++ = (uint8_t)(x2 >> 24); - - *out++ = (uint8_t)(x3 ); - *out++ = (uint8_t)(x3 >> 8); - *out++ = (uint8_t)(x3 >> 16); - *out++ = (uint8_t)(x3 >> 24); - - *out++ = (uint8_t)(x0 ); - *out++ = (uint8_t)(x0 >> 8); - *out++ = (uint8_t)(x0 >> 16); - *out++ = (uint8_t)(x0 >> 24); - - *out++ = (uint8_t)(x1 ); - *out++ = (uint8_t)(x1 >> 8); - *out++ = (uint8_t)(x1 >> 16); - *out++ = (uint8_t)(x1 >> 24); -} - -/** - * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box - * 32-bit entity from two key material 32-bit entities. - * - * @param k0 1st 32-bit entity. - * @param k1 2nd 32-bit entity. - * @return Remainder polynomial generated using RS code - */ -uint32_t _TwoFish_RS_MDS_Encode(uint32_t k0,uint32_t k1) -{ uint32_t i,r; - - for(r=k1,i=0;i<4;i++) /* shift 1 byte at a time */ - TwoFish_RS_rem(r); - r ^= k0; - for(i=0;i<4;i++) - TwoFish_RS_rem(r); - - return r; -} - -uint32_t _TwoFish_F32(uint32_t k64Cnt,uint32_t x,uint32_t *k32) -{ uint8_t b0,b1,b2,b3; - uint32_t k0,k1,k2,k3,result = 0; - - b0=TwoFish_b0(x); - b1=TwoFish_b1(x); - b2=TwoFish_b2(x); - b3=TwoFish_b3(x); - k0=k32[0]; - k1=k32[1]; - k2=k32[2]; - k3=k32[3]; - - switch (k64Cnt & 3) - { case 1: /* 64-bit keys */ - result = - TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0] & 0xFF) ^ TwoFish_b0(k0)] ^ - TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1] & 0xFF) ^ TwoFish_b1(k0)] ^ - TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2] & 0xFF) ^ TwoFish_b2(k0)] ^ - TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3] & 0xFF) ^ TwoFish_b3(k0)]; - break; - case 0: /* 256-bit keys (same as 4) */ - b0 = (TwoFish_P[TwoFish_P_04][b0] & 0xFF) ^ TwoFish_b0(k3); - b1 = (TwoFish_P[TwoFish_P_14][b1] & 0xFF) ^ TwoFish_b1(k3); - b2 = (TwoFish_P[TwoFish_P_24][b2] & 0xFF) ^ TwoFish_b2(k3); - b3 = (TwoFish_P[TwoFish_P_34][b3] & 0xFF) ^ TwoFish_b3(k3); - - case 3: /* 192-bit keys */ - b0 = (TwoFish_P[TwoFish_P_03][b0] & 0xFF) ^ TwoFish_b0(k2); - b1 = (TwoFish_P[TwoFish_P_13][b1] & 0xFF) ^ TwoFish_b1(k2); - b2 = (TwoFish_P[TwoFish_P_23][b2] & 0xFF) ^ TwoFish_b2(k2); - b3 = (TwoFish_P[TwoFish_P_33][b3] & 0xFF) ^ TwoFish_b3(k2); - case 2: /* 128-bit keys (optimize for this case) */ - result = - TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0] & 0xFF) ^ TwoFish_b0(k1)] & 0xFF) ^ TwoFish_b0(k0)] ^ - TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1] & 0xFF) ^ TwoFish_b1(k1)] & 0xFF) ^ TwoFish_b1(k0)] ^ - TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2] & 0xFF) ^ TwoFish_b2(k1)] & 0xFF) ^ TwoFish_b2(k0)] ^ - TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3] & 0xFF) ^ TwoFish_b3(k1)] & 0xFF) ^ TwoFish_b3(k0)]; - break; - } - return result; -} - -uint32_t _TwoFish_Fe320(uint32_t *lsBox,uint32_t x) -{ return lsBox[ TwoFish_b0(x)<<1 ]^ - lsBox[ ((TwoFish_b1(x)<<1)|1)]^ - lsBox[0x200+ (TwoFish_b2(x)<<1) ]^ - lsBox[0x200+((TwoFish_b3(x)<<1)|1)]; -} - -uint32_t _TwoFish_Fe323(uint32_t *lsBox,uint32_t x) -{ return lsBox[ (TwoFish_b3(x)<<1) ]^ - lsBox[ ((TwoFish_b0(x)<<1)|1)]^ - lsBox[0x200+ (TwoFish_b1(x)<<1) ]^ - lsBox[0x200+((TwoFish_b2(x)<<1)|1)]; -} - -uint32_t _TwoFish_Fe32(uint32_t *lsBox,uint32_t x,uint32_t R) -{ return lsBox[ 2*TwoFish__b(x,R ) ]^ - lsBox[ 2*TwoFish__b(x,R+1)+1]^ - lsBox[0x200+2*TwoFish__b(x,R+2) ]^ - lsBox[0x200+2*TwoFish__b(x,R+3)+1]; -} - - -#endif - -/* ******************************************* */ -#if defined TWOFISH_UNIT_TEST -#include - -#define TEST_DATA_SIZE 327 - -int main(int argc, char* argv[]) -{ - int i; - int n; - - char outbuf[4096]; - char * outp = outbuf; - - uint8_t key[] = { 0xfc, 0x77, 0x1a, 0xda, 0xaa, - 0xfc, 0x77, 0x1a, 0xda, 0xaa, - 0xfc, 0x77, 0x1a, 0xda, 0xaa, - 0xfc, 0x77, 0x1a, 0xda, 0xaa, - 0xfc, 0x77, 0x1a, 0xda, 0xaa, - 0xfc, 0x77, 0x1a, 0xda, 0xaa, - 0xfc, 0x77 }; - - TWOFISH *tfa = TwoFishInit( key ); - TWOFISH *tfb = TwoFishInit( key ); - - uint8_t out[2048], out2[2048]; - uint8_t in[TEST_DATA_SIZE]; - - for ( i=0; i