mirror of https://github.com/ntop/n2n.git
Logan007
5 years ago
9 changed files with 389 additions and 2 deletions
@ -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)); |
|||
} |
|||
*/ |
|||
|
@ -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[]); |
@ -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