Browse Source

Code rework changes

- Remove keyschedule leftover and adapt to new API
- Fix cleanup functions
- Remove unused random_device_mac
pull/100/head
emanuele-f 5 years ago
parent
commit
c89ece71ca
  1. 4
      Makefile.in
  2. 48
      benchmark.c
  3. 42
      edge.c
  4. 62
      edge_utils.c
  5. 1
      legacy/edge_keyschedule.c
  6. 4
      n2n.c
  7. 11
      n2n.h
  8. 8
      n2n_transforms.h
  9. 17
      n2n_wire.h
  10. 548
      transform_aes.c
  11. 25
      transform_null.c
  12. 345
      transform_tf.c

4
Makefile.in

@ -44,7 +44,7 @@ MAN7DIR=$(MANDIR)/man7
MAN8DIR=$(MANDIR)/man8
N2N_LIB=libn2n.a
N2N_OBJS=n2n.o n2n_keyfile.o wire.o minilzo.o twofish.o \
N2N_OBJS=n2n.o wire.o minilzo.o twofish.o \
edge_utils.o \
transform_null.o transform_tf.o transform_aes.o \
tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o \
@ -81,7 +81,7 @@ benchmark: benchmark.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
example_edge_embed: example_edge_embed.c $(N2N_LIB) n2n.h
$(CC) $(CFLAGS) example_edge_embed.c $(N2N_LIB) $(LIBS_EDGE) -o example_edge_embed
.c.o: n2n.h n2n_keyfile.h n2n_transforms.h n2n_wire.h twofish.h Makefile
.c.o: n2n.h n2n_transforms.h n2n_wire.h twofish.h Makefile
$(CC) $(CFLAGS) -c $<
%.gz : %

48
benchmark.c

@ -70,7 +70,7 @@ uint8_t PKT_CONTENT[]={
/* Prototypes */
static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c );
static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, uint8_t *pktbuf, n2n_community_t c);
static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2n_edge_conf_t *conf, uint8_t *pktbuf);
static int perform_decryption = 0;
static void usage() {
@ -93,34 +93,44 @@ static void parseArgs(int argc, char * argv[]) {
int main(int argc, char * argv[]) {
uint8_t pktbuf[N2N_PKT_BUF_SIZE];
n2n_community_t c;
n2n_trans_op_t transop_null, transop_twofish, transop_aes_cbc;
u_char encrypt_pwd[] = "SoMEVer!S$cUREPassWORD";
n2n_trans_op_t transop_null, transop_twofish;
#ifdef N2N_HAVE_AES
n2n_trans_op_t transop_aes_cbc;
#endif
n2n_edge_conf_t conf;
parseArgs(argc, argv);
memset(c,0,sizeof(N2N_COMMUNITY_SIZE));
memcpy(c, "abc123def456", 12);
/* Init configuration */
edge_init_conf_defaults(&conf);
strncpy((char*)conf.community_name, "abc123def456", sizeof(conf.community_name));
conf.encrypt_key = "SoMEVer!S$cUREPassWORD";
/* Init transopts */
memset(&transop_null, 0, sizeof(transop_null));
transop_null_init(&transop_null);
memset(&transop_twofish, 0, sizeof(transop_twofish));
transop_twofish_init(&transop_twofish);
transop_twofish_setup_psk(&transop_twofish, 0, encrypt_pwd, sizeof(encrypt_pwd)-1);
memset(&transop_aes_cbc, 0, sizeof(transop_aes_cbc));
transop_aes_init(&transop_aes_cbc);
transop_aes_setup_psk(&transop_aes_cbc, 0, encrypt_pwd, sizeof(encrypt_pwd)-1);
n2n_transop_null_init(&conf, &transop_null);
n2n_transop_twofish_init(&conf, &transop_twofish);
#ifdef N2N_HAVE_AES
n2n_transop_aes_cbc_init(&conf, &transop_aes_cbc);
#endif
/* Run the tests */
run_transop_benchmark("transop_null", &transop_null, pktbuf, c);
run_transop_benchmark("transop_twofish", &transop_twofish, pktbuf, c);
run_transop_benchmark("transop_aes", &transop_aes_cbc, pktbuf, c);
run_transop_benchmark("transop_null", &transop_null, &conf, pktbuf);
run_transop_benchmark("transop_twofish", &transop_twofish, &conf, pktbuf);
#ifdef N2N_HAVE_AES
run_transop_benchmark("transop_aes", &transop_aes_cbc, &conf, pktbuf);
#endif
/* Cleanup */
transop_null.deinit(&transop_null);
transop_twofish.deinit(&transop_twofish);
#ifdef N2N_HAVE_AES
transop_aes_cbc.deinit(&transop_aes_cbc);
#endif
return 0;
}
static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, uint8_t *pktbuf, n2n_community_t c) {
static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, n2n_edge_conf_t *conf, uint8_t *pktbuf) {
n2n_common_t cmn;
n2n_PACKET_t pkt;
n2n_mac_t mac_buf;
@ -142,7 +152,7 @@ static void run_transop_benchmark(const char *op_name, n2n_trans_op_t *op_fn, ui
gettimeofday( &t1, NULL );
while(tdiff < target_usec) {
nw = do_encode_packet( pktbuf, N2N_PKT_BUF_SIZE, c);
nw = do_encode_packet( pktbuf, N2N_PKT_BUF_SIZE, conf->community_name);
nw += op_fn->fwd(op_fn,
pktbuf+nw, N2N_PKT_BUF_SIZE-nw,

42
edge.c

@ -142,7 +142,7 @@ static void help() {
printf("-a <mode:address> | Set interface address. For DHCP use '-r -a dhcp:0.0.0.0'\n");
printf("-c <community> | n2n community name the edge belongs to.\n");
printf("-k <encrypt key> | Encryption key (ASCII) - also N2N_KEY=<encrypt key>. Not with -K.\n");
printf("-k <encrypt key> | Encryption key (ASCII) - also N2N_KEY=<encrypt key>.\n");
printf("-s <netmask> | Edge interface netmask in dotted decimal notation (255.255.255.0).\n");
printf("-l <supernode host:port> | Supernode IP:port\n");
printf("-b | Periodically resolve supernode IP\n");
@ -160,14 +160,14 @@ static void help() {
printf("-M <mtu> | Specify n2n MTU of edge interface (default %d).\n", DEFAULT_MTU);
printf("-r | Enable packet forwarding through n2n community.\n");
#ifdef N2N_HAVE_AES
printf("-A | Set AES CBC as the preferred encryption mode.\n");
printf("-A | Use AES CBC for encryption (default=use twofish).\n");
#endif
printf("-E | Accept multicast MAC addresses (default=drop).\n");
printf("-v | Make more verbose. Repeat as required.\n");
printf("-t <port> | Management UDP Port (for multiple edges on a machine).\n");
printf("\nEnvironment variables:\n");
printf(" N2N_KEY | Encryption key (ASCII). Not with -K or -k.\n");
printf(" N2N_KEY | Encryption key (ASCII). Not with -k.\n");
exit(0);
}
@ -536,20 +536,6 @@ static void daemonize() {
/* *************************************************** */
void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
memset(conf, 0, sizeof(*conf));
conf->local_port = 0 /* any port */;
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH; /* use twofish for compatibility */
conf->drop_multicast = 1;
if(getenv("N2N_KEY"))
conf->encrypt_key = strdup(getenv("N2N_KEY"));
}
/* *************************************************** */
/** Entry point to program from kernel. */
int main(int argc, char* argv[]) {
int keep_on_running = 1;
@ -564,6 +550,7 @@ int main(int argc, char* argv[]) {
/* Defaults */
edge_init_conf_defaults(&conf);
memset(&ec, 0, sizeof(ec));
ec.mtu = DEFAULT_MTU;
ec.daemon = 1; /* By default run in daemon mode. */
#ifndef WIN32
@ -579,6 +566,8 @@ int main(int argc, char* argv[]) {
snprintf(ec.ip_mode, sizeof(ec.ip_mode), "static");
snprintf(ec.netmask, sizeof(ec.netmask), "255.255.255.0");
traceEvent(TRACE_NORMAL, "Starting n2n edge %s %s", PACKAGE_VERSION, PACKAGE_BUILDDATE);
#ifndef WIN32
if((argc >= 2) && (argv[1][0] != '-')) {
rc = loadFromFile(argv[1], &conf, &ec);
@ -591,8 +580,6 @@ int main(int argc, char* argv[]) {
if(rc < 0)
help();
traceEvent(TRACE_NORMAL, "Starting n2n edge %s %s", PACKAGE_VERSION, PACKAGE_BUILDDATE);
if(0 == strcmp("dhcp", ec.ip_mode)) {
traceEvent(TRACE_NORMAL, "Dynamic IP address assignment enabled.");
@ -611,6 +598,12 @@ int main(int argc, char* argv[]) {
))
help();
#ifndef WIN32
/* If running suid root then we need to setuid before using the force. */
setuid(0);
/* setgid(0); */
#endif
if(tuntap_open(&tuntap, ec.tuntap_dev_name, ec.ip_mode, ec.ip_addr, ec.netmask, ec.device_mac, ec.mtu) < 0)
return(-1);
@ -619,12 +612,6 @@ int main(int argc, char* argv[]) {
exit(1);
}
#ifndef WIN32
/* If running suid root then we need to setuid before using the force. */
setuid(0);
/* setgid(0); */
#endif
#ifndef WIN32
if(ec.daemon) {
setUseSyslog(1); /* traceEvent output now goes to syslog. */
@ -644,11 +631,14 @@ int main(int argc, char* argv[]) {
#endif
traceEvent(TRACE_NORMAL, "edge started");
rc = run_edge_loop(eee, &keep_on_running);
/* Cleanup */
edge_term(eee);
tuntap_close(&tuntap);
if(conf.encrypt_key) free(conf.encrypt_key);
return(rc);
}

62
edge_utils.c

@ -59,6 +59,7 @@ static void check_peer(n2n_edge_t * eee,
const n2n_mac_t mac,
const n2n_sock_t * peer);
static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port);
static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn);
/* ************************************** */
@ -117,7 +118,7 @@ struct n2n_edge {
* This also initialises the NULL transform operation opstruct.
*/
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv) {
n2n_transform_id_t transop_id = conf->transop_id;
n2n_transform_t transop_id = conf->transop_id;
n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t));
int rc = -1;
@ -166,15 +167,15 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
switch(transop_id) {
case N2N_TRANSFORM_ID_TWOFISH:
rc = n2n_transop_twofish_init(eee, &eee->transop);
rc = n2n_transop_twofish_init(&eee->conf, &eee->transop);
break;
#ifdef N2N_HAVE_AES
case N2N_TRANSFORM_ID_AESCBC:
rc = n2n_transop_aes_init(eee, &eee->transop);
rc = n2n_transop_aes_cbc_init(&eee->conf, &eee->transop);
break;
#endif
default:
rc = n2n_transop_null_init(eee, &eee->transop);
rc = n2n_transop_null_init(&eee->conf, &eee->transop);
}
if((rc < 0) || (eee->transop.fwd == NULL) || (eee->transop.transform_id != transop_id)) {
@ -208,7 +209,7 @@ edge_init_error:
* REVISIT: This is a really bad idea. The edge will block completely while the
* hostname resolution is performed. This could take 15 seconds.
*/
void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) {
n2n_sn_name_t addr;
const char *supernode_host;
@ -786,9 +787,9 @@ static int handle_PACKET(n2n_edge_t * eee,
{
uint8_t decodebuf[N2N_PKT_BUF_SIZE];
size_t eth_size;
n2n_transform_id_t rx_transop_id;
n2n_transform_t rx_transop_id;
rx_transop_id = (n2n_transform_id_t)pkt->transform;
rx_transop_id = (n2n_transform_t)pkt->transform;
if(rx_transop_id == eee->conf.transop_id) {
eth_payload = decodebuf;
@ -1575,32 +1576,7 @@ void edge_term(n2n_edge_t * eee) {
clear_peer_list(&(eee->known_peers));
eee->transop.deinit(&eee->transop);
}
/* ************************************** */
// TODO check
const char *random_device_mac(void)
{
const char key[] = "0123456789abcdef";
static char mac[18];
int i;
for (i = 0; i < sizeof(mac) - 1; ++i) {
if ((i + 1) % 3 == 0) {
mac[i] = ':';
continue;
}
#ifdef WIN32
#define random rand
#endif
mac[i] = key[random() % sizeof(key)];
#ifdef WIN32
#undef random
#endif
}
mac[sizeof(mac) - 1] = '\0';
return mac;
memset(eee, 0, sizeof(*eee));
}
/* ************************************** */
@ -1661,6 +1637,26 @@ static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port)
/* ************************************** */
void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
memset(conf, 0, sizeof(*conf));
conf->local_port = 0 /* any port */;
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH; /* use twofish for compatibility */
conf->drop_multicast = 1;
if(getenv("N2N_KEY"))
conf->encrypt_key = strdup(getenv("N2N_KEY"));
}
/* ************************************** */
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee) {
return(&eee->conf);
}
/* ************************************** */
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port) {
if(conf->sn_num >= N2N_EDGE_NUM_SUPERNODES)
return(-1);

1
legacy/edge_keyschedule.c

@ -3,6 +3,7 @@ typedef struct n2n_tostat {
n2n_cipherspec_t tx_spec; /* If can_tx, the spec used to encode. */
} n2n_tostat_t;
typedef uint32_t n2n_sa_t; /* security association number */
typedef int (*n2n_transaddspec_f)( struct n2n_trans_op * arg,
const n2n_cipherspec_t * cspec );

4
n2n.c

@ -87,8 +87,8 @@ void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...) {
va_list va_ap;
if(eventTraceLevel <= traceLevel) {
char buf[2048];
char out_buf[640];
char buf[1024];
char out_buf[1280];
char theDate[N2N_TRACE_DATESIZE];
char *extra_msg = "";
time_t theTime = time(NULL);

11
n2n.h

@ -186,7 +186,7 @@ typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];
typedef struct n2n_edge_conf {
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
n2n_community_t community_name; /**< The community. 16 full octets. */
n2n_transform_id_t transop_id; /**< The transop to use. */
n2n_transform_t transop_id; /**< The transop to use. */
uint8_t re_resolve_supernode_ip;
uint8_t dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */
uint8_t allow_routing; /**< Accept packet no to interface address. */
@ -230,10 +230,10 @@ typedef struct n2n_edge n2n_edge_t; /* Opaque, see edge_utils.c */
/* ************************************** */
/* Transop Init Functions */
int n2n_transop_null_init(n2n_edge_t *eee, n2n_trans_op_t *op);
int n2n_transop_twofish_init(n2n_edge_t *eee, n2n_trans_op_t *op);
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);
#ifdef N2N_HAVE_AES
int n2n_transop_aes_init(n2n_edge_t *eee, n2n_trans_op_t *op);
int n2n_transop_aes_cbc_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
#endif
/* Log */
@ -258,9 +258,7 @@ uint8_t is_multi_broadcast(const uint8_t * dest_mac);
char* msg_type2str(uint16_t msg_type);
void hexdump(const uint8_t * buf, size_t len);
void print_n2n_version();
void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn);
int is_empty_ip_address(const n2n_sock_t * sock);
const char *random_device_mac(void);
/* Sockets */
char* sock_to_cstr( n2n_sock_str_t out,
@ -289,6 +287,7 @@ void update_peer_address(n2n_edge_t * eee,
void edge_init_conf_defaults(n2n_edge_conf_t *conf);
int edge_verify_conf(const n2n_edge_conf_t *conf);
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port);
const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee);
/* Public functions */
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv);

8
n2n_transforms.h

@ -24,12 +24,12 @@
#define N2N_TRANSFORM_ID_USER_START 64
#define N2N_TRANSFORM_ID_MAX 65535
typedef enum n2n_transform_id {
typedef enum n2n_transform {
N2N_TRANSFORM_ID_INVAL = 0,
N2N_TRANSFORM_ID_NULL = 1,
N2N_TRANSFORM_ID_TWOFISH = 2,
N2N_TRANSFORM_ID_AESCBC = 3,
} n2n_transform_id_t;
} n2n_transform_t;
struct n2n_trans_op;
@ -50,8 +50,8 @@ typedef int (*n2n_transform_f)( struct n2n_trans_op * arg,
*/
typedef struct n2n_trans_op {
void * priv; /* opaque data. Key schedule goes here. */
uint8_t no_encryption; /* 1 if this transop does not perform encryption */ // TODO
n2n_transform_t transform_id; /* link header enum to a transform */
uint8_t no_encryption; /* 1 if this transop does not perform encryption */
n2n_transform_t transform_id;
size_t tx_cnt;
size_t rx_cnt;

17
n2n_wire.h

@ -51,7 +51,7 @@ typedef uint8_t n2n_cookie_t[N2N_COOKIE_SIZE];
typedef char n2n_sock_str_t[N2N_SOCKBUF_SIZE]; /* tracing string buffer */
enum n2n_pc
typedef enum n2n_pc
{
n2n_ping=0, /* Not used */
n2n_register=1, /* Register edge to edge */
@ -62,9 +62,7 @@ enum n2n_pc
n2n_register_super_ack=6, /* ACK from supernode to edge */
n2n_register_super_nak=7, /* NAK from supernode to edge - registration refused */
n2n_federation=8 /* Not used by edge */
};
typedef enum n2n_pc n2n_pc_t;
} n2n_pc_t;
#define N2N_FLAGS_OPTIONS 0x0080
#define N2N_FLAGS_SOCKET 0x0040
@ -86,11 +84,6 @@ typedef enum n2n_pc n2n_pc_t;
#define N2N_EINVAL -3
#define N2N_ENOSPACE -4
typedef uint16_t n2n_flags_t;
typedef uint16_t n2n_transform_t; /* Encryption, compression type. */
typedef uint32_t n2n_sa_t; /* security association number */
struct n2n_sock
{
uint8_t family; /* AF_INET or AF_INET6; or 0 if invalid */
@ -118,8 +111,8 @@ struct n2n_common
{
/* int version; */
uint8_t ttl;
n2n_pc_t pc;
n2n_flags_t flags;
uint8_t pc;
uint16_t flags;
n2n_community_t community;
};
@ -150,7 +143,7 @@ struct n2n_PACKET
n2n_mac_t srcMac;
n2n_mac_t dstMac;
n2n_sock_t sock;
n2n_transform_t transform;
uint16_t transform;
};
typedef struct n2n_PACKET n2n_PACKET_t;

548
transform_aes.c

@ -19,16 +19,10 @@
#include "n2n.h"
#include "n2n_transforms.h"
#if defined(N2N_HAVE_AES)
#ifdef N2N_HAVE_AES
#include "openssl/aes.h"
#include "openssl/sha.h"
#ifndef _MSC_VER
/* Not included in Visual Studio 2008 */
#include <strings.h> /* index() */
#endif
#define N2N_AES_NUM_SA 32 /* space for SAa */
#define N2N_AES_TRANSFORM_VERSION 1 /* version of the transform encoding */
#define N2N_AES_IVEC_SIZE 32 /* Enough space for biggest AES ivec */
@ -37,88 +31,39 @@
#define AES192_KEY_BYTES (192/8)
#define AES128_KEY_BYTES (128/8)
/* AES plaintext preamble */
#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */
#define TRANSOP_AES_SA_SIZE 4
#define TRANSOP_AES_IV_SEED_SIZE 8
#define TRANSOP_AES_PREAMBLE_SIZE (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_IV_SEED_SIZE)
/* AES ciphertext preamble */
#define TRANSOP_AES_NONCE_SIZE 4
typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE];
struct sa_aes
{
n2n_cipherspec_t spec; /* cipher spec parameters */
n2n_sa_t sa_id; /* security association index */
typedef struct transop_aes {
AES_KEY enc_key; /* tx key */
AES_KEY dec_key; /* tx key */
AES_KEY iv_enc_key; /* key used to encrypt the IV */
uint8_t iv_ext_val[AES128_KEY_BYTES]; /* key used to extend the random IV seed to full block size */
};
typedef struct sa_aes sa_aes_t;
/** Aes transform state data.
*
* With a key-schedule in place this will be populated with a number of
* SAs. Each SA has a lifetime and some opque data. The opaque data for aes
* consists of the SA number and key material.
*
*/
struct transop_aes
{
ssize_t tx_sa;
size_t num_sa;
sa_aes_t sa[N2N_AES_NUM_SA];
u_int8_t psk_mode;
};
typedef struct transop_aes transop_aes_t;
static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id );
static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size, size_t sa_num);
static int transop_deinit_aes( n2n_trans_op_t * arg )
{
transop_aes_t * priv = (transop_aes_t *)arg->priv;
size_t i;
if ( priv )
{
/* Memory was previously allocated */
for (i=0; i<N2N_AES_NUM_SA; ++i )
{
sa_aes_t * sa = &(priv->sa[i]);
} transop_aes_t;
sa->sa_id=0;
}
struct sha512_keybuf {
uint8_t enc_dec_key[AES256_KEY_BYTES]; /* The key to use for AES CBC encryption/decryption */
uint8_t iv_enc_key[AES128_KEY_BYTES]; /* The key to use to encrypt the IV with AES ECB */
uint8_t iv_ext_val[AES128_KEY_BYTES]; /* A value to extend the IV seed */
}; /* size: SHA512_DIGEST_LENGTH */
priv->num_sa=0;
priv->tx_sa=-1;
static int transop_deinit_aes(n2n_trans_op_t *arg) {
transop_aes_t *priv = (transop_aes_t *)arg->priv;
if(priv)
free(priv);
}
arg->priv=NULL; /* return to fully uninitialised state */
return 0;
}
static size_t aes_choose_tx_sa( transop_aes_t * priv, const u_int8_t * peer_mac ) {
return priv->tx_sa; /* set in tick */
}
static ssize_t aes_choose_rx_sa( transop_aes_t * priv, const u_int8_t * peer_mac, ssize_t sa_rx) {
if(!priv->psk_mode)
return aes_find_sa(priv, sa_rx);
else
/* NOTE the sa_rx of the packet is ignored in this case */
return 0;
}
/* AES plaintext preamble */
#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */
#define TRANSOP_AES_SA_SIZE 4
#define TRANSOP_AES_IV_SEED_SIZE 8
#define TRANSOP_AES_PREAMBLE_SIZE (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_IV_SEED_SIZE)
/* AES ciphertext preamble */
#define TRANSOP_AES_NONCE_SIZE 4
/* Return the best acceptable AES key size (in bytes) given an input keysize.
*
* The value returned will be one of AES128_KEY_BYTES, AES192_KEY_BYTES or
@ -140,11 +85,11 @@ static size_t aes_best_keysize(size_t numBytes)
}
}
static void set_aes_cbc_iv(sa_aes_t *sa, n2n_aes_ivec_t ivec, uint64_t iv_seed) {
static void set_aes_cbc_iv(transop_aes_t *priv, n2n_aes_ivec_t ivec, uint64_t iv_seed) {
uint8_t iv_full[AES_BLOCK_SIZE];
/* Extend the seed to full block size via the fixed ext value */
memcpy(iv_full, sa->iv_ext_val, sizeof(iv_seed)); // note: only 64bits used of 128 available
memcpy(iv_full, priv->iv_ext_val, sizeof(iv_seed)); // note: only 64bits used of 128 available
memcpy(iv_full + sizeof(iv_seed), &iv_seed, sizeof(iv_seed));
/* Encrypt the IV with secret key to make it unpredictable.
@ -153,7 +98,7 @@ static void set_aes_cbc_iv(sa_aes_t *sa, n2n_aes_ivec_t ivec, uint64_t iv_seed)
* can be easily reconstructed from plaintext headers and used by an attacker
* to perform differential analysis.
*/
AES_ecb_encrypt(iv_full, ivec, &sa->iv_enc_key, AES_ENCRYPT);
AES_ecb_encrypt(iv_full, ivec, &priv->iv_enc_key, AES_ENCRYPT);
}
/** The aes packet format consists of:
@ -178,30 +123,22 @@ static int transop_encode_aes( n2n_trans_op_t * arg,
uint8_t assembly[N2N_PKT_BUF_SIZE] = {0};
uint32_t * pnonce;
if ( (in_len + TRANSOP_AES_NONCE_SIZE) <= N2N_PKT_BUF_SIZE )
{
if ( (in_len + TRANSOP_AES_NONCE_SIZE + TRANSOP_AES_PREAMBLE_SIZE) <= out_len )
{
if ( (in_len + TRANSOP_AES_NONCE_SIZE) <= N2N_PKT_BUF_SIZE ) {
if ( (in_len + TRANSOP_AES_NONCE_SIZE + TRANSOP_AES_PREAMBLE_SIZE) <= out_len ) {
int len=-1;
size_t idx=0;
sa_aes_t * sa;
size_t tx_sa_num = 0;
size_t tx_sa_num = 0; // Not used
uint64_t iv_seed = 0;
uint8_t padding = 0;
n2n_aes_ivec_t enc_ivec = {0};
/* The transmit sa is periodically updated */
tx_sa_num = aes_choose_tx_sa( priv, peer_mac );
sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
traceEvent( TRACE_DEBUG, "encode_aes %lu with SA %lu.", in_len, sa->sa_id );
traceEvent( TRACE_DEBUG, "encode_aes %lu", in_len);
/* Encode the aes format version. */
encode_uint8( outbuf, &idx, N2N_AES_TRANSFORM_VERSION );
/* Encode the security association (SA) number */
encode_uint32( outbuf, &idx, sa->sa_id );
encode_uint32( outbuf, &idx, tx_sa_num ); // Not used
/* Generate and encode the IV seed.
* Using two calls to rand() because RAND_MAX is usually < 64bit
@ -227,60 +164,29 @@ static int transop_encode_aes( n2n_trans_op_t * arg,
assembly[len2 - 1] = padding;
traceEvent( TRACE_DEBUG, "padding = %u, seed = %016lx", padding, iv_seed );
set_aes_cbc_iv(sa, enc_ivec, iv_seed);
set_aes_cbc_iv(priv, enc_ivec, iv_seed);
AES_cbc_encrypt( assembly, /* source */
outbuf + TRANSOP_AES_PREAMBLE_SIZE, /* dest */
len2, /* enc size */
&(sa->enc_key), enc_ivec, AES_ENCRYPT );
&(priv->enc_key), enc_ivec, AES_ENCRYPT );
len2 += TRANSOP_AES_PREAMBLE_SIZE; /* size of data carried in UDP. */
}
else
{
} else
traceEvent( TRACE_ERROR, "encode_aes outbuf too small." );
}
}
else
{
} else
traceEvent( TRACE_ERROR, "encode_aes inbuf too big to encrypt." );
}
return len2;
}
/* Search through the array of SAs to find the one with the required ID.
*
* @return array index where found or -1 if not found
*/
static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id )
{
size_t i;
for (i=0; i < priv->num_sa; ++i)
{
const sa_aes_t * sa=NULL;
sa = &(priv->sa[i]);
if (req_id == sa->sa_id)
{
return i;
}
}
return -1;
}
/* See transop_encode_aes for packet format */
static int transop_decode_aes( 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)
{
const uint8_t * peer_mac) {
int len=0;
transop_aes_t * priv = (transop_aes_t *)arg->priv;
uint8_t assembly[N2N_PKT_BUF_SIZE];
@ -289,8 +195,7 @@ static int transop_decode_aes( n2n_trans_op_t * arg,
&& (in_len >= (TRANSOP_AES_PREAMBLE_SIZE + TRANSOP_AES_NONCE_SIZE) ) /* Has at least version, SA, iv seed and nonce */
)
{
n2n_sa_t sa_rx;
ssize_t sa_idx=-1;
uint32_t sa_rx=0; // Not used
size_t rem=in_len;
size_t idx=0;
uint8_t aes_enc_ver=0;
@ -299,35 +204,27 @@ static int transop_decode_aes( n2n_trans_op_t * arg,
/* Get the encoding version to make sure it is supported */
decode_uint8( &aes_enc_ver, inbuf, &rem, &idx );
if ( N2N_AES_TRANSFORM_VERSION == aes_enc_ver )
{
/* Get the SA number and make sure we are decrypting with the right one. */
if ( N2N_AES_TRANSFORM_VERSION == aes_enc_ver ) {
/* Get the SA number and make sure we are decrypting with the right one. - Not used*/
decode_uint32( &sa_rx, inbuf, &rem, &idx );
sa_idx = aes_choose_rx_sa(priv, peer_mac, sa_rx);
if ( sa_idx >= 0 )
{
sa_aes_t * sa = &(priv->sa[sa_idx]);
/* Get the IV seed */
decode_buf((uint8_t *)&iv_seed, sizeof(iv_seed), inbuf, &rem, &idx);
traceEvent( TRACE_DEBUG, "decode_aes %lu with SA %lu and seed %016lx", in_len, sa->sa_id, iv_seed );
traceEvent( TRACE_DEBUG, "decode_aes %lu with seed %016lx", in_len, iv_seed );
len = (in_len - TRANSOP_AES_PREAMBLE_SIZE);
if ( 0 == (len % AES_BLOCK_SIZE ) )
{
if ( 0 == (len % AES_BLOCK_SIZE ) ) {
uint8_t padding;
n2n_aes_ivec_t dec_ivec = {0};
set_aes_cbc_iv(sa, dec_ivec, iv_seed);
set_aes_cbc_iv(priv, dec_ivec, iv_seed);
AES_cbc_encrypt( (inbuf + TRANSOP_AES_PREAMBLE_SIZE),
assembly, /* destination */
len,
&(sa->dec_key),
&(priv->dec_key),
dec_ivec, AES_DECRYPT );
/* last byte is how much was padding: max value should be
@ -348,61 +245,30 @@ static int transop_decode_aes( n2n_trans_op_t * arg,
memcpy( outbuf,
assembly + TRANSOP_AES_NONCE_SIZE,
len );
}
else
{
} else
traceEvent( TRACE_WARNING, "UDP payload decryption failed." );
}
}
else
{
} else {
traceEvent( TRACE_WARNING, "Encrypted length %d is not a multiple of AES_BLOCK_SIZE (%d)", len, AES_BLOCK_SIZE );
len = 0;
}
}
else
{
/* Wrong security association; drop the packet as it is undecodable. */
traceEvent( TRACE_ERROR, "decode_aes SA number %lu not found.", sa_rx );
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
}
}
else
{
/* Wrong security association; drop the packet as it is undecodable. */
} else
traceEvent( TRACE_ERROR, "decode_aes unsupported aes version %u.", aes_enc_ver );
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
}
}
else
{
} else
traceEvent( TRACE_ERROR, "decode_aes inbuf wrong size (%ul) to decrypt.", in_len );
}
return len;
}
struct sha512_keybuf {
uint8_t enc_dec_key[AES256_KEY_BYTES]; /* The key to use for AES CBC encryption/decryption */
uint8_t iv_enc_key[AES128_KEY_BYTES]; /* The key to use to encrypt the IV with AES ECB */
uint8_t iv_ext_val[AES128_KEY_BYTES]; /* A value to extend the IV seed */
}; /* size: SHA512_DIGEST_LENGTH */
/* NOTE: the caller should adjust priv->num_sa accordingly */
static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size, size_t sa_num) {
sa_aes_t * sa = &(priv->sa[sa_num]);
static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size) {
size_t aes_keysize_bytes;
size_t aes_keysize_bits;
struct sha512_keybuf keybuf;
/* Clear out any old possibly longer key matter. */
memset( &(sa->enc_key), 0, sizeof(sa->enc_key) );
memset( &(sa->dec_key), 0, sizeof(sa->dec_key) );
memset( &(sa->iv_enc_key), 0, sizeof(sa->iv_enc_key) );
memset( &(sa->iv_ext_val), 0, sizeof(sa->iv_ext_val) );
memset( &(priv->enc_key), 0, sizeof(priv->enc_key) );
memset( &(priv->dec_key), 0, sizeof(priv->dec_key) );
memset( &(priv->iv_enc_key), 0, sizeof(priv->iv_enc_key) );
memset( &(priv->iv_ext_val), 0, sizeof(priv->iv_ext_val) );
/* We still use aes_best_keysize (even not necessary since we hash the key
* into the 256bits enc_dec_key) to let the users choose the degree of encryption.
@ -415,316 +281,44 @@ static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_si
SHA512(key, key_size, (u_char*)&keybuf);
/* setup of enc_key/dec_key, used for the CBC encryption */
AES_set_encrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(sa->enc_key));
AES_set_decrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(sa->dec_key));
AES_set_encrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(priv->enc_key));
AES_set_decrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(priv->dec_key));
/* setup of iv_enc_key and iv_ext_val, used for generating the CBC IV */
AES_set_encrypt_key(keybuf.iv_enc_key, sizeof(keybuf.iv_enc_key) * 8, &(sa->iv_enc_key));
memcpy(sa->iv_ext_val, keybuf.iv_ext_val, sizeof(keybuf.iv_ext_val));
AES_set_encrypt_key(keybuf.iv_enc_key, sizeof(keybuf.iv_enc_key) * 8, &(priv->iv_enc_key));
memcpy(priv->iv_ext_val, keybuf.iv_ext_val, sizeof(keybuf.iv_ext_val));
traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits key=%s.\n",
priv->sa[sa_num].sa_id, aes_keysize_bits, key);
traceEvent( TRACE_DEBUG, "AES %u bits setup completed\n",
aes_keysize_bits, key);
return(0);
}
/*
* priv: pointer to transform state
* keybuf: buffer holding the key
* pstat: length of keybuf
*/
static void add_aes_key(transop_aes_t *priv, uint8_t *keybuf, ssize_t pstat) {
setup_aes_key(priv, keybuf, pstat, priv->num_sa);
++(priv->num_sa);
}
static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
{
int retval = 1;
ssize_t pstat=-1;
transop_aes_t * priv = (transop_aes_t *)arg->priv;
uint8_t keybuf[N2N_MAX_KEYSIZE];
if ( priv->num_sa < N2N_AES_NUM_SA )
{
const char * op = (const char *)cspec->opaque;
const char * sep = index( op, '_' );
if ( sep )
{
char tmp[256];
size_t s;
s = sep - op;
memcpy( tmp, cspec->opaque, s );
tmp[s]=0;
s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
static void transop_tick_aes(n2n_trans_op_t * arg, time_t now) {}
priv->sa[priv->num_sa].spec = *cspec;
priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
memset( keybuf, 0, N2N_MAX_KEYSIZE );
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
if ( pstat > 0 )
{
add_aes_key(priv, keybuf, pstat);
retval = 0;
}
}
else
{
traceEvent( TRACE_ERROR, "transop_addspec_aes : bad key data - missing '_'.\n");
}
}
else
{
traceEvent( TRACE_ERROR, "transop_addspec_aes : full.\n");
}
return retval;
}
static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
{
transop_aes_t * priv = (transop_aes_t *)arg->priv;
size_t i;
int found=0;
n2n_tostat_t r;
memset( &r, 0, sizeof(r) );
traceEvent( TRACE_DEBUG, "transop_aes tick num_sa=%u now=%lu", priv->num_sa, now );
for ( i=0; i < priv->num_sa; ++i )
{
if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
{
time_t remaining = priv->sa[i].spec.valid_until - now;
traceEvent( TRACE_INFO, "transop_aes choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
priv->tx_sa=i;
found=1;
break;
}
else
{
traceEvent( TRACE_DEBUG, "transop_aes tick rejecting sa=%u %lu -> %lu",
priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
}
}
if ( 0==found)
{
traceEvent( TRACE_INFO, "transop_aes no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
}
else
{
r.can_tx = 1;
r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC;
r.tx_spec = priv->sa[priv->tx_sa].spec;
}
return r;
}
static n2n_tostat_t transop_tick_aes_psk(n2n_trans_op_t * arg, time_t now) {
transop_aes_t * priv = (transop_aes_t *)arg->priv;
n2n_tostat_t r;
memset(&r, 0, sizeof(r));
// Always tx
r.can_tx = 1;
r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC;
r.tx_spec = priv->sa[priv->tx_sa].spec;
return r;
}
int transop_aes_init( n2n_trans_op_t * ttt )
{
int retval = 1;
transop_aes_t * priv = NULL;
if ( ttt->priv )
{
transop_deinit_aes( ttt );
}
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
priv = (transop_aes_t *) calloc(1, sizeof(transop_aes_t));
if ( NULL != priv )
{
size_t i;
sa_aes_t * sa=NULL;
/* install the private structure. */
ttt->priv = priv;
priv->num_sa=0;
priv->tx_sa=0; /* We will use this sa index for encoding. */
priv->psk_mode = 0;
/* AES initialization function */
int n2n_transop_aes_cbc_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
transop_aes_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_AESCBC;
ttt->addspec = transop_addspec_aes;
ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
ttt->deinit = transop_deinit_aes;
ttt->fwd = transop_encode_aes;
ttt->rev = transop_decode_aes;
for(i=0; i<N2N_AES_NUM_SA; ++i)
{
sa = &(priv->sa[i]);
sa->sa_id=0;
memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
memset( &(sa->enc_key), 0, sizeof(sa->enc_key) );
memset( &(sa->dec_key), 0, sizeof(sa->dec_key) );
memset( &(sa->iv_enc_key), 0, sizeof(sa->iv_enc_key) );
memset( &(sa->iv_ext_val), 0, sizeof(sa->iv_ext_val) );
}
retval = 0;
}
else
{
memset( ttt, 0, sizeof(n2n_trans_op_t) );
traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
}
return retval;
}
/* Setup AES in pre-shared key mode */
int transop_aes_setup_psk(n2n_trans_op_t *ttt,
n2n_sa_t sa_num,
uint8_t *encrypt_pwd,
uint32_t encrypt_pwd_len) {
int retval = 1;
transop_aes_t *priv = (transop_aes_t *)ttt->priv;
if(ttt->priv) {
/* Replace the tick function with the PSK version of it */
ttt->tick = transop_tick_aes_psk;
priv->psk_mode = 1;
priv->num_sa=0;
priv->tx_sa=0;
/* Setup the key to use for encryption/decryption */
add_aes_key(priv, encrypt_pwd, encrypt_pwd_len);
retval = 0;
} else
traceEvent(TRACE_ERROR, "AES priv is not allocated");
return retval;
}
#else /* #if defined(N2N_HAVE_AES) */
struct transop_aes
{
ssize_t tx_sa;
};
typedef struct transop_aes transop_aes_t;
static int transop_deinit_aes( n2n_trans_op_t * arg )
{
transop_aes_t * priv = (transop_aes_t *)arg->priv;
if ( priv )
{
free(priv);
}
arg->priv=NULL; /* return to fully uninitialised state */
return 0;
}
static int transop_encode_aes( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
return -1;
}
static int transop_decode_aes( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
return -1;
}
static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
{
traceEvent( TRACE_DEBUG, "transop_addspec_aes AES not built into edge.\n");
return -1;
}
static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
{
n2n_tostat_t r;
memset( &r, 0, sizeof(r) );
return r;
}
int transop_aes_init( n2n_trans_op_t * ttt )
{
int retval = 1;
transop_aes_t * priv = NULL;
if ( ttt->priv )
{
transop_deinit_aes( ttt );
}
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) );
if ( NULL != priv )
{
/* install the private structure. */
ttt->priv = priv;
priv->tx_sa=0; /* We will use this sa index for encoding. */
ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
ttt->addspec = transop_addspec_aes;
ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
ttt->tick = transop_tick_aes;
ttt->deinit = transop_deinit_aes;
ttt->fwd = transop_encode_aes;
ttt->rev = transop_decode_aes;
retval = 0;
priv = (transop_aes_t*) calloc(1, sizeof(transop_aes_t));
if(!priv) {
traceEvent(TRACE_ERROR, "cannot allocate transop_aes_t memory");
return(-1);
}
else
{
memset( ttt, 0, sizeof(n2n_trans_op_t) );
traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
}
return retval;
}
ttt->priv = priv;
int transop_aes_setup_psk(n2n_trans_op_t *ttt,
n2n_sa_t sa_num,
uint8_t *encrypt_pwd,
uint32_t encrypt_pwd_len) {
return 0;
/* Setup the key */
return(setup_aes_key(priv, encrypt_key, encrypt_key_len));
}
#endif /* #if defined(N2N_HAVE_AES) */
#endif /* N2N_HAVE_AES */

25
transform_null.c

@ -71,32 +71,17 @@ static int transop_decode_null( n2n_trans_op_t * arg,
return retval;
}
static int transop_addspec_null( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
{
return 0;
}
static n2n_tostat_t transop_tick_null( n2n_trans_op_t * arg, time_t now )
{
n2n_tostat_t r;
static void transop_tick_null(n2n_trans_op_t * arg, time_t now) {}
r.can_tx=1;
r.tx_spec.t = N2N_TRANSFORM_ID_NULL;
r.tx_spec.valid_from = 0;
r.tx_spec.valid_until = (time_t)(-1);
r.tx_spec.opaque_size=0;
return r;
}
void transop_null_init( n2n_trans_op_t * ttt )
{
int n2n_transop_null_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
memset(ttt, 0, sizeof(n2n_trans_op_t) );
ttt->transform_id = N2N_TRANSFORM_ID_NULL;
ttt->no_encryption = 1;
ttt->deinit = transop_deinit_null;
ttt->addspec = transop_addspec_null;
ttt->tick = transop_tick_null;
ttt->fwd = transop_encode_null;
ttt->rev = transop_decode_null;
return(0);
}

345
transform_tf.c

@ -28,70 +28,23 @@
#define N2N_TWOFISH_TRANSFORM_VERSION 1 /* version of the transform encoding */
struct sa_twofish
{
n2n_cipherspec_t spec; /* cipher spec parameters */
n2n_sa_t sa_id; /* security association index */
TWOFISH * enc_tf; /* tx state */
TWOFISH * dec_tf; /* rx state */
};
typedef struct sa_twofish sa_twofish_t;
/** Twofish transform state data.
*
* With a key-schedule in place this will be populated with a number of
* SAs. Each SA has a lifetime and some opque data. The opaque data for twofish
* consists of the SA number and key material.
*
*/
struct transop_tf
{
ssize_t tx_sa;
size_t num_sa;
sa_twofish_t sa[N2N_TWOFISH_NUM_SA];
};
typedef struct transop_tf transop_tf_t;
static int transop_deinit_twofish( n2n_trans_op_t * arg )
{
transop_tf_t * priv = (transop_tf_t *)arg->priv;
size_t i;
if ( priv )
{
/* Memory was previously allocated */
for (i=0; i<N2N_TWOFISH_NUM_SA; ++i )
{
sa_twofish_t * sa = &(priv->sa[i]);
TwoFishDestroy(sa->enc_tf); /* deallocate TWOFISH */
sa->enc_tf=NULL;
TwoFishDestroy(sa->dec_tf); /* deallocate TWOFISH */
sa->dec_tf=NULL;
sa->sa_id=0;
}
typedef struct transop_tf {
TWOFISH* enc_tf; /* tx state */
TWOFISH* dec_tf; /* rx state */
} transop_tf_t;
priv->num_sa=0;
priv->tx_sa=-1;
static int transop_deinit_twofish( 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);
}
arg->priv=NULL; /* return to fully uninitialised state */
return 0;
}
static size_t tf_choose_tx_sa( transop_tf_t * priv )
{
return priv->tx_sa; /* set in tick */
}
#define TRANSOP_TF_VER_SIZE 1 /* Support minor variants in encoding in one module. */
#define TRANSOP_TF_NONCE_SIZE 4
#define TRANSOP_TF_SA_SIZE 4
@ -122,21 +75,15 @@ static int transop_encode_twofish( n2n_trans_op_t * arg,
if ( (in_len + TRANSOP_TF_NONCE_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_VER_SIZE) <= out_len )
{
size_t idx=0;
sa_twofish_t * sa;
size_t tx_sa_num = 0;
/* The transmit sa is periodically updated */
tx_sa_num = tf_choose_tx_sa( priv );
uint32_t sa_id=0; // Not used
sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
traceEvent( TRACE_DEBUG, "encode_twofish %lu with SA %lu.", in_len, sa->sa_id );
traceEvent(TRACE_DEBUG, "encode_twofish %lu", in_len);
/* Encode the twofish format version. */
encode_uint8( outbuf, &idx, N2N_TWOFISH_TRANSFORM_VERSION );
/* Encode the security association (SA) number */
encode_uint32( outbuf, &idx, sa->sa_id );
encode_uint32( outbuf, &idx, sa_id );
/* The assembly buffer is a source for encrypting data. The nonce is
* written in first followed by the packet payload. The whole
@ -149,7 +96,7 @@ static int transop_encode_twofish( n2n_trans_op_t * arg,
len = TwoFishEncryptRaw( assembly, /* source */
outbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE,
in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */
sa->enc_tf);
priv->enc_tf);
if ( len > 0 )
{
len += TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE; /* size of data carried in UDP. */
@ -173,30 +120,6 @@ static int transop_encode_twofish( n2n_trans_op_t * arg,
return len;
}
/* Search through the array of SAs to find the one with the required ID.
*
* @return array index where found or -1 if not found
*/
static ssize_t twofish_find_sa( const transop_tf_t * priv, const n2n_sa_t req_id )
{
size_t i;
for (i=0; i < priv->num_sa; ++i)
{
const sa_twofish_t * sa=NULL;
sa = &(priv->sa[i]);
if (req_id == sa->sa_id)
{
return i;
}
}
return -1;
}
/** The twofish packet format consists of:
*
* - a 8-bit twofish encoding version in clear text
@ -219,249 +142,77 @@ static int transop_decode_twofish( n2n_trans_op_t * arg,
if ( ( (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */
&& (in_len >= (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_NONCE_SIZE) ) /* Has at least version, SA and nonce */
)
{
n2n_sa_t sa_rx;
ssize_t sa_idx=-1;
) {
size_t rem=in_len;
size_t idx=0;
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 )
{
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 );
sa_idx = twofish_find_sa(priv, sa_rx);
if ( sa_idx >= 0 )
{
sa_twofish_t * sa = &(priv->sa[sa_idx]);
traceEvent( TRACE_DEBUG, "decode_twofish %lu with SA %lu.", in_len, sa_rx, sa->sa_id );
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)),
sa->dec_tf);
priv->dec_tf);
if ( len > 0 )
{
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
{
/* Wrong security association; drop the packet as it is undecodable. */
traceEvent( TRACE_ERROR, "decode_twofish SA number %lu not found.", sa_rx );
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
}
}
else
{
/* Wrong security association; drop the packet as it is undecodable. */
} else
traceEvent(TRACE_ERROR, "decode_twofish decryption failed");
} else
traceEvent( TRACE_ERROR, "decode_twofish unsupported twofish version %u.", tf_enc_ver );
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
}
}
else
{
} else
traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len );
}
return len;
}
static int transop_addspec_twofish( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
{
int retval = 1;
ssize_t pstat=-1;
transop_tf_t * priv = (transop_tf_t *)arg->priv;
uint8_t keybuf[N2N_MAX_KEYSIZE];
if ( priv->num_sa < N2N_TWOFISH_NUM_SA )
{
const char * op = (const char *)cspec->opaque;
#ifdef __ANDROID_NDK__
const char *sep = strchr(op, '_');
#else
const char * sep = index( op, '_' );
#endif // __ANDROID_NDK__
if ( sep )
{
char tmp[256];
size_t s;
s = sep - op;
memcpy( tmp, cspec->opaque, s );
tmp[s]=0;
s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
priv->sa[priv->num_sa].spec = *cspec;
priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
if ( pstat > 0 )
{
priv->sa[priv->num_sa].enc_tf = TwoFishInit( keybuf, pstat);
priv->sa[priv->num_sa].dec_tf = TwoFishInit( keybuf, pstat);
traceEvent( TRACE_DEBUG, "transop_addspec_twofish sa_id=%u data=%s.\n",
priv->sa[priv->num_sa].sa_id, sep+1);
++(priv->num_sa);
retval = 0;
}
}
else
{
traceEvent( TRACE_ERROR, "transop_addspec_twofish : bad key data - missing '_'.\n");
}
}
else
{
traceEvent( TRACE_ERROR, "transop_addspec_twofish : full.\n");
}
return retval;
}
static n2n_tostat_t transop_tick_twofish( n2n_trans_op_t * arg, time_t now )
{
transop_tf_t * priv = (transop_tf_t *)arg->priv;
size_t i;
int found=0;
n2n_tostat_t r;
memset( &r, 0, sizeof(r) );
traceEvent( TRACE_DEBUG, "transop_tf tick num_sa=%u", priv->num_sa );
for ( i=0; i < priv->num_sa; ++i )
{
if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
{
time_t remaining = priv->sa[i].spec.valid_until - now;
static void transop_tick_twofish( n2n_trans_op_t * arg, time_t now ) {}
traceEvent( TRACE_INFO, "transop_tf choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
priv->tx_sa=i;
found=1;
break;
}
else
{
traceEvent( TRACE_DEBUG, "transop_tf tick rejecting sa=%u %lu -> %lu",
priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
}
}
if ( 0==found)
{
traceEvent( TRACE_INFO, "transop_tf no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
}
else
{
r.can_tx = 1;
r.tx_spec.t = N2N_TRANSFORM_ID_TWOFISH;
r.tx_spec = priv->sa[priv->tx_sa].spec;
}
return r;
}
int transop_twofish_setup_psk( n2n_trans_op_t * ttt,
n2n_sa_t sa_num,
uint8_t * encrypt_pwd,
uint32_t encrypt_pwd_len )
{
int retval = 1;
transop_tf_t * priv = (transop_tf_t *)ttt->priv;
if(priv) {
sa_twofish_t *sa;
priv->num_sa=1; /* There is one SA in the array. */
priv->tx_sa=0;
sa = &(priv->sa[priv->tx_sa]);
sa->sa_id=sa_num;
sa->spec.valid_until = 0x7fffffff;
/* This is a preshared key setup. Both Tx and Rx are using the same security association. */
sa->enc_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
sa->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
if ( (sa->enc_tf) && (sa->dec_tf) )
retval = 0;
else
traceEvent( TRACE_ERROR, "transop_twofish_setup_psk" );
} else
traceEvent( TRACE_ERROR, "twofish priv is not allocated" );
return retval;
}
int transop_twofish_init( n2n_trans_op_t * ttt )
{
int retval = 1;
transop_tf_t * priv = NULL;
if ( ttt->priv )
{
transop_deinit_twofish( ttt );
}
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) );
if ( NULL != priv ) {
size_t i;
sa_twofish_t * sa=NULL;
/* install the private structure. */
ttt->priv = priv;
priv->num_sa=0;
priv->tx_sa=0; /* We will use this sa index for encoding. */
/* 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->addspec = transop_addspec_twofish;
ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */
ttt->tick = transop_tick_twofish;
ttt->deinit = transop_deinit_twofish;
ttt->fwd = transop_encode_twofish;
ttt->rev = transop_decode_twofish;
for(i=0; i<N2N_TWOFISH_NUM_SA; ++i)
{
sa = &(priv->sa[i]);
sa->sa_id=0;
memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
sa->enc_tf=NULL;
sa->dec_tf=NULL;
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 association. */
priv->enc_tf = TwoFishInit(encrypt_key, encrypt_key_len);
priv->dec_tf = TwoFishInit(encrypt_key, encrypt_key_len);
retval = 0;
} else {
memset( ttt, 0, sizeof(n2n_trans_op_t) );
traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" );
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 retval;
return(0);
}

Loading…
Cancel
Save