From e8181c96f9218fd3212aca5e7004d285763fc113 Mon Sep 17 00:00:00 2001 From: Logan007 Date: Sat, 29 Aug 2020 20:53:37 +0545 Subject: [PATCH] speck transform code clean-up --- include/speck.h | 47 ++++++++--- src/speck.c | 192 ++++++++++++++++++------------------------ src/transform_speck.c | 94 ++++++++------------- 3 files changed, 150 insertions(+), 183 deletions(-) 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 - -#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,30 +33,15 @@ 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 + if(priv->ctx) speck_deinit(priv->ctx); + + 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 ! - 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)); - } -} - -/* ****************************************************** */ - /** The Speck packet format consists of: * * - a 128-bit random IV @@ -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); + 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 - /* Get the IV */ - decode_buf((uint8_t *)&dec_ivec, N2N_SPECK_IVEC_SIZE, inbuf, &rem, &idx); - - 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); }