Browse Source

Merge pull request #265 from Logan007/headerEnc

prepared header encryption
pull/266/head
Luca Deri 4 years ago
committed by GitHub
parent
commit
1dd99c32a1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      CMakeLists.txt
  2. 2
      Makefile.in
  3. 128
      header_encryption.c
  4. 28
      header_encryption.h
  5. 24
      n2n.h
  6. 56
      pearson.c
  7. 2
      pearson.h
  8. 24
      sn.c
  9. 23
      sn_utils.c
  10. 124
      speck.c
  11. 15
      speck.h

4
CMakeLists.txt

@ -61,8 +61,12 @@ add_library(n2n n2n.c
transform_null.c
transform_tf.c
transform_aes.c
transform_cc20.c
transform_speck.c
speck.c
random_numbers.c
pearson.c
header_encryption.c
tuntap_freebsd.c
tuntap_netbsd.c
tuntap_linux.c

2
Makefile.in

@ -51,7 +51,7 @@ N2N_LIB=libn2n.a
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_speck.o \
pearson.o \
header_encryption.o pearson.o \
tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o random_numbers.o \
tuntap_osx.o
LIBS_EDGE+=$(LIBS_EDGE_OPT)

128
header_encryption.c

@ -0,0 +1,128 @@
#include "header_encryption.h"
#include <string.h>
#include "random_numbers.h"
#include "pearson.h"
#include "portable_endian.h"
#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out)
uint32_t packet_header_decrypt (uint8_t packet[], uint8_t packet_len,
char * community_name, he_context_t * ctx) {
// assemble IV
// the last four are ASCII "n2n!" and do not get overwritten
uint8_t iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6E, 0x32, 0x6E, 0x21 };
// the first 96 bits of the packet get padded with ASCII "n2n!"
// to full 128 bit IV
memcpy (iv, packet, 12);
// alternatively, consider: pearson_hash_128 (iv, packet, 12);
// try community name as possible key and check for magic bytes
uint32_t magic = 0x6E326E00; // ="n2n_"
uint32_t test_magic;
// check for magic bytes and resonable value in header len field
speck_he ((uint8_t*)&test_magic, &packet[12], 4, iv, (speck_context_t*)ctx);
test_magic = be32toh (test_magic);
if ( ((test_magic << 8) == magic)
&& ((test_magic >> 24) <= packet_len) // (test_masgic >> 24) is header_len
) {
speck_he (&packet[12], &packet[12], (test_magic >> 24) - 12, iv, (speck_context_t*)ctx);
// restore original packet order
memcpy (&packet[0], &packet[16], 4);
memcpy (&packet[4], community_name, N2N_COMMUNITY_SIZE);
return (1); // successful
} else
return (0); // unsuccessful
}
int8_t packet_header_decrypt_if_required (uint8_t packet[], uint16_t packet_len,
struct sn_community *communities) {
struct sn_community *c, *tmp;
if (packet_len < 20)
return (-1);
// first, check if header is unenrypted to put it into the fast-lane then
// the following check is around 99.99962 percent reliable
// it heavily relies on the structure of packet's common part
// changes to wire.c:encode/decode_common need to go together with this code
if ( (packet[19] == (uint8_t)0x00) // null terminated community name
&& (packet[00] == N2N_PKT_VERSION) // correct packet version
// && (packet[01] <= N2N_DEFAULT_TTL) // reasonable TTL -- might interfere with hole-punching-related or cli passed higher values ?!
&& ((be16toh (*(uint16_t*)&(packet[02])) & N2N_FLAGS_TYPE_MASK ) <= MSG_TYPE_MAX_TYPE ) // message type
&& ( be16toh (*(uint16_t*)&(packet[02])) < N2N_FLAGS_OPTIONS) // flags
) {
// most probably unencrypted
// make sure, no downgrading happens here and no unencrypted packets can be
// injected in a community which definitely deals with encrypted headers
HASH_FIND_COMMUNITY(communities, (char *)&packet[04], c);
if (!c)
if (c->header_encryption == HEADER_ENCRYPTION_ENABLED)
return (-2);
// set 'no encryption' in case it is not set yet
c->header_encryption = HEADER_ENCRYPTION_NONE;
c->header_encryption_ctx = NULL;
return (HEADER_ENCRYPTION_NONE);
} else {
// most probably encrypted
// cycle through the known communities (as keys) to eventually decrypt
int32_t ret;
HASH_ITER (hh, communities, c, tmp) {
// skip the definitely unencrypted communities
if (c->header_encryption == HEADER_ENCRYPTION_NONE)
continue;
if ( (ret = packet_header_decrypt (packet, packet_len, c->community, c->header_encryption_ctx)) ) {
// set 'encrypted' in case it is not set yet
c->header_encryption = HEADER_ENCRYPTION_ENABLED;
// no need to test further communities
return (HEADER_ENCRYPTION_ENABLED);
}
}
// no matching key/community
return (-3);
}
}
int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx) {
if (header_len < 20)
return (-1);
memcpy (&packet[16], &packet[00], 4);
uint8_t iv[16];
((uint64_t*)iv)[0] = n2n_rand ();
((uint64_t*)iv)[1] = n2n_rand ();
const uint32_t magic = 0x006E326E;
((uint32_t*)iv)[3] = htobe32 (magic);
iv[12] = header_len;
speck_he (&packet[12], &packet[12], header_len - 12, iv, (speck_context_t*)ctx);
return (0);
}
void packet_header_setup_key (char * community_name, he_context_t * ctx) {
uint8_t key[16];
pearson_hash_128 (key, (uint8_t*)community_name, N2N_COMMUNITY_SIZE);
ctx = calloc(1, sizeof(speck_context_t));
speck_expand_key_he (key, (speck_context_t*)ctx);
}

28
header_encryption.h

@ -0,0 +1,28 @@
#include <stdint.h>
#include "n2n.h"
#include "speck.h"
typedef struct speck_context_t he_context_t;
/* Header encryption indicators */
#define HEADER_ENCRYPTION_UNKNOWN 0
#define HEADER_ENCRYPTION_NONE 1
#define HEADER_ENCRYPTION_ENABLED 2
uint32_t packet_header_decrypt (uint8_t packet[], uint8_t packet_len,
char * community_name, he_context_t * ctx);
int8_t packet_header_decrypt_if_required (uint8_t packet[], uint16_t packet_len,
struct sn_community * communities);
int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx);
void packet_header_setup_key (char * community_name, he_context_t * ctx);

24
n2n.h

@ -160,6 +160,7 @@ typedef struct tuntap_dev {
#define MSG_TYPE_FEDERATION 8
#define MSG_TYPE_PEER_INFO 9
#define MSG_TYPE_QUERY_PEER 10
#define MSG_TYPE_MAX_TYPE 10
/* N2N compression indicators. */
/* Compression is disabled by default for outgoing packets if no cli
@ -178,6 +179,9 @@ typedef struct tuntap_dev {
bits of transform_id; will be obsolete as soon as compression gets
its own field in the packet. REVISIT then. */
/* forward delcaration of header encryption context, see 'header_encryption.h' */
typedef struct speck_context_t he_context_t;
#define DEFAULT_MTU 1290
/** Uncomment this to enable the MTU check, then try to ssh to generate a fragmented packet. */
@ -225,6 +229,8 @@ typedef struct n2n_edge_conf {
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
n2n_route_t *routes; /**< Networks to route through n2n */
n2n_community_t community_name; /**< The community. 16 full octets. */
uint8_t header_encryption; /**< Header encryption indicator. */
he_context_t *header_encryption_ctx; /**< Header encryption cipher context. */
n2n_transform_t transop_id; /**< The transop to use. */
uint16_t compression; /**< Compress outgoing data packets before encryption */
uint16_t num_routes; /**< Number of routes in routes */
@ -255,6 +261,16 @@ typedef struct sn_stats
time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */
} sn_stats_t;
struct sn_community
{
char community[N2N_COMMUNITY_SIZE];
uint8_t header_encryption; /* Header encryption indicator. */
he_context_t *header_encryption_ctx; /* Header encryption cipher context. */
struct peer_info *edges; /* Link list of registered edges. */
UT_hash_handle hh; /* makes this structure hashable */
};
typedef struct n2n_sn
{
time_t start_time; /* Used to measure uptime. */
@ -267,14 +283,6 @@ typedef struct sn_stats
struct sn_community *communities;
} n2n_sn_t;
struct sn_community
{
char community[N2N_COMMUNITY_SIZE];
struct peer_info *edges; /* Link list of registered edges. */
UT_hash_handle hh; /* makes this structure hashable */
};
/* ************************************** */
#ifdef __ANDROID_NDK__

56
pearson.c

@ -157,3 +157,59 @@ void pearson_hash_256 (uint8_t *out, const uint8_t *in, size_t len) {
o = (uint64_t*)&out[24];
*o = lower_hash;
}
void pearson_hash_128 (uint8_t *out, const uint8_t *in, size_t len) {
/* initial values - astonishingly, assembling using SHIFTs and ORs (in register)
* works faster on well pipelined CPUs than loading the 64-bit value from memory.
* however, there is one advantage to loading from memory: as we also store back to
* memory at the end, we do not need to care about endianess! */
uint8_t upper[8] = { 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 };
uint8_t lower[8] = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
uint64_t upper_hash_mask = *(uint64_t*)&upper;
uint64_t lower_hash_mask = *(uint64_t*)&lower;
uint64_t upper_hash = 0;
uint64_t lower_hash = 0;
for (size_t i = 0; i < len; i++) {
// broadcast the character, xor into hash, make them different permutations
uint64_t c = (uint8_t)in[i];
c |= c << 8;
c |= c << 16;
c |= c << 32;
upper_hash ^= c ^ upper_hash_mask;
lower_hash ^= c ^ lower_hash_mask;
// table lookup
uint8_t x;
uint64_t h = 0;
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
x = upper_hash; x = t[x]; upper_hash >>= 8; h |= x; h=ROR64(h,8);
upper_hash = h;
h = 0;
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
x = lower_hash; x = t[x]; lower_hash >>= 8; h |= x; h=ROR64(h,8);
lower_hash = h;
}
// store output
uint64_t *o;
o = (uint64_t*)&out[0];
*o = upper_hash;
o = (uint64_t*)&out[8];
*o = lower_hash;
}

2
pearson.h

@ -17,3 +17,5 @@
*/
void pearson_hash_256 (uint8_t *out, const uint8_t *in, size_t len);
void pearson_hash_128 (uint8_t *out, const uint8_t *in, size_t len);

24
sn.c

@ -19,6 +19,7 @@
/* Supernode for n2n-2.x */
#include "n2n.h"
#include "header_encryption.h"
#ifdef WIN32
#include <signal.h>
@ -80,6 +81,8 @@ static void deinit_sn(n2n_sn_t * sss)
HASH_ITER(hh, sss->communities, community, tmp) {
clear_peer_list(&community->edges);
if (NULL != community->header_encryption_ctx)
free (community->header_encryption_ctx);
HASH_DEL(sss->communities, community);
free(community);
}
@ -389,6 +392,8 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
HASH_ITER(hh, sss->communities, s, tmp) {
HASH_DEL(sss->communities, s);
if (NULL != s->header_encryption_ctx)
free (s->header_encryption_ctx);
free(s);
}
@ -412,7 +417,12 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
if(s != NULL) {
strncpy((char*)s->community, line, N2N_COMMUNITY_SIZE-1);
s->community[N2N_COMMUNITY_SIZE-1] = '\0';
/* we do not know if header encryption is used in this community,
* first packet will show. just in case, setup the key. */
s->header_encryption = HEADER_ENCRYPTION_UNKNOWN;
packet_header_setup_key (s->community, s->header_encryption_ctx);
HASH_ADD_STR(sss->communities, community, s);
num_communities++;
traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]",
(char*)s->community, num_communities);
@ -435,13 +445,14 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
*/
static int process_udp(n2n_sn_t * sss,
const struct sockaddr_in * sender_sock,
const uint8_t * udp_buf,
uint8_t * udp_buf,
size_t udp_size,
time_t now)
{
n2n_common_t cmn; /* common fields in the packet header */
size_t rem;
size_t idx;
int8_t he = HEADER_ENCRYPTION_UNKNOWN;
size_t msg_type;
uint8_t from_supernode;
macstr_t mac_buf;
@ -453,6 +464,10 @@ static int process_udp(n2n_sn_t * sss,
udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)),
ntohs(sender_sock->sin_port));
he = packet_header_decrypt_if_required (udp_buf, udp_size, sss->communities);
if (he < 0)
return -1; /* something wrong during packet decryption */
/* Use decode_common() to determine the kind of packet then process it:
*
* REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK
@ -622,6 +637,10 @@ static int process_udp(n2n_sn_t * sss,
if(comm) {
strncpy(comm->community, (char*)cmn.community, N2N_COMMUNITY_SIZE-1);
comm->community[N2N_COMMUNITY_SIZE-1] = '\0';
/* new communities introduced by REGISTERs could not have had encrypted header */
comm->header_encryption = HEADER_ENCRYPTION_NONE;
comm->header_encryption_ctx = NULL;
HASH_ADD_STR(sss->communities, community, comm);
traceEvent(TRACE_INFO, "New community: %s", comm->community);
@ -1113,6 +1132,9 @@ static int run_loop(n2n_sn_t * sss) {
if((comm->edges == NULL) && (!sss->lock_communities)) {
traceEvent(TRACE_INFO, "Purging idle community %s", comm->community);
if (NULL != comm->header_encryption_ctx)
/* this should not happen as no 'locked' and thus only communities w/o encrypted header here */
free (comm->header_encryption_ctx);
HASH_DEL(sss->communities, comm);
free(comm);
}

23
sn_utils.c

@ -1,4 +1,5 @@
#include "n2n.h"
#include "header_encryption.h"
#define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out)
#define N2N_SN_LPORT_DEFAULT 7654
@ -37,7 +38,7 @@ static int process_mgmt(n2n_sn_t *sss,
static int process_udp(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *udp_buf,
uint8_t *udp_buf,
size_t udp_size,
time_t now);
@ -225,6 +226,8 @@ void sn_term(n2n_sn_t *sss)
HASH_ITER(hh, sss->communities, community, tmp)
{
clear_peer_list(&community->edges);
if (NULL != community->header_encryption_ctx)
free (community->header_encryption_ctx);
HASH_DEL(sss->communities, community);
free(community);
}
@ -372,13 +375,14 @@ static int process_mgmt(n2n_sn_t *sss,
*/
static int process_udp(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *udp_buf,
uint8_t *udp_buf,
size_t udp_size,
time_t now)
{
n2n_common_t cmn; /* common fields in the packet header */
size_t rem;
size_t idx;
int8_t he = HEADER_ENCRYPTION_UNKNOWN;
size_t msg_type;
uint8_t from_supernode;
macstr_t mac_buf;
@ -390,6 +394,10 @@ static int process_udp(n2n_sn_t *sss,
udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)),
ntohs(sender_sock->sin_port));
he = packet_header_decrypt_if_required (udp_buf, udp_size, sss->communities);
if (he < 0)
return -1; /* something wrong during packet decryption */
/* Use decode_common() to determine the kind of packet then process it:
*
* REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK
@ -571,6 +579,10 @@ static int process_udp(n2n_sn_t *sss,
{
strncpy(comm->community, (char *)cmn.community, N2N_COMMUNITY_SIZE - 1);
comm->community[N2N_COMMUNITY_SIZE - 1] = '\0';
/* new communities introduced by REGISTERs could not have had encrypted header */
comm->header_encryption = HEADER_ENCRYPTION_NONE;
comm->header_encryption_ctx = NULL;
HASH_ADD_STR(sss->communities, community, comm);
traceEvent(TRACE_INFO, "New community: %s", comm->community);
@ -771,7 +783,10 @@ int run_sn_loop(n2n_sn_t *sss, int *keep_running)
if ((comm->edges == NULL) && (!sss->lock_communities))
{
traceEvent(TRACE_INFO, "Purging idle community %s", comm->community);
HASH_DEL(sss->communities, comm);
if (NULL != comm->header_encryption_ctx)
/* this should not happen as no 'locked' and thus only communities w/o encrypted header here */
free (comm->header_encryption_ctx);
HASH_DEL(sss->communities, comm);
free(comm);
}
}
@ -781,4 +796,4 @@ int run_sn_loop(n2n_sn_t *sss, int *keep_running)
sn_term(sss);
return 0;
}
}

124
speck.c

@ -1,9 +1,8 @@
// cipher SPECK -- 128 bit block size -- 256 bit key size
// 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 <stdint.h>
#include "portable_endian.h"
#include "speck.h"
@ -565,9 +564,9 @@ int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
#else // plain C ----------------------------------------------------------------
#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 ROR(x,r) (((x)>>(r))|((x)<<(64-(r))))
#define ROL(x,r) (((x)<<(r))|((x)>>(64-(r))))
#define R(x,y,k) (x=ROR(x,8), x+=y, x^=k, y=ROL(y,3), y^=x)
static int speck_encrypt (u64 *u, u64 *v, speck_context_t *ctx) {
@ -642,6 +641,85 @@ int speck_expand_key (const unsigned char *k, speck_context_t *ctx) {
#endif // AVX, SSE, NEON, plain C ------------------------------------------------
// 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
#define ROR64(x,r) (((x)>>(r))|((x)<<(64-(r))))
#define ROL64(x,r) (((x)<<(r))|((x)>>(64-(r))))
#define R64(x,y,k) (x=ROR64(x,8), x+=y, x^=k, y=ROL64(y,3), y^=x)
static int speck_encrypt_he (u64 *u, u64 *v, speck_context_t *ctx) {
u64 i, x=*u, y=*v;
for (i = 0; i < 32; i++)
R64 (x, y, ctx->key[i]);
*u = x; *v = y;
return 0;
}
int speck_he (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);
if (!inlen) {
free (block);
return 0;
}
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_he (&x, &y, ctx);
((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_he (&x, &y, ctx);
((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_he (const unsigned char *k, speck_context_t *ctx) {
u64 A, B;
u64 i;
A = htole64 ( ((u64 *)k)[0] );
B = htole64 ( ((u64 *)k)[1] );
for (i = 0; i < 32; i ++) {
ctx->key[i] = A;
R64 ( B, A, i);
}
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,
@ -649,16 +727,23 @@ int speck_test () {
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 xv[16] = { 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x69, 0x74,
0x20, 0x65, 0x71, 0x75, 0x69, 0x76, 0x61, 0x6c };
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 };
uint8_t xt[16] = { 0x18, 0x0d, 0x57, 0x5c, 0xdf, 0xfe, 0x60, 0x78,
0x65, 0x32, 0x78, 0x79, 0x51, 0x98, 0x5d, 0xa6 };
speck_context_t ctx;
speck_expand_key (key, &ctx);
@ -667,24 +752,35 @@ int speck_test () {
#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");
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;
return (ret);
}
/*
#include <stdio.h> // for testing
int main (int argc, char* argv[]) {
int main (int argc, char* argv[]) {
fprintf (stdout, "SPECK SELF TEST RESULT: %u\n", speck_test (0,NULL));
}
}
*/

15
speck.h

@ -2,6 +2,11 @@
// 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/
#ifndef SPECK_H
#define SPECK_H
#include <stdint.h>
#define u32 uint32_t
#define u64 uint64_t
@ -54,3 +59,13 @@ speck_context_t *ctx);
int speck_expand_key (const unsigned char *k, 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);
#endif

Loading…
Cancel
Save