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_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

View File

@ -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)

View File

@ -1,35 +1,38 @@
#include <stdio.h>
#include <stdint.h>
#include "header_encryption.h"
#include <string.h>
// #include "n2n_wire.h" // n2n_community_t
#include "n2n.h"
#include "speck.h"
#include "random_numbers.h"
#include "pearson.h"
#include "portable_endian.h"
uint32_t decryt_packet_header (uint8_t packet[], uint8_t packet_len,
char * community_name, speck_ctx * ctx) {
#include <stdio.h>
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 are used padded with ASCII "n2n!"
// the first 96 bits of the packet get padded with ASCII "n2n!"
// to full 128 bit IV
memcopy (iv, packet, 12);
// alternatively, consider: pearson_hash_128 (iv, packet, 12)
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, ctx);
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, ctx);
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);
@ -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) {
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
return (1);
// TODO:
// !!! make sure, no downgrading happens here !!!
// NOT FOR DEFINETLY ENCRYPTED COMMUNITIES / NO DOWNGRADE, NO INJECTION
return (HEADER_ENCRYPTION_NONE);
} else {
// most probably encrypted
@ -67,24 +74,23 @@ int32_t decryt_packet_header_if_required (uint8_t packet[], uint16_t packet_len,
int32_t ret;
struct sn_community *c, *tmp;
HASH_ITER (hh, communities, c, tmp) {
// check if this is an encrypted community
if ( ret = decrypt_packet_header (packet, packet_len, c->community, c-> ctx) ) {
// no upgrade from unencrypted to encrypted
if (c->header_encryption == 1)
return (-2);
// 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 to 'encrypted'
c->header_encryption = 2;
c->header_encryption = HEADER_ENCRYPTION_ENABLED;
// no need to test any further
return (2);
return (HEADER_ENCRYPTION_ENABLED);
}
}
// no match
// no matching key/community
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)
return (-1);
@ -100,5 +106,16 @@ int32_t encryt_packet_header (uint8_t packet[], uint8_t header_len, speck_ctx *
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/crypto.h>
#include "minilzo.h"
#include "header_encryption.h"
#define closesocket(a) close(a)
#endif /* #ifndef WIN32 */
@ -160,6 +161,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
@ -225,6 +227,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 */
@ -270,7 +274,9 @@ typedef struct sn_stats
struct sn_community
{
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 */
};

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 = 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_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)
// https://github.com/nsacyber/simon-speck-supercop/blob/master/crypto_stream/speck128256ctr/
#ifndef SPECK_H
#define SPECK_H
#define u32 uint32_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);
#endif