mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
added Speck
This commit is contained in:
parent
12aea29abf
commit
0477e476e8
|
@ -48,9 +48,9 @@ MAN7DIR=$(MANDIR)/man7
|
|||
MAN8DIR=$(MANDIR)/man8
|
||||
|
||||
N2N_LIB=libn2n.a
|
||||
N2N_OBJS=n2n.o wire.o minilzo.o twofish.o \
|
||||
N2N_OBJS=n2n.o wire.o minilzo.o twofish.o speck.o \
|
||||
edge_utils.o sn_utils.o \
|
||||
transform_null.o transform_tf.o transform_aes.o transform_cc20.o \
|
||||
transform_null.o transform_tf.o transform_aes.o transform_cc20.o transform_speck.o \
|
||||
tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o \
|
||||
tuntap_osx.o
|
||||
LIBS_EDGE+=$(LIBS_EDGE_OPT)
|
||||
|
|
6
edge.c
6
edge.c
|
@ -179,6 +179,7 @@ static void help() {
|
|||
#endif
|
||||
#ifdef HAVE_OPENSSL_1_1
|
||||
printf("-A4 | Use ChaCha20 for payload encryption. Requires a key.\n");
|
||||
printf("-A5 | Use Speck for payload encryption. Requires a key.\n");
|
||||
#endif
|
||||
printf("-E | Accept multicast MAC addresses (default=drop).\n");
|
||||
printf("-S | Do not connect P2P. Always use the supernode.\n");
|
||||
|
@ -324,6 +325,11 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
case 5:
|
||||
{
|
||||
conf->transop_id = N2N_TRANSFORM_ID_SPECK;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
conf->transop_id = N2N_TRANSFORM_ID_INVAL;
|
||||
|
|
|
@ -139,6 +139,7 @@ const char* transop_str(enum n2n_transform tr) {
|
|||
case N2N_TRANSFORM_ID_TWOFISH: return("twofish");
|
||||
case N2N_TRANSFORM_ID_AESCBC: return("AES-CBC");
|
||||
case N2N_TRANSFORM_ID_CHACHA20:return("ChaCha20");
|
||||
case N2N_TRANSFORM_ID_SPECK :return("Speck");
|
||||
default: return("invalid");
|
||||
};
|
||||
}
|
||||
|
@ -247,6 +248,10 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
|
|||
rc = n2n_transop_cc20_init(&eee->conf, &eee->transop);
|
||||
break;
|
||||
#endif
|
||||
case N2N_TRANSFORM_ID_SPECK:
|
||||
rc = n2n_transop_speck_init(&eee->conf, &eee->transop);
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = n2n_transop_null_init(&eee->conf, &eee->transop);
|
||||
}
|
||||
|
|
1
n2n.h
1
n2n.h
|
@ -296,6 +296,7 @@ int n2n_transop_aes_cbc_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
|
|||
#ifdef HAVE_OPENSSL_1_1
|
||||
int n2n_transop_cc20_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
|
||||
#endif
|
||||
int n2n_transop_speck_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt);
|
||||
|
||||
/* Log */
|
||||
void setTraceLevel(int level);
|
||||
|
|
|
@ -31,6 +31,7 @@ typedef enum n2n_transform {
|
|||
N2N_TRANSFORM_ID_TWOFISH = 2,
|
||||
N2N_TRANSFORM_ID_AESCBC = 3,
|
||||
N2N_TRANSFORM_ID_CHACHA20 = 4,
|
||||
N2N_TRANSFORM_ID_SPECK = 5,
|
||||
} n2n_transform_t;
|
||||
|
||||
struct n2n_trans_op;
|
||||
|
|
149
speck.c
Normal file
149
speck.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
// cipher SPECK -- 128 bit block size -- 256 bit key size
|
||||
// taken from (and modified: removed pure crypto-stream generation and seperated key expansion)
|
||||
// https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/ref/stream.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// #define u64 unsigned long long
|
||||
#define u64 uint64_t
|
||||
|
||||
#define ROR64(x,r) (((x)>>(r))|((x)<<(64-(r))))
|
||||
#define ROL64(x,r) (((x)<<(r))|((x)>>(64-(r))))
|
||||
#define R(x,y,k) (x=ROR64(x,8), x+=y, x^=k, y=ROL64(y,3), y^=x)
|
||||
#define RI(x,y,k) (y^=x, y=ROR64(y,3), x^=k, x-=y, x=ROL64(x,8))
|
||||
|
||||
|
||||
static int speck_encrypt(u64 *u, u64 *v, u64 key[]) {
|
||||
|
||||
u64 i, x = *u, y = *v;
|
||||
|
||||
for (i = 0; i < 34; i++)
|
||||
R (x, y, key[i]);
|
||||
|
||||
*u = x; *v = y;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// not neccessary for CTR mode
|
||||
/* static int speck_decrypt(u64 *u, u64 *v, u64 key[]) {
|
||||
|
||||
int i;
|
||||
u64 x=*u,y=*v;
|
||||
for (i = 33; i >= 0 ;i--)
|
||||
RI (x, y, key[i]);
|
||||
|
||||
*u = x; *v = y;
|
||||
|
||||
return 0;
|
||||
} */
|
||||
|
||||
|
||||
int speck_ctr (unsigned char *out, const unsigned char *in,
|
||||
unsigned long long inlen,
|
||||
const unsigned char *n,
|
||||
u64 rk[]) {
|
||||
|
||||
u64 i, nonce[2], x, y, t;
|
||||
unsigned char *block = malloc (16);
|
||||
|
||||
if (!inlen) {
|
||||
free (block);
|
||||
return 0;
|
||||
}
|
||||
// !!! htole64 !!!
|
||||
nonce[0] = htole64 ( ((u64*)n)[0] );
|
||||
nonce[1] = htole64 ( ((u64*)n)[1] );
|
||||
|
||||
t=0;
|
||||
while(inlen >= 16) {
|
||||
x = nonce[1]; y = nonce[0]; nonce[0]++;
|
||||
speck_encrypt (&x, &y, rk);
|
||||
// !!! htole64 !!!
|
||||
((u64 *)out)[1+t] = htole64 (x ^ ((u64 *)in)[1+t]);
|
||||
((u64 *)out)[0+t] = htole64 (y ^ ((u64 *)in)[0+t]);
|
||||
t += 2;
|
||||
inlen -= 16;
|
||||
}
|
||||
if (inlen > 0) {
|
||||
x = nonce[1]; y = nonce[0];
|
||||
speck_encrypt (&x, &y, rk);
|
||||
// !!! htole64 !!!
|
||||
((u64 *)block)[1] = htole64 (x); ((u64 *)block)[0] = htole64 (y);
|
||||
for (i=0; i < inlen; i++)
|
||||
out[i + 8*t] = block[i] ^ in[i + 8*t];
|
||||
}
|
||||
|
||||
free (block);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int speck_expand_key (const unsigned char *k, u64 rk[]) {
|
||||
|
||||
u64 K[4];
|
||||
u64 i;
|
||||
|
||||
for (i=0; i < 4; i++)
|
||||
// !!! htole64 !!!
|
||||
K[i] = htole64 ( ((u64 *)k)[i] );
|
||||
|
||||
|
||||
u64 D = K[3], C = K[2], B = K[1], A = K[0];
|
||||
|
||||
for (i = 0; i < 33; i += 3) {
|
||||
rk[i ] = A; R (B, A, i );
|
||||
rk[i+1] = A; R (C, A, i + 1);
|
||||
rk[i+2] = A; R (D, A, i + 2);
|
||||
}
|
||||
rk[33] = A;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int speck_test () {
|
||||
|
||||
uint8_t key[32] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
|
||||
|
||||
|
||||
uint8_t iv[16] = { 0x70, 0x6f, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x20,
|
||||
0x49, 0x6e, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65 };
|
||||
|
||||
uint8_t pt[16] = { 0x00 };
|
||||
|
||||
// expected outcome (according to pp. 35 & 36 of Implementation Guide)
|
||||
uint8_t ct[16] = { 0x43, 0x8f, 0x18, 0x9c, 0x8d, 0xb4, 0xee, 0x4e,
|
||||
0x3e, 0xf5, 0xc0, 0x05, 0x04, 0x01, 0x09, 0x41 };
|
||||
|
||||
u64 round_keys[34];
|
||||
speck_expand_key (key, round_keys);
|
||||
|
||||
speck_ctr (pt, pt, 16, iv, round_keys);
|
||||
|
||||
fprintf (stderr, "rk00: %016lx\n", round_keys[0]);
|
||||
fprintf (stderr, "rk33: %016lx\n", round_keys[33]);
|
||||
fprintf (stderr, "out : %016lx\n", *(uint64_t*)pt);
|
||||
fprintf (stderr, "mem : " ); for (int i=0; i < 16; i++) fprintf (stderr, "%02x ", pt[i]); fprintf (stderr, "\n");
|
||||
|
||||
int ret = 1;
|
||||
for (int i=0; i < 16; i++)
|
||||
if (pt[i] != ct[i]) ret = 0;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
int main (int argc, char* argv[]) {
|
||||
|
||||
fprintf (stdout, "SPECK SELF TEST RESULT: %u\n", speck_test (0,NULL));
|
||||
}
|
||||
*/
|
||||
|
9
speck.h
Normal file
9
speck.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
#define u64 uint64_t
|
||||
|
||||
int speck_ctr (unsigned char *out, const unsigned char *in,
|
||||
unsigned long long inlen,
|
||||
const unsigned char *n,
|
||||
u64 rk[]);
|
||||
|
||||
int speck_expand_key (const unsigned char *k, u64 rk[]);
|
|
@ -100,6 +100,7 @@ int main(int argc, char * argv[]) {
|
|||
#ifdef HAVE_OPENSSL_1_1
|
||||
n2n_trans_op_t transop_cc20;
|
||||
#endif
|
||||
n2n_trans_op_t transop_speck;
|
||||
n2n_edge_conf_t conf;
|
||||
|
||||
parseArgs(argc, argv);
|
||||
|
@ -118,6 +119,7 @@ int main(int argc, char * argv[]) {
|
|||
#ifdef HAVE_OPENSSL_1_1
|
||||
n2n_transop_cc20_init(&conf, &transop_cc20);
|
||||
#endif
|
||||
n2n_transop_speck_init(&conf, &transop_speck);
|
||||
|
||||
/* Run the tests */
|
||||
run_transop_benchmark("transop_null", &transop_null, &conf, pktbuf);
|
||||
|
@ -128,6 +130,7 @@ int main(int argc, char * argv[]) {
|
|||
#ifdef N2N_HAVE_AES
|
||||
run_transop_benchmark("transop_cc20", &transop_cc20, &conf, pktbuf);
|
||||
#endif
|
||||
run_transop_benchmark("transop_speck", &transop_speck, &conf, pktbuf);
|
||||
|
||||
/* Cleanup */
|
||||
transop_null.deinit(&transop_null);
|
||||
|
@ -138,6 +141,7 @@ int main(int argc, char * argv[]) {
|
|||
#ifdef HAVE_OPENSSL_1_1
|
||||
transop_cc20.deinit(&transop_cc20);
|
||||
#endif
|
||||
transop_speck.deinit(&transop_speck);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
212
transform_speck.c
Normal file
212
transform_speck.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
/**
|
||||
* (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/>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "n2n.h"
|
||||
#include "n2n_transforms.h"
|
||||
#include "speck.h"
|
||||
|
||||
#define N2N_SPECK_TRANSFORM_VERSION 1 /* version of the transform encoding */
|
||||
#define N2N_SPECK_IVEC_SIZE 16
|
||||
|
||||
#define SPECK_KEY_BYTES (256/8)
|
||||
|
||||
/* Speck plaintext preamble */
|
||||
#define TRANSOP_SPECK_VER_SIZE 1 /* Support minor variants in encoding in one module. */
|
||||
#define TRANSOP_SPECK_PREAMBLE_SIZE (TRANSOP_SPECK_VER_SIZE + N2N_SPECK_IVEC_SIZE)
|
||||
|
||||
typedef unsigned char n2n_speck_ivec_t[N2N_SPECK_IVEC_SIZE];
|
||||
|
||||
typedef struct transop_speck {
|
||||
uint64_t rk[34]; /* the round keys for payload encryption & decryption */
|
||||
} transop_speck_t;
|
||||
|
||||
/* ****************************************************** */
|
||||
|
||||
static int transop_deinit_speck(n2n_trans_op_t *arg) {
|
||||
transop_speck_t *priv = (transop_speck_t *)arg->priv;
|
||||
|
||||
if(priv)
|
||||
free(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ****************************************************** */
|
||||
|
||||
static void set_speck_iv(transop_speck_t *priv, n2n_speck_ivec_t ivec) {
|
||||
// keep in mind the following condition: N2N_SPECK_IVEC_SIZE % sizeof(rand_value) == 0 !
|
||||
uint32_t rand_value;
|
||||
for (uint8_t i = 0; i < N2N_SPECK_IVEC_SIZE; i += sizeof(rand_value)) {
|
||||
rand_value = rand(); // CONCERN: rand() is not considered cryptographicly secure, REPLACE later
|
||||
memcpy(ivec + i, &rand_value, sizeof(rand_value));
|
||||
}
|
||||
}
|
||||
|
||||
/* ****************************************************** */
|
||||
|
||||
/** The Speck packet format consists of:
|
||||
*
|
||||
* - a 8-bit speck encoding version in clear text
|
||||
* - a 128-bit random IV
|
||||
* - encrypted payload.
|
||||
*
|
||||
* [V|IIII|DDDDDDDDDDDDDDDDDDDDD]
|
||||
* |<---- encrypted ---->|
|
||||
*/
|
||||
static int transop_encode_speck(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_speck_t * priv = (transop_speck_t *)arg->priv;
|
||||
|
||||
if(in_len <= N2N_PKT_BUF_SIZE) {
|
||||
if((in_len + TRANSOP_SPECK_PREAMBLE_SIZE) <= out_len) {
|
||||
size_t idx=0;
|
||||
n2n_speck_ivec_t enc_ivec = {0};
|
||||
|
||||
traceEvent(TRACE_DEBUG, "encode_speck %lu bytes", in_len);
|
||||
|
||||
/* Encode the Speck format version. */
|
||||
encode_uint8(outbuf, &idx, N2N_SPECK_TRANSFORM_VERSION);
|
||||
|
||||
/* Generate and encode the IV. */
|
||||
set_speck_iv(priv, enc_ivec);
|
||||
encode_buf(outbuf, &idx, &enc_ivec, N2N_SPECK_IVEC_SIZE);
|
||||
traceEvent(TRACE_DEBUG, "encode_speck iv=%016llx:%016llx",
|
||||
htobe64(*(uint64_t*)&enc_ivec[0]),
|
||||
htobe64(*(uint64_t*)&enc_ivec[8]) );
|
||||
|
||||
/* Encrypt the payload and write the ciphertext after the iv. */
|
||||
/* len is set to the length of the cipher plain text to be encrpyted
|
||||
which is (in this case) identical to original packet lentgh */
|
||||
len = in_len;
|
||||
|
||||
speck_ctr (outbuf + TRANSOP_SPECK_PREAMBLE_SIZE, inbuf, in_len, enc_ivec, priv->rk);
|
||||
traceEvent(TRACE_DEBUG, "encode_speck: encrypted %u bytes.\n", in_len);
|
||||
|
||||
len += TRANSOP_SPECK_PREAMBLE_SIZE; /* size of data carried in UDP. */
|
||||
} else
|
||||
traceEvent(TRACE_ERROR, "encode_speck outbuf too small.");
|
||||
} else
|
||||
traceEvent(TRACE_ERROR, "encode_speck inbuf too big to encrypt.");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ****************************************************** */
|
||||
|
||||
/* See transop_encode_speck for packet format */
|
||||
static int transop_decode_speck(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_speck_t * priv = (transop_speck_t *)arg->priv;
|
||||
|
||||
if(((in_len - TRANSOP_SPECK_PREAMBLE_SIZE) <= N2N_PKT_BUF_SIZE) /* Cipher text fits in buffer */
|
||||
&& (in_len >= TRANSOP_SPECK_PREAMBLE_SIZE) /* Has at least version, iv */
|
||||
)
|
||||
{
|
||||
size_t rem=in_len;
|
||||
size_t idx=0;
|
||||
uint8_t speck_enc_ver=0;
|
||||
n2n_speck_ivec_t dec_ivec = {0};
|
||||
|
||||
/* Get the encoding version to make sure it is supported */
|
||||
decode_uint8(&speck_enc_ver, inbuf, &rem, &idx );
|
||||
|
||||
if(N2N_SPECK_TRANSFORM_VERSION == speck_enc_ver) {
|
||||
traceEvent(TRACE_DEBUG, "decode_speck %lu bytes", in_len);
|
||||
len = (in_len - TRANSOP_SPECK_PREAMBLE_SIZE);
|
||||
|
||||
/* Get the IV */
|
||||
decode_buf((uint8_t *)&dec_ivec, N2N_SPECK_IVEC_SIZE, inbuf, &rem, &idx);
|
||||
traceEvent(TRACE_DEBUG, "decode_speck iv=%016llx:%016llx",
|
||||
htobe64(*(uint64_t*)&dec_ivec[0]),
|
||||
htobe64(*(uint64_t*)&dec_ivec[8]) );
|
||||
|
||||
speck_ctr (outbuf, inbuf + TRANSOP_SPECK_PREAMBLE_SIZE, len, dec_ivec, priv->rk);
|
||||
traceEvent(TRACE_DEBUG, "decode_speck: decrypted %u bytes.\n", len);
|
||||
|
||||
} else
|
||||
traceEvent(TRACE_ERROR, "decode_speck unsupported Speck version %u.", speck_enc_ver);
|
||||
} else
|
||||
traceEvent(TRACE_ERROR, "decode_speck inbuf wrong size (%ul) to decrypt.", in_len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ****************************************************** */
|
||||
|
||||
static int setup_speck_key(transop_speck_t *priv, const uint8_t *key, ssize_t key_size) {
|
||||
|
||||
uint8_t key_mat_buf[32] = { 0x00 };
|
||||
|
||||
/* Clear out any old possibly longer key matter. */
|
||||
memset(&(priv->rk), 0, sizeof(priv->rk) );
|
||||
|
||||
/* TODO: The input key always gets hashed to make a more unpredictable and more complete use of the key space */
|
||||
// REVISIT: Hash the key to keymat (formerly used: SHA)
|
||||
// SHA256(key, key_size, key_mat_buf)
|
||||
// memcpy (priv->key, key_mat_buf, SHA256_DIGEST_LENGTH);
|
||||
// ADD: Pearson Hashing
|
||||
// FOR NOW: USE KEY ITSELF
|
||||
memcpy (key_mat_buf, key, ((key_size>32)?32:key_size) );
|
||||
|
||||
speck_expand_key (key_mat_buf, priv->rk);
|
||||
traceEvent(TRACE_DEBUG, "Speck key setup completed\n");
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* ****************************************************** */
|
||||
|
||||
static void transop_tick_speck(n2n_trans_op_t * arg, time_t now) { ; }
|
||||
|
||||
/* ****************************************************** */
|
||||
|
||||
/* Speck initialization function */
|
||||
int n2n_transop_speck_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
|
||||
transop_speck_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_SPECK;
|
||||
|
||||
ttt->tick = transop_tick_speck;
|
||||
ttt->deinit = transop_deinit_speck;
|
||||
ttt->fwd = transop_encode_speck;
|
||||
ttt->rev = transop_decode_speck;
|
||||
|
||||
priv = (transop_speck_t*) calloc(1, sizeof(transop_speck_t));
|
||||
if(!priv) {
|
||||
traceEvent(TRACE_ERROR, "cannot allocate transop_speck_t memory");
|
||||
return(-1);
|
||||
}
|
||||
ttt->priv = priv;
|
||||
|
||||
/* Setup the cipher and key */
|
||||
return(setup_speck_key(priv, encrypt_key, encrypt_key_len));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user