Browse Source

added Speck

pull/249/head
Logan007 5 years ago
parent
commit
0477e476e8
  1. 4
      Makefile.in
  2. 6
      edge.c
  3. 5
      edge_utils.c
  4. 1
      n2n.h
  5. 1
      n2n_transforms.h
  6. 149
      speck.c
  7. 9
      speck.h
  8. 4
      tools/benchmark.c
  9. 212
      transform_speck.c

4
Makefile.in

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

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

5
edge_utils.c

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

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

1
n2n_transforms.h

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

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

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

4
tools/benchmark.c

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

@ -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…
Cancel
Save