"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/transform_tf.c" between
n2n-2.8.tar.gz and n2n-3.0.tar.gz

About: n2n is a layer-two peer-to-peer virtual private network (VPN) which allows bypassing intermediate firewalls.

transform_tf.c  (n2n-2.8):transform_tf.c  (n2n-3.0)
/** /**
* (C) 2007-20 - ntop.org and contributors * (C) 2007-21 - ntop.org and contributors
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * 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/> * along with this program; if not see see <http://www.gnu.org/licenses/>
* *
*/ */
#include "n2n.h" #include "n2n.h"
#define N2N_TWOFISH_NUM_SA 32 /* space for SAa */ // size of random value prepended to plaintext defaults to TF_BLOCK_SIZE;
// gradually abandoning security, lower values could be chosen;
#define N2N_TWOFISH_TRANSFORM_VERSION 1 /* version of the transform encoding // 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 tf_null_iv
const uint8_t tf_null_iv[TF_IV_SIZE] = { 0 };
typedef struct transop_tf { typedef struct transop_tf {
TWOFISH* enc_tf; /* tx state */ tf_context_t *ctx;
TWOFISH* dec_tf; /* rx state */
} transop_tf_t; } 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) { transop_tf_t *priv = (transop_tf_t *)arg->priv;
TwoFishDestroy(priv->enc_tf); /* deallocate TWOFISH */
TwoFishDestroy(priv->dec_tf); /* deallocate TWOFISH */
free(priv);
}
return 0; if(priv->ctx)
} tf_deinit(priv->ctx);
#define TRANSOP_TF_VER_SIZE 1 /* Support minor variants in encoding in if(priv)
one module. */ free(priv);
#define TRANSOP_TF_NONCE_SIZE 4
#define TRANSOP_TF_SA_SIZE 4
/** The twofish packet format consists of: return 0;
* }
* - a 8-bit twofish encoding version in clear text
* - a 32-bit SA number in clear text // the Twofish packet format consists of
* - ciphertext encrypted from a 32-bit nonce followed by the payload. //
* // - a random TF_PREAMBLE_SIZE-sized value prepended to plaintext
* [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD] // encrypted together with the...
* |<------ encrypted ------>| // - ... payload data
*/ //
static int transop_encode_twofish( n2n_trans_op_t * arg, // [VV|DDDDDDDDDDDDDDDDDDDDD]
uint8_t * outbuf, // | <---- encrypted ----> |
size_t out_len, //
const uint8_t * inbuf, static int transop_encode_tf (n2n_trans_op_t *arg,
size_t in_len, uint8_t *outbuf,
const uint8_t * peer_mac) size_t out_len,
{ const uint8_t *inbuf,
int len=-1; size_t in_len,
transop_tf_t * priv = (transop_tf_t *)arg->priv; const uint8_t *peer_mac) {
uint8_t assembly[N2N_PKT_BUF_SIZE];
uint32_t * pnonce; transop_tf_t *priv = (transop_tf_t *)arg->priv;
if ( (in_len + TRANSOP_TF_NONCE_SIZE) <= N2N_PKT_BUF_SIZE ) // the assembly buffer is a source for encrypting data
{ // the whole contents of assembly are encrypted
if ( (in_len + TRANSOP_TF_NONCE_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_VER uint8_t assembly[N2N_PKT_BUF_SIZE];
_SIZE) <= out_len ) size_t idx = 0;
{ int padded_len;
size_t idx=0; uint8_t padding;
uint32_t sa_id=0; // Not used uint8_t buf[TF_BLOCK_SIZE];
traceEvent(TRACE_DEBUG, "encode_twofish %lu", in_len); if(in_len <= N2N_PKT_BUF_SIZE) {
if((in_len + TF_PREAMBLE_SIZE + TF_BLOCK_SIZE) <= out_len) {
/* Encode the twofish format version. */ traceEvent(TRACE_DEBUG, "transop_encode_tf %lu bytes plaintext", in_
encode_uint8( outbuf, &idx, N2N_TWOFISH_TRANSFORM_VERSION ); len);
/* Encode the security association (SA) number */ // full block sized random value (128 bit)
encode_uint32( outbuf, &idx, sa_id ); encode_uint64(assembly, &idx, n2n_rand());
encode_uint64(assembly, &idx, n2n_rand());
/* The assembly buffer is a source for encrypting data. The nonce is
* written in first followed by the packet payload. The whole // adjust for maybe differently chosen TF_PREAMBLE_SIZE
* contents of assembly are encrypted. */ idx = TF_PREAMBLE_SIZE;
pnonce = (uint32_t *)assembly;
*pnonce = n2n_rand(); // the plaintext data
memcpy( assembly + TRANSOP_TF_NONCE_SIZE, inbuf, in_len ); encode_buf(assembly, &idx, inbuf, in_len);
/* Encrypt the assembly contents and write the ciphertext after the SA. // round up to next whole TF block size
*/ padded_len = (((idx - 1) / TF_BLOCK_SIZE) + 1) * TF_BLOCK_SIZE;
len = TwoFishEncryptRaw( assembly, /* source */ padding = (padded_len-idx);
outbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_S
IZE, // pad the following bytes with zero, fixed length (TF_BLOCK_SIZE) s
in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */ eems to compile
priv->enc_tf); // to slightly faster code than run-time dependant 'padding'
if ( len > 0 ) memset(assembly + idx, 0, TF_BLOCK_SIZE);
{ tf_cbc_encrypt(outbuf, assembly, padded_len, tf_null_iv, priv->ctx);
len += TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE; /* size of data ca
rried in UDP. */ if(padding) {
} // exchange last two cipher blocks
else memcpy(buf, outbuf + padded_len - TF_BLOCK_SIZE, TF_BLOCK_SIZE);
{ memcpy(outbuf + padded_len - TF_BLOCK_SIZE, outbuf + padded_len
traceEvent( TRACE_ERROR, "encode_twofish encryption failed." ); - 2 * TF_BLOCK_SIZE, TF_BLOCK_SIZE);
memcpy(outbuf + padded_len - 2 * TF_BLOCK_SIZE, buf, TF_BLOCK_SI
ZE);
} }
} else
traceEvent(TRACE_ERROR, "transop_encode_tf outbuf too small");
} else
traceEvent(TRACE_ERROR, "transop_encode_tf inbuf too big to encrypt");
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) {
transop_tf_t *priv = (transop_tf_t *)arg->priv;
uint8_t assembly[N2N_PKT_BUF_SIZE];
uint8_t rest;
size_t penultimate_block;
uint8_t buf[TF_BLOCK_SIZE];
int len = -1;
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 require
ment 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 + penulti
mate_block, TF_BLOCK_SIZE);
// write new penultimate block from buf
memcpy(assembly + penultimate_block, buf, TF_BLOCK_SIZE);
// regular cbc decryption of the re-arranged ciphertext
tf_cbc_decrypt(assembly, assembly, in_len + TF_BLOCK_SIZE - rest, tf
_null_iv, priv->ctx);
// check for expected zero padding and give a warning otherwise
if(memcmp(assembly + in_len, tf_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, tf_null_iv, priv->ctx);
} }
else len = in_len - TF_PREAMBLE_SIZE;
{ memcpy(outbuf, assembly + TF_PREAMBLE_SIZE, len);
traceEvent( TRACE_ERROR, "encode_twofish outbuf too small." ); } else
} traceEvent(TRACE_ERROR, "transop_decode_tf inbuf wrong size (%ul) to dec
} rypt", in_len);
else
{ return len;
traceEvent( TRACE_ERROR, "encode_twofish inbuf too big to encrypt." ); }
static int setup_tf_key (transop_tf_t *priv, const uint8_t *password, ssize_t pa
ssword_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", ke
y_size * 8);
return -1;
} }
return len; traceEvent(TRACE_DEBUG, "setup_tf_key %u-bit key setup completed", key_size
* 8);
return 0;
} }
/** The twofish packet format consists of: static void transop_tick_tf (n2n_trans_op_t *arg, time_t now) {
*
* - a 8-bit twofish encoding version in clear text // no tick action
* - a 32-bit SA number in clear text }
* - ciphertext encrypted from a 32-bit nonce followed by the payload.
* // Twofish initialization function
* [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD] int n2n_transop_tf_init (const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
* |<------ encrypted ------>|
*/ transop_tf_t *priv;
static int transop_decode_twofish( n2n_trans_op_t * arg, const u_char *encrypt_key = (const u_char *)conf->encrypt_key;
uint8_t * outbuf, size_t encrypt_key_len = strlen(conf->encrypt_key);
size_t out_len,
const uint8_t * inbuf, memset(ttt, 0, sizeof(*ttt));
size_t in_len, ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
const uint8_t * peer_mac)
{ ttt->tick = transop_tick_tf;
int len=0; ttt->deinit = transop_deinit_tf;
transop_tf_t * priv = (transop_tf_t *)arg->priv; ttt->fwd = transop_encode_tf;
uint8_t assembly[N2N_PKT_BUF_SIZE]; ttt->rev = transop_decode_tf;
if ( ( (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)) <= N2N_PKT_BUF_SI priv = (transop_tf_t*)calloc(1, sizeof(transop_tf_t));
ZE ) /* Cipher text fits in assembly */ if(!priv) {
&& (in_len >= (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_NONC traceEvent(TRACE_ERROR, "n2n_transop_tf_cbc_init cannot allocate transop
E_SIZE) ) /* Has at least version, SA and nonce */ _tf_t memory");
) { return -1;
size_t rem=in_len; }
size_t idx=0; ttt->priv = priv;
uint8_t tf_enc_ver=0;
uint32_t sa_rx=0; // Not used
/* Get the encoding version to make sure it is supported */
decode_uint8( &tf_enc_ver, inbuf, &rem, &idx );
if ( N2N_TWOFISH_TRANSFORM_VERSION == tf_enc_ver ) {
/* Get the SA number and make sure we are decrypting with the right one
. */
decode_uint32( &sa_rx, inbuf, &rem, &idx );
traceEvent(TRACE_DEBUG, "decode_twofish %lu", in_len);
len = TwoFishDecryptRaw( (void *)(inbuf + TRANSOP_TF_VER_SIZE + TRANSOP
_TF_SA_SIZE),
assembly, /* destination */
(in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_
SA_SIZE)),
priv->dec_tf);
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 unsupported twofish version %u."
, tf_enc_ver );
} else
traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt."
, in_len );
return len;
}
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) {
transop_tf_t *priv;
const u_char *encrypt_key = (const u_char *)conf->encrypt_key;
size_t encrypt_key_len = strlen(conf->encrypt_key);
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;
priv = (transop_tf_t*) calloc(1, sizeof(transop_tf_t));
if(!priv) {
traceEvent(TRACE_ERROR, "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 a
ssociation. */
priv->enc_tf = TwoFishInit(encrypt_key, encrypt_key_len);
priv->dec_tf = TwoFishInit(encrypt_key, encrypt_key_len);
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);
} }
 End of changes. 14 change blocks. 
190 lines changed or deleted 203 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)