diff --git a/include/speck.h b/include/speck.h
index 4179e74..32727e6 100644
--- a/include/speck.h
+++ b/include/speck.h
@@ -1,3 +1,22 @@
+/**
+ * (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
+ *
+ */
+
+
// 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/
@@ -7,13 +26,20 @@
#define SPECK_H
#include
+#include
+#include "portable_endian.h"
+
#define u32 uint32_t
#define u64 uint64_t
+#define N2N_SPECK_IVEC_SIZE 16
+#define SPECK_KEY_BYTES (256/8)
+
+
#if defined (__AVX2__)
-#define SPECK_ALIGNED_CTX 32
#include
+#define SPECK_ALIGNED_CTX 32
#define u256 __m256i
typedef struct {
u256 rk[34];
@@ -22,9 +48,9 @@ typedef struct {
#elif defined (__SSE4_2__)
+#include
#define SPECK_ALIGNED_CTX 16
#define SPECK_CTX_BYVAL 1
-#include
#define u128 __m128i
typedef struct {
u128 rk[34];
@@ -48,33 +74,30 @@ typedef struct {
#endif
+// -----
int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen,
const unsigned char *n,
-#if defined (SPECK_CTX_BYVAL)
- speck_context_t ctx);
-#else
-speck_context_t *ctx);
-#endif
+ speck_context_t *ctx);
+int speck_init (const unsigned char *k, speck_context_t **ctx);
-int speck_expand_key (const unsigned char *k, speck_context_t *ctx);
+int speck_deinit (speck_context_t *ctx);
+// -----
int speck_he (unsigned char *out, const unsigned char *in, unsigned long long inlen,
const unsigned char *n, speck_context_t *ctx);
-
int speck_expand_key_he (const unsigned char *k, speck_context_t *ctx);
+// -----
int speck_he_iv_encrypt (unsigned char *inout, speck_context_t *ctx);
-
int speck_he_iv_decrypt (unsigned char *inout, speck_context_t *ctx);
-
int speck_expand_key_he_iv (const unsigned char *k, speck_context_t *ctx);
-#endif
+#endif // SPECK_H
diff --git a/src/speck.c b/src/speck.c
index 9ca7811..bfc39ee 100644
--- a/src/speck.c
+++ b/src/speck.c
@@ -1,9 +1,26 @@
+/**
+ * (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
+ *
+ */
+
+
// cipher SPECK -- 128 bit block size -- 256 bit key size -- CTR mode
// 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/
-#include
-#include "portable_endian.h"
#include "speck.h"
@@ -139,8 +156,8 @@ static int speck_encrypt_xor(unsigned char *out, const unsigned char *in, u64 no
}
-int speck_ctr( unsigned char *out, const unsigned char *in, unsigned long long inlen,
- const unsigned char *n, speck_context_t *ctx) {
+static int internal_speck_ctr(unsigned char *out, const unsigned char *in, unsigned long long inlen,
+ const unsigned char *n, speck_context_t *ctx) {
int i;
u64 nonce[2];
@@ -195,10 +212,11 @@ int speck_ctr( unsigned char *out, const unsigned char *in, unsigned long long i
}
-int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
+static int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
u64 K[4];
size_t i;
+
for (i = 0; i < numkeywords; i++)
K[i] = ((u64 *)k)[i];
@@ -281,6 +299,7 @@ int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
RK(C,A,k,key,28), RK(D,A,k,key,29), RK(B,A,k,key,30), RK(C,A,k,key,31), RK(D,A,k,key,32), RK(B,A,k,key,33))
+// attention: ctx is provided by value as it is faster in this case, astonishingly
static int speck_encrypt_xor (unsigned char *out, const unsigned char *in, u64 nonce[], const speck_context_t ctx, int numbytes) {
u64 x[2], y[2];
@@ -325,9 +344,9 @@ static int speck_encrypt_xor (unsigned char *out, const unsigned char *in, u64 n
return 0;
}
-
-int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen,
- const unsigned char *n, const speck_context_t ctx) {
+// attention: ctx is provided by value as it is faster in this case, astonishingly
+static int internal_speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen,
+ const unsigned char *n, const speck_context_t ctx) {
int i;
u64 nonce[2];
@@ -377,10 +396,11 @@ int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long i
}
-int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
+static int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
u64 K[4];
size_t i;
+
for (i = 0; i < numkeywords; i++)
K[i] = ((u64 *)k)[i];
@@ -497,8 +517,8 @@ static int speck_encrypt_xor (unsigned char *out, const unsigned char *in, u64 n
}
-int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen,
- const unsigned char *n, speck_context_t *ctx) {
+static int internal_speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen,
+ const unsigned char *n, speck_context_t *ctx) {
int i;
u64 nonce[2];
@@ -548,10 +568,11 @@ int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long i
}
-int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
+static int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
u64 K[4];
size_t i;
+
for (i = 0; i < numkeywords; i++)
K[i] = ((u64 *)k)[i];
@@ -582,8 +603,8 @@ static int speck_encrypt (u64 *u, u64 *v, speck_context_t *ctx) {
}
-int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen,
- const unsigned char *n, speck_context_t *ctx) {
+static int internal_speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen,
+ const unsigned char *n, speck_context_t *ctx) {
u64 i, nonce[2], x, y, t;
unsigned char *block = malloc (16);
@@ -617,7 +638,7 @@ int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long i
}
-int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
+static int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
u64 K[4];
u64 i;
@@ -638,12 +659,55 @@ int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
}
-#endif // AVX, SSE, NEON, plain C ------------------------------------------------
+#endif // AVX, SSE, NEON, plain C
+
+
+// this functions wraps the call to internal speck_ctr functions which have slightly different
+// signature -- ctx by value for SSE with SPECK_CTX_BYVAL defined in speck.h, by name otherwise
+inline int speck_ctr (unsigned char *out, const unsigned char *in, unsigned long long inlen,
+ const unsigned char *n, speck_context_t *ctx) {
+
+ return internal_speck_ctr (out, in, inlen, n,
+#if defined (SPECK_CTX_BYVAL)
+ *ctx);
+#else
+ ctx);
+#endif
+}
+
+
+int speck_init (const unsigned char *k, speck_context_t **ctx) {
+
+#if defined (SPECK_ALIGNED_CTX)
+ *ctx = (speck_context_t*) _mm_malloc (sizeof(speck_context_t), SPECK_ALIGNED_CTX);
+#else
+ *ctx = (speck_context_t*) calloc (1, sizeof(speck_context_t));
+#endif
+ if(!(*ctx)) {
+ return -1;
+ }
+
+ return speck_expand_key(k, *ctx);
+}
+
+
+int speck_deinit (speck_context_t *ctx) {
+
+#if defined (SPECK_ALIGNED_CTX)
+ _mm_free (ctx);
+#else
+ free (ctx);
+#endif
+ return 0;
+}
+
+
+// ----------------------------------------------------------------------------------------
// cipher SPECK -- 128 bit block size -- 128 bit key size -- CTR mode
// used for header encryption, thus the prefix 'he_'
-// for now: just plain C -- AVX, SSE, NEON might follow
+// for now: just plain C -- AVX, SSE, NEON do not make sense for short header
#define ROR64(x,r) (((x)>>(r))|((x)<<(64-(r))))
#define ROL64(x,r) (((x)<<(r))|((x)>>(64-(r))))
@@ -787,97 +851,3 @@ int speck_expand_key_he_iv (const unsigned char *k, speck_context_t *ctx) {
return 1;
}
-
-
-// ----------------------------------------------------------------------------------------
-
-/*
-// code for testing -- to be removed when finished
-#include // for testing
-#include
-
-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 k96[12] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D };
-
- uint8_t iv[16] = { 0x70, 0x6f, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x20,
- 0x49, 0x6e, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65 };
-
- uint8_t xv[16] = { 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x69, 0x74,
- 0x20, 0x65, 0x71, 0x75, 0x69, 0x76, 0x61, 0x6c };
-
- uint8_t p96[12] = { 0x20, 0x75, 0x73, 0x61, 0x67, 0x65,
- 0x2C, 0x20, 0x68, 0x6F, 0x77, 0x65 };
-
- uint8_t pt[16] = { 0x00 };
-
- // expected outcome (according to pp. 35 & 36 of Implementation Guide 1.1 as of 2019) and
- // original cipher presentation as of 2013 in which notably a different endianess is used
- uint8_t ct[16] = { 0x43, 0x8f, 0x18, 0x9c, 0x8d, 0xb4, 0xee, 0x4e,
- 0x3e, 0xf5, 0xc0, 0x05, 0x04, 0x01, 0x09, 0x41 };
-
- uint8_t xt[16] = { 0x18, 0x0d, 0x57, 0x5c, 0xdf, 0xfe, 0x60, 0x78,
- 0x65, 0x32, 0x78, 0x79, 0x51, 0x98, 0x5d, 0xa6 };
-
- uint8_t x96[12] = { 0xAA, 0x79, 0x8F, 0xDE, 0xBD, 0x62,
- 0x78, 0x71, 0xAB, 0x09, 0x4D, 0x9E };
- speck_context_t ctx;
-
- speck_expand_key (key, &ctx);
-#if defined (SPECK_CTX_BYVAL)
- speck_ctr (pt, pt, 16, iv, ctx);
-#else
- speck_ctr (pt, pt, 16, iv, &ctx);
-#endif
-
- u64 i;
- fprintf (stderr, "rk00: %016llx\n", ctx.key[0]);
- fprintf (stderr, "rk33: %016llx\n", ctx.key[33]);
- fprintf (stderr, "out : %016lx\n", *(uint64_t*)pt);
- fprintf (stderr, "mem : " ); for (i=0; i < 16; i++) fprintf (stderr, "%02x ", pt[i]); fprintf (stderr, "\n");
-
- int ret = 1;
- for (i=0; i < 16; i++)
- if (pt[i] != ct[i]) ret = 0;
-
- memset (pt, 0, 16);
- speck_expand_key_he (key, &ctx);
- speck_he (pt, pt, 16, xv, &ctx);
-
- fprintf (stderr, "rk00: %016llx\n", ctx.key[0]);
- fprintf (stderr, "rk31: %016llx\n", ctx.key[31]);
- fprintf (stderr, "out : %016lx\n", *(uint64_t*)pt);
- fprintf (stderr, "mem : " ); for (i=0; i < 16; i++) fprintf (stderr, "%02x ", pt[i]); fprintf (stderr, "\n");
-
- for (i=0; i < 16; i++)
- if (pt[i] != xt[i]) ret = 0;
-
- speck_expand_key_he_iv (k96, &ctx);
- speck_he_iv_encrypt (p96, &ctx);
-// speck_he_iv_decrypt (p96, &ctx);
-// speck_he_iv_encrypt (p96, &ctx);
-
- fprintf (stderr, "rk00: %016llx\n", ctx.key[0]);
- fprintf (stderr, "rk27: %016llx\n", ctx.key[27]);
- fprintf (stderr, "out : %016lx\n", *(uint64_t*)p96);
- fprintf (stderr, "mem : " ); for (i=0; i < 12; i++) fprintf (stderr, "%02x ", p96[i]); fprintf (stderr, "\n");
-
- for (i=0; i < 12; i++)
- if (p96[i] != x96[i]) ret = 0;
-
- return (ret);
-}
-
-
-int main (int argc, char* argv[]) {
-
- fprintf (stdout, "SPECK SELF TEST RESULT: %u\n", speck_test (0,NULL));
-}
-
-*/
diff --git a/src/transform_speck.c b/src/transform_speck.c
index 18b9aa4..822ad6b 100644
--- a/src/transform_speck.c
+++ b/src/transform_speck.c
@@ -16,19 +16,16 @@
*
*/
-#include "n2n.h"
-#define N2N_SPECK_IVEC_SIZE 16
+#include "n2n.h"
-#define SPECK_KEY_BYTES (256/8)
/* Speck plaintext preamble */
-#define TRANSOP_SPECK_PREAMBLE_SIZE (N2N_SPECK_IVEC_SIZE)
+#define TRANSOP_SPECK_PREAMBLE_SIZE (N2N_SPECK_IVEC_SIZE)
-typedef unsigned char n2n_speck_ivec_t[N2N_SPECK_IVEC_SIZE];
typedef struct transop_speck {
- speck_context_t ctx; /* the round keys for payload encryption & decryption */
+ speck_context_t *ctx; /* the round keys for payload encryption & decryption */
} transop_speck_t;
/* ****************************************************** */
@@ -36,26 +33,11 @@ typedef struct transop_speck {
static int transop_deinit_speck(n2n_trans_op_t *arg) {
transop_speck_t *priv = (transop_speck_t *)arg->priv;
- if(priv)
-#if defined (SPECK_ALIGNED_CTX)
- _mm_free (priv);
-#else
- free (priv);
-#endif
- return 0;
-}
+ if(priv->ctx) speck_deinit(priv->ctx);
-/* ****************************************************** */
+ if(priv) free (priv);
-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 !
- uint64_t rand_value;
- uint8_t i;
-
- for (i = 0; i < N2N_SPECK_IVEC_SIZE; i += sizeof(rand_value)) {
- rand_value = n2n_rand();
- memcpy(ivec + i, &rand_value, sizeof(rand_value));
- }
+ return 0;
}
/* ****************************************************** */
@@ -74,31 +56,30 @@ static int transop_encode_speck(n2n_trans_op_t * arg,
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);
/* Generate and encode the IV. */
- set_speck_iv(priv, enc_ivec);
- encode_buf(outbuf, &idx, &enc_ivec, N2N_SPECK_IVEC_SIZE);
+ encode_uint64(outbuf, &idx, n2n_rand());
+ encode_uint64(outbuf, &idx, n2n_rand());
/* 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, // output starts right after the iv
+ inbuf, // input
+ in_len, // len
+ outbuf, // iv (already encoded in outbuf, speck does not change it)
+ priv->ctx); // ctx already setup with round keys
- speck_ctr (outbuf + TRANSOP_SPECK_PREAMBLE_SIZE, inbuf, in_len, enc_ivec,
-#if defined (SPECK_CTX_BYVAL)
- (priv->ctx));
-#else
- &(priv->ctx));
-#endif
traceEvent(TRACE_DEBUG, "encode_speck: encrypted %u bytes.\n", in_len);
len += TRANSOP_SPECK_PREAMBLE_SIZE; /* size of data carried in UDP. */
@@ -119,6 +100,7 @@ static int transop_decode_speck(n2n_trans_op_t * arg,
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;
@@ -128,21 +110,17 @@ static int transop_decode_speck(n2n_trans_op_t * arg,
{
size_t rem=in_len;
size_t idx=0;
- n2n_speck_ivec_t dec_ivec = {0};
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);
+ len = (in_len - TRANSOP_SPECK_PREAMBLE_SIZE);
+ speck_ctr (outbuf, // output
+ inbuf + TRANSOP_SPECK_PREAMBLE_SIZE, // encrypted data starts right after preamble (IV)
+ len, // len
+ inbuf, // IV can be found at input's beginning
+ priv->ctx); // ctx already setup with round keys
- speck_ctr (outbuf, inbuf + TRANSOP_SPECK_PREAMBLE_SIZE, len, dec_ivec,
-#if defined (SPECK_CTX_BYVAL)
- (priv->ctx));
-#else
- &(priv->ctx));
-#endif
- traceEvent(TRACE_DEBUG, "decode_speck: decrypted %u bytes.\n", len);
+ traceEvent(TRACE_DEBUG, "decode_speck decrypted %u bytes.\n", len);
} else
traceEvent(TRACE_ERROR, "decode_speck inbuf wrong size (%ul) to decrypt.", in_len);
@@ -154,20 +132,17 @@ static int transop_decode_speck(n2n_trans_op_t * arg,
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->ctx), 0, sizeof(speck_context_t) );
+ uint8_t key_mat_buf[32];
/* the input key always gets hashed to make a more unpredictable and more complete use of the key space */
- pearson_hash_256 (key_mat_buf, key, key_size);
+ pearson_hash_256(key_mat_buf, key, key_size);
/* expand the key material to the context (= round keys) */
- speck_expand_key (key_mat_buf, &(priv->ctx));
+ speck_init(key_mat_buf, &(priv->ctx));
- traceEvent(TRACE_DEBUG, "Speck key setup completed\n");
+ traceEvent(TRACE_DEBUG, "setup_speck_key completed\n");
- return(0);
+ return 0;
}
/* ****************************************************** */
@@ -175,8 +150,10 @@ static int setup_speck_key(transop_speck_t *priv, const uint8_t *key, ssize_t ke
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);
@@ -188,17 +165,14 @@ int n2n_transop_speck_init(const n2n_edge_conf_t *conf, n2n_trans_op_t *ttt) {
ttt->deinit = transop_deinit_speck;
ttt->fwd = transop_encode_speck;
ttt->rev = transop_decode_speck;
-#if defined (SPECK_ALIGNED_CTX)
- priv = (transop_speck_t*) _mm_malloc (sizeof(transop_speck_t), SPECK_ALIGNED_CTX);
-#else
- priv = (transop_speck_t*) calloc (1, sizeof(transop_speck_t));
-#endif
+
+ priv = (transop_speck_t*) calloc(1, sizeof(transop_speck_t));
if(!priv) {
- traceEvent(TRACE_ERROR, "cannot allocate transop_speck_t memory");
+ traceEvent(TRACE_ERROR, "n2n_transop_speck_init 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));
+ return setup_speck_key(priv, encrypt_key, encrypt_key_len);
}