prepared header encryption

This commit is contained in:
Logan007 2020-06-16 13:27:38 +05:45
parent 105cc40bd4
commit 43feafa1b6
8 changed files with 135 additions and 26 deletions

View File

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

View File

@ -51,7 +51,7 @@ N2N_LIB=libn2n.a
N2N_OBJS=n2n.o wire.o minilzo.o twofish.o speck.o \ N2N_OBJS=n2n.o wire.o minilzo.o twofish.o speck.o \
edge_utils.o sn_utils.o \ edge_utils.o sn_utils.o \
transform_null.o transform_tf.o transform_aes.o transform_cc20.o transform_speck.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_freebsd.o tuntap_netbsd.o tuntap_linux.o random_numbers.o \
tuntap_osx.o tuntap_osx.o
LIBS_EDGE+=$(LIBS_EDGE_OPT) LIBS_EDGE+=$(LIBS_EDGE_OPT)

View File

@ -1,35 +1,38 @@
#include <stdio.h> #include "header_encryption.h"
#include <stdint.h>
#include <string.h>
// #include "n2n_wire.h" // n2n_community_t
#include "n2n.h" #include "n2n.h"
#include "speck.h" #include "random_numbers.h"
#include "pearson.h"
#include "portable_endian.h" #include "portable_endian.h"
uint32_t decryt_packet_header (uint8_t packet[], uint8_t packet_len, #include <stdio.h>
char * community_name, speck_ctx * ctx) {
uint32_t packet_header_decrypt (uint8_t packet[], uint8_t packet_len,
char * community_name, he_context_t * ctx) {
// assemble IV // assemble IV
// the last four are ASCII "n2n!" and do not get overwritten // the last four are ASCII "n2n!" and do not get overwritten
uint8_t iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, uint8_t iv[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6E, 0x32, 0x6E, 0x21 }; 0x00, 0x00, 0x00, 0x00, 0x6E, 0x32, 0x6E, 0x21 };
// the first 96 bits of the packet are used padded with ASCII "n2n!" // the first 96 bits of the packet get padded with ASCII "n2n!"
// to full 128 bit IV // to full 128 bit IV
memcopy (iv, packet, 12); memcpy (iv, packet, 12);
// alternatively, consider: pearson_hash_128 (iv, packet, 12);
// alternatively, consider: pearson_hash_128 (iv, packet, 12)
// try community name as possible key and check for magic bytes // try community name as possible key and check for magic bytes
uint32_t magic = 0x6E326E00; // ="n2n_" uint32_t magic = 0x6E326E00; // ="n2n_"
uint32_t test_magic; uint32_t test_magic;
// check for magic bytes and resonable value in header len field // check for magic bytes and resonable value in header len field
speck_he ((uint8_t*)&test_magic, &packet[12], 4, iv, ctx); speck_he ((uint8_t*)&test_magic, &packet[12], 4, iv, (speck_context_t*)ctx);
test_magic = be32toh (test_magic); test_magic = be32toh (test_magic);
if ( ((test_magic << 8) == magic) if ( ((test_magic << 8) == magic)
&& ((test_magic >> 24) <= packet_len) // (test_masgic >> 24) is header_len && ((test_magic >> 24) <= packet_len) // (test_masgic >> 24) is header_len
) { ) {
speck_he (&packet[12], &packet[12], (test_magic >> 24) - 12, iv, ctx); speck_he (&packet[12], &packet[12], (test_magic >> 24) - 12, iv, (speck_context_t*)ctx);
// restore original packet order // restore original packet order
memcpy (&packet[0], &packet[16], 4); memcpy (&packet[0], &packet[16], 4);
memcpy (&packet[4], community_name, N2N_COMMUNITY_SIZE); memcpy (&packet[4], community_name, N2N_COMMUNITY_SIZE);
@ -39,7 +42,7 @@ uint32_t decryt_packet_header (uint8_t packet[], uint8_t packet_len,
} }
int32_t decryt_packet_header_if_required (uint8_t packet[], uint16_t packet_len, int32_t packet_header_decrypt_if_required (uint8_t packet[], uint16_t packet_len,
struct sn_community *communities) { struct sn_community *communities) {
if (packet_len < 20) if (packet_len < 20)
@ -58,8 +61,12 @@ int32_t decryt_packet_header_if_required (uint8_t packet[], uint16_t packet_len,
) { ) {
// most probably unencrypted // most probably unencrypted
return (1);
// TODO:
// !!! make sure, no downgrading happens here !!!
// NOT FOR DEFINETLY ENCRYPTED COMMUNITIES / NO DOWNGRADE, NO INJECTION
return (HEADER_ENCRYPTION_NONE);
} else { } else {
// most probably encrypted // most probably encrypted
@ -67,24 +74,23 @@ int32_t decryt_packet_header_if_required (uint8_t packet[], uint16_t packet_len,
int32_t ret; int32_t ret;
struct sn_community *c, *tmp; struct sn_community *c, *tmp;
HASH_ITER (hh, communities, c, tmp) { HASH_ITER (hh, communities, c, tmp) {
// check if this is an encrypted community // skip the definitely unencrypted communities
if ( ret = decrypt_packet_header (packet, packet_len, c->community, c-> ctx) ) { if (c->header_encryption == HEADER_ENCRYPTION_NONE)
// no upgrade from unencrypted to encrypted continue;
if (c->header_encryption == 1) if ( (ret = packet_header_decrypt (packet, packet_len, c->community, &(c->header_encryption_ctx))) ) {
return (-2);
// set to 'encrypted' // set to 'encrypted'
c->header_encryption = 2; c->header_encryption = HEADER_ENCRYPTION_ENABLED;
// no need to test any further // no need to test any further
return (2); return (HEADER_ENCRYPTION_ENABLED);
} }
} }
// no match // no matching key/community
return (-3); return (-3);
} }
} }
int32_t encryt_packet_header (uint8_t packet[], uint8_t header_len, speck_ctx * ctx) { int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx) {
if (header_len < 20) if (header_len < 20)
return (-1); return (-1);
@ -100,5 +106,16 @@ int32_t encryt_packet_header (uint8_t packet[], uint8_t header_len, speck_ctx *
iv[12] = header_len; iv[12] = header_len;
speck_he (&packet[12], &packet[12], header_len - 12, iv, ctx); 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);
speck_expand_key_he (key, ctx);
} }

17
header_encryption.h Normal file
View File

@ -0,0 +1,17 @@
#include <stdint.h>
#include "speck.h"
typedef speck_context_t he_context_t;
#define HEADER_ENCRYPTION_UNKNOWN 0
#define HEADER_ENCRYPTION_NONE 1
#define HEADER_ENCRYPTION_ENABLED 2
uint32_t decrypt_packet_header (uint8_t packet[], uint8_t packet_len,
char * community_name, he_context_t * ctx);
int32_t encryt_packet_header (uint8_t packet[], uint8_t header_len, he_context_t * ctx);
int32_t encryt_packet_header (uint8_t packet[], uint8_t header_len, he_context_t * ctx);

8
n2n.h
View File

@ -111,6 +111,7 @@ typedef struct ether_hdr ether_hdr_t;
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include "minilzo.h" #include "minilzo.h"
#include "header_encryption.h"
#define closesocket(a) close(a) #define closesocket(a) close(a)
#endif /* #ifndef WIN32 */ #endif /* #ifndef WIN32 */
@ -160,6 +161,7 @@ typedef struct tuntap_dev {
#define MSG_TYPE_FEDERATION 8 #define MSG_TYPE_FEDERATION 8
#define MSG_TYPE_PEER_INFO 9 #define MSG_TYPE_PEER_INFO 9
#define MSG_TYPE_QUERY_PEER 10 #define MSG_TYPE_QUERY_PEER 10
#define MSG_TYPE_MAX_TYPE 10
/* N2N compression indicators. */ /* N2N compression indicators. */
/* Compression is disabled by default for outgoing packets if no cli /* Compression is disabled by default for outgoing packets if no cli
@ -225,6 +227,8 @@ typedef struct n2n_edge_conf {
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES]; n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
n2n_route_t *routes; /**< Networks to route through n2n */ n2n_route_t *routes; /**< Networks to route through n2n */
n2n_community_t community_name; /**< The community. 16 full octets. */ 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. */ n2n_transform_t transop_id; /**< The transop to use. */
uint16_t compression; /**< Compress outgoing data packets before encryption */ uint16_t compression; /**< Compress outgoing data packets before encryption */
uint16_t num_routes; /**< Number of routes in routes */ uint16_t num_routes; /**< Number of routes in routes */
@ -270,7 +274,9 @@ typedef struct sn_stats
struct sn_community struct sn_community
{ {
char community[N2N_COMMUNITY_SIZE]; char community[N2N_COMMUNITY_SIZE];
struct peer_info *edges; /* Link list of registered edges. */ 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 */ UT_hash_handle hh; /* makes this structure hashable */
}; };

View File

@ -157,3 +157,59 @@ void pearson_hash_256 (uint8_t *out, const uint8_t *in, size_t len) {
o = (uint64_t*)&out[24]; o = (uint64_t*)&out[24];
*o = lower_hash; *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;
}

View File

@ -17,3 +17,5 @@
*/ */
void pearson_hash_256 (uint8_t *out, const uint8_t *in, size_t len); 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);

View File

@ -2,6 +2,10 @@
// taken from (and modified: removed pure crypto-stream generation and seperated key expansion) // 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/ // https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/
#ifndef SPECK_H
#define SPECK_H
#define u32 uint32_t #define u32 uint32_t
#define u64 uint64_t #define u64 uint64_t
@ -61,3 +65,6 @@ int speck_he (unsigned char *out, const unsigned char *in, unsigned long long in
int speck_expand_key_he (const unsigned char *k, speck_context_t *ctx); int speck_expand_key_he (const unsigned char *k, speck_context_t *ctx);
#endif