Permalink
Browse files

Add -A option to enable AES CBC psk encryption

  • Loading branch information...
emanuele-f committed Jan 27, 2019
1 parent 63e74cc commit e4601590aa4199c2374123c5e9d04fabb9a62f9c
Showing with 160 additions and 107 deletions.
  1. +15 −4 edge.c
  2. +48 −17 edge_utils.c
  3. +4 −1 n2n.h
  4. +6 −1 n2n_transforms.h
  5. +69 −27 transform_aes.c
  6. +18 −57 transform_tf.c
19 edge.c
@@ -136,7 +136,7 @@ static void help() {
"-l <supernode host:port>\n"
" "
"[-p <local port>] [-M <mtu>] "
"[-r] [-E] [-v] [-t <mgmt port>] [-b] [-h]\n\n");
"[-r] [-E] [-v] [-t <mgmt port>] [-b] [-A] [-h]\n\n");

#ifdef __linux__
printf("-d <tun device> | tun device name\n");
@@ -162,6 +162,7 @@ static void help() {
" | eg. -m 01:02:03:04:05:06\n");
printf("-M <mtu> | Specify n2n MTU of edge interface (default %d).\n", DEFAULT_MTU);
printf("-r | Enable packet forwarding through n2n community.\n");
printf("-A | Set AES CBC as the preferred encryption mode.\n");
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");
@@ -268,6 +269,12 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
break;
}

case 'A':
{
eee->preferred_aes = 1;
break;
}

case 'l': /* supernode-list */
if(optargument) {
if(eee->sn_num < N2N_EDGE_NUM_SUPERNODES) {
@@ -357,7 +364,7 @@ static int loadFromCLI(int argc, char *argv[], edge_conf_t *ec, n2n_edge_t *eee)
u_char c;

while((c = getopt_long(argc, argv,
"K:k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:",
"K:k:a:bc:Eu:g:m:M:s:d:l:p:fvhrAt:",
long_options, NULL)) != '?') {
if(c == 255) break;
setOption(c, optarg, ec, eee);
@@ -665,8 +672,12 @@ int main(int argc, char* argv[]) {
traceEvent(TRACE_NORMAL, "Binding to local port %d", (signed int)ec.local_port);

if(ec.encrypt_key) {
if(edge_init_twofish(&eee, (uint8_t *)(ec.encrypt_key), strlen(ec.encrypt_key)) < 0) {
fprintf(stderr, "Error: twofish setup failed.\n");
if(edge_init_aes_psk(&eee, (uint8_t *)(ec.encrypt_key), strlen(ec.encrypt_key)) < 0) {
fprintf(stderr, "Error: AES PSK setup failed.\n");
return(-1);
}
if(edge_init_twofish_psk(&eee, (uint8_t *)(ec.encrypt_key), strlen(ec.encrypt_key)) < 0) {
fprintf(stderr, "Error: twofish PSK setup failed.\n");
return(-1);
}
} else if(strlen(eee.keyschedule) > 0) {
@@ -75,6 +75,7 @@ int edge_init(n2n_edge_t * eee) {
eee->tx_transop_idx = N2N_TRANSOP_NULL_IDX; /* No guarantee the others have been setup */

eee->daemon = 1; /* By default run in daemon mode. */
eee->preferred_aes = 0; /* Disable AES by default (for compatibility) */
eee->re_resolve_supernode_ip = 0;
/* keyschedule set to NULLs by memset */
/* community_name set to NULLs by memset */
@@ -644,38 +645,66 @@ const char * supernode_ip(const n2n_edge_t * eee) {

/* ************************************** */

int edge_init_twofish(n2n_edge_t * eee, uint8_t *encrypt_pwd,
int edge_init_twofish_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
uint32_t encrypt_pwd_len) {
return transop_twofish_setup(&(eee->transop[N2N_TRANSOP_TF_IDX]),
return transop_twofish_setup_psk(&(eee->transop[N2N_TRANSOP_TF_IDX]),
0, encrypt_pwd, encrypt_pwd_len);
}

/* ************************************** */

/** Called periodically to roll keys and do any periodic maintenance in the
* tranform operations state machines. */
static int n2n_tick_transop(n2n_edge_t * eee, time_t now)
{
n2n_tostat_t tst;
size_t trop = eee->tx_transop_idx;
int edge_init_aes_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
uint32_t encrypt_pwd_len) {
return transop_aes_setup_psk(&(eee->transop[N2N_TRANSOP_AESCBC_IDX]),
0, encrypt_pwd, encrypt_pwd_len);
}

/* ************************************** */

static n2n_tostat_t n2n_tick_aes(n2n_edge_t * eee, time_t now, size_t *trop) {
n2n_tostat_t tst = (eee->transop[N2N_TRANSOP_AESCBC_IDX].tick)(&(eee->transop[N2N_TRANSOP_AESCBC_IDX]), now);

/* Tests are done in order that most preferred transform is last and causes
* tx_transop_idx to be left at most preferred valid transform. */
tst = (eee->transop[N2N_TRANSOP_NULL_IDX].tick)(&(eee->transop[N2N_TRANSOP_NULL_IDX]), now);
tst = (eee->transop[N2N_TRANSOP_AESCBC_IDX].tick)(&(eee->transop[N2N_TRANSOP_AESCBC_IDX]), now);
if(tst.can_tx)
{
traceEvent(TRACE_DEBUG, "can_tx AESCBC (idx=%u)", (unsigned int)N2N_TRANSOP_AESCBC_IDX);
trop = N2N_TRANSOP_AESCBC_IDX;
*trop = N2N_TRANSOP_AESCBC_IDX;
}

tst = (eee->transop[N2N_TRANSOP_TF_IDX].tick)(&(eee->transop[N2N_TRANSOP_TF_IDX]), now);
return tst;
}

/* ************************************** */
static n2n_tostat_t n2n_tick_twofish(n2n_edge_t * eee, time_t now, size_t *trop) {
n2n_tostat_t tst = (eee->transop[N2N_TRANSOP_TF_IDX].tick)(&(eee->transop[N2N_TRANSOP_TF_IDX]), now);
if(tst.can_tx)
{
traceEvent(TRACE_DEBUG, "can_tx TF (idx=%u)", (unsigned int)N2N_TRANSOP_TF_IDX);
trop = N2N_TRANSOP_TF_IDX;
*trop = N2N_TRANSOP_TF_IDX;
}

return tst;
}

/* ************************************** */

/** Called periodically to roll keys and do any periodic maintenance in the
* tranform operations state machines. */
static int n2n_tick_transop(n2n_edge_t * eee, time_t now)
{
size_t trop = eee->tx_transop_idx;

/* Tests are done in order that most preferred transform is last and causes
* tx_transop_idx to be left at most preferred valid transform. */
(eee->transop[N2N_TRANSOP_NULL_IDX].tick)(&(eee->transop[N2N_TRANSOP_NULL_IDX]), now);

if(eee->preferred_aes) {
n2n_tick_twofish(eee, now, &trop);
n2n_tick_aes(eee, now, &trop);
} else {
n2n_tick_aes(eee, now, &trop);
n2n_tick_twofish(eee, now, &trop);
}

if(trop != eee->tx_transop_idx)
{
eee->tx_transop_idx = trop;
@@ -1688,8 +1717,10 @@ int quick_edge_init(char *device_name, char *community_name,
device_mac, DEFAULT_MTU) < 0)
return(-1);

if(edge_init_twofish(&eee, (uint8_t *)encrypt_key, strlen(encrypt_key)) < 0)
return(-2);
if(edge_init_aes_psk(&eee, (uint8_t *)encrypt_key, strlen(encrypt_key)) < 0)
return(-2);
if(edge_init_twofish_psk(&eee, (uint8_t *)encrypt_key, strlen(encrypt_key)) < 0)
return(-2);

snprintf((char*)eee.community_name, sizeof(eee.community_name), "%s", community_name);
supernode2addr(&(eee.supernode), supernode_ip_address_port);
5 n2n.h
@@ -186,6 +186,7 @@ typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];

struct n2n_edge {
int daemon; /**< Non-zero if edge should detach and run in the background. */
int preferred_aes; /**< Non-zero if AES is the preferred encryption meothd. */
uint8_t re_resolve_supernode_ip;

n2n_sock_t supernode;
@@ -337,7 +338,9 @@ void set_peer_operational(n2n_edge_t * eee,
const n2n_mac_t mac,
const n2n_sock_t * peer);
const char * supernode_ip(const n2n_edge_t * eee);
int edge_init_twofish(n2n_edge_t * eee, uint8_t *encrypt_pwd,
int edge_init_twofish_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
uint32_t encrypt_pwd_len);
int edge_init_aes_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
uint32_t encrypt_pwd_len);
int run_edge_loop(n2n_edge_t * eee, int *keep_running);
void edge_term(n2n_edge_t * eee);
@@ -78,7 +78,12 @@ struct n2n_trans_op {
};

/* Setup a single twofish SA for single-key operation. */
int transop_twofish_setup( n2n_trans_op_t * ttt,
int transop_twofish_setup_psk( n2n_trans_op_t * ttt,
n2n_sa_t sa_num,
uint8_t * encrypt_pwd,
uint32_t encrypt_pwd_len );
/* Setup a single AES SA for single-key operation. */
int transop_aes_setup_psk( n2n_trans_op_t * ttt,
n2n_sa_t sa_num,
uint8_t * encrypt_pwd,
uint32_t encrypt_pwd_len );
@@ -339,6 +339,41 @@ static int transop_decode_aes( n2n_trans_op_t * arg,
return len;
}

/*
* 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) {
/* pstat is number of bytes read into keybuf. */
sa_aes_t * sa = &(priv->sa[priv->num_sa]);
size_t aes_keysize_bytes;
size_t aes_keysize_bits;

/* Clear out any old possibly longer key matter. */
memset( &(sa->enc_key), 0, sizeof(AES_KEY) );
memset( &(sa->dec_key), 0, sizeof(AES_KEY) );

memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );

aes_keysize_bytes = aes_best_keysize(pstat);
aes_keysize_bits = 8 * aes_keysize_bytes;

/* Use N2N_MAX_KEYSIZE because the AES key needs to be of fixed
* size. If fewer bits specified then the rest will be
* zeroes. AES acceptable key sizes are 128, 192 and 256
* bits. */
AES_set_encrypt_key( keybuf, aes_keysize_bits, &(sa->enc_key));
AES_set_decrypt_key( keybuf, aes_keysize_bits, &(sa->dec_key));
/* Leave ivecs set to all zeroes */

traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits data=%s.\n",
priv->sa[priv->num_sa].sa_id, aes_keysize_bits, keybuf);

++(priv->num_sa);
}

static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
{
int retval = 1;
@@ -369,33 +404,7 @@ static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * c
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
if ( pstat > 0 )
{
/* pstat is number of bytes read into keybuf. */
sa_aes_t * sa = &(priv->sa[priv->num_sa]);
size_t aes_keysize_bytes;
size_t aes_keysize_bits;

/* Clear out any old possibly longer key matter. */
memset( &(sa->enc_key), 0, sizeof(AES_KEY) );
memset( &(sa->dec_key), 0, sizeof(AES_KEY) );

memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );

aes_keysize_bytes = aes_best_keysize(pstat);
aes_keysize_bits = 8 * aes_keysize_bytes;

/* Use N2N_MAX_KEYSIZE because the AES key needs to be of fixed
* size. If fewer bits specified then the rest will be
* zeroes. AES acceptable key sizes are 128, 192 and 256
* bits. */
AES_set_encrypt_key( keybuf, aes_keysize_bits, &(sa->enc_key));
AES_set_decrypt_key( keybuf, aes_keysize_bits, &(sa->dec_key));
/* Leave ivecs set to all zeroes */

traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits data=%s.\n",
priv->sa[priv->num_sa].sa_id, aes_keysize_bits, sep+1);

++(priv->num_sa);
add_aes_key(priv, keybuf, pstat);
retval = 0;
}
}
@@ -510,6 +519,31 @@ int transop_aes_init( n2n_trans_op_t * ttt )
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) {
sa_aes_t *sa;
priv->num_sa=0;
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. */
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
@@ -606,5 +640,13 @@ int transop_aes_init( n2n_trans_op_t * ttt )
return retval;
}


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

#endif /* #if defined(N2N_HAVE_AES) */

Oops, something went wrong.

0 comments on commit e460159

Please sign in to comment.