Browse Source

Merge pull request #389 from Logan007/revTf

reworked twofish implementation and replaced it by a faster version
pull/392/head
Luca Deri 4 years ago
committed by GitHub
parent
commit
31a05e18d1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CMakeLists.txt
  2. 4
      include/n2n.h
  3. 82
      include/tf.h
  4. 284
      include/twofish.h
  5. 2
      src/edge_utils.c
  6. 505
      src/tf.c
  7. 279
      src/transform_tf.c
  8. 1002
      src/twofish.c
  9. 8
      tools/benchmark.c
  10. 2
      tools/n2n_decode.c

2
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

4
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

82
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 <http://www.gnu.org/licenses/>
*
*/
// 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 <stdint.h>
#include <stdlib.h>
#include <string.h>
#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

284
include/twofish.h

@ -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 <frank@knobbe.us>:
* --- 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 <stdint.h> /* 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

2
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:

505
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 <http://www.gnu.org/licenses/>
*
*/
// 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 <immintrin.h>
//#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;
}

279
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));
}

1002
src/twofish.c

File diff suppressed because it is too large

8
tools/benchmark.c

@ -62,7 +62,7 @@ static void parseArgs(int argc, char * argv[]) {
int main(int argc, char * argv[]) {
uint8_t pktbuf[N2N_PKT_BUF_SIZE];
n2n_trans_op_t transop_null, transop_twofish;
n2n_trans_op_t transop_null, transop_tf;
#ifdef N2N_HAVE_AES
n2n_trans_op_t transop_aes_cbc;
#endif
@ -82,7 +82,7 @@ int main(int argc, char * argv[]) {
/* Init transopts */
n2n_transop_null_init(&conf, &transop_null);
n2n_transop_twofish_init(&conf, &transop_twofish);
n2n_transop_tf_init(&conf, &transop_tf);
#ifdef N2N_HAVE_AES
n2n_transop_aes_cbc_init(&conf, &transop_aes_cbc);
#endif
@ -93,7 +93,7 @@ int main(int argc, char * argv[]) {
/* Run the tests */
run_transop_benchmark("transop_null", &transop_null, &conf, pktbuf);
run_transop_benchmark("transop_twofish", &transop_twofish, &conf, pktbuf);
run_transop_benchmark("transop_tf", &transop_tf, &conf, pktbuf);
#ifdef N2N_HAVE_AES
run_transop_benchmark("transop_aes", &transop_aes_cbc, &conf, pktbuf);
#endif
@ -104,7 +104,7 @@ int main(int argc, char * argv[]) {
/* Cleanup */
transop_null.deinit(&transop_null);
transop_twofish.deinit(&transop_twofish);
transop_tf.deinit(&transop_tf);
#ifdef N2N_HAVE_AES
transop_aes_cbc.deinit(&transop_aes_cbc);
#endif

2
tools/n2n_decode.c

@ -283,7 +283,7 @@ int main(int argc, char* argv[]) {
n2n_transop_aes_cbc_init(&conf, &transop);
else
#endif
n2n_transop_twofish_init(&conf, &transop);
n2n_transop_tf_init(&conf, &transop);
if((handle = pcap_create(ifname, errbuf)) == NULL) {
traceEvent(TRACE_ERROR, "Cannot open device %s: %s", ifname, errbuf);

Loading…
Cancel
Save