Add -A option to enable AES CBC psk encryption

This commit is contained in:
emanuele-f 2019-01-28 00:27:54 +01:00
parent 63e74ccc6a
commit e4601590aa
6 changed files with 161 additions and 108 deletions

19
edge.c
View File

@ -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) {

View File

@ -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,36 +645,64 @@ 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);
}
/* ************************************** */
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);
if(tst.can_tx)
{
traceEvent(TRACE_DEBUG, "can_tx AESCBC (idx=%u)", (unsigned int)N2N_TRANSOP_AESCBC_IDX);
*trop = N2N_TRANSOP_AESCBC_IDX;
}
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;
}
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)
{
n2n_tostat_t tst;
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. */
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;
}
(eee->transop[N2N_TRANSOP_NULL_IDX].tick)(&(eee->transop[N2N_TRANSOP_NULL_IDX]), now);
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;
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)
@ -1688,7 +1717,9 @@ 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)
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);

5
n2n.h
View File

@ -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);

View File

@ -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 );

View File

@ -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) */

View File

@ -384,40 +384,16 @@ static n2n_tostat_t transop_tick_twofish( n2n_trans_op_t * arg, time_t now )
return r;
}
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 )
{
int retval = 1;
transop_tf_t * priv = NULL;
transop_tf_t * priv = (transop_tf_t *)ttt->priv;
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;
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;
}
if(priv) {
sa_twofish_t *sa;
priv->num_sa=1; /* There is one SA in the array. */
priv->tx_sa=0;
@ -431,26 +407,11 @@ int transop_twofish_setup( n2n_trans_op_t * ttt,
sa->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
if ( (sa->enc_tf) && (sa->dec_tf) )
{
ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
ttt->deinit = transop_deinit_twofish;
ttt->addspec = transop_addspec_twofish;
ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */
ttt->fwd = transop_encode_twofish;
ttt->rev = transop_decode_twofish;
retval = 0;
}
else
{
traceEvent( TRACE_ERROR, "TwoFishInit failed" );
}
}
else
{
memset( ttt, 0, sizeof(n2n_trans_op_t) );
traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" );
}
traceEvent( TRACE_ERROR, "transop_twofish_setup_psk" );
} else
traceEvent( TRACE_ERROR, "twofish priv is not allocated" );
return retval;
}