Browse Source

speck transform code clean-up

pull/394/head
Logan007 4 years ago
parent
commit
e8181c96f9
  1. 47
      include/speck.h
  2. 184
      src/speck.c
  3. 90
      src/transform_speck.c

47
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 <http://www.gnu.org/licenses/>
*
*/
// 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 <stdint.h>
#include <stdlib.h>
#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 <immintrin.h>
#define SPECK_ALIGNED_CTX 32
#define u256 __m256i
typedef struct {
u256 rk[34];
@ -22,9 +48,9 @@ typedef struct {
#elif defined (__SSE4_2__)
#include <immintrin.h>
#define SPECK_ALIGNED_CTX 16
#define SPECK_CTX_BYVAL 1
#include <immintrin.h>
#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

184
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 <http://www.gnu.org/licenses/>
*
*/
// 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 <stdlib.h>
#include "portable_endian.h"
#include "speck.h"
@ -139,7 +156,7 @@ 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,
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;
@ -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,8 +344,8 @@ 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,
// 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;
@ -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,7 +517,7 @@ 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,
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;
@ -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,7 +603,7 @@ 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,
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;
@ -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 <stdio.h> // for testing
#include <string.h>
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));
}
*/

90
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)
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);
}

Loading…
Cancel
Save