diff --git a/Makefile.in b/Makefile.in index e27686b..6037faf 100644 --- a/Makefile.in +++ b/Makefile.in @@ -7,7 +7,7 @@ GIT_COMMITS=@GIT_COMMITS@ CC?=gcc DEBUG?=-g3 -OPTIMIZATION?=-O3 #-march=native +OPTIMIZATION?=-O3 -march=native WARN?=-Wall #Ultrasparc64 users experiencing SIGBUS should try the following gcc options @@ -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 \ - tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o \ + tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o random_numbers.o \ tuntap_osx.o LIBS_EDGE+=$(LIBS_EDGE_OPT) LIBS_SN= diff --git a/edge.c b/edge.c index d3600da..5b7b84a 100644 --- a/edge.c +++ b/edge.c @@ -17,6 +17,7 @@ */ #include "n2n.h" +#include "random_numbers.h" #ifdef WIN32 #include #else @@ -871,7 +872,7 @@ int main(int argc, char* argv[]) { traceEvent(TRACE_NORMAL, "Using %s cipher.", transop_str(conf.transop_id)); /* Random seed */ - srand(time(NULL)); + n2n_srand (n2n_seed()); if(0 == strcmp("dhcp", ec.ip_mode)) { traceEvent(TRACE_NORMAL, "Dynamic IP address assignment enabled."); diff --git a/edge_utils.c b/edge_utils.c index 72ff8ab..825b8ef 100644 --- a/edge_utils.c +++ b/edge_utils.c @@ -18,6 +18,7 @@ #include "n2n.h" #include "lzoconf.h" +#include "random_numbers.h" #ifdef HAVE_LIBZSTD #include @@ -759,7 +760,7 @@ static void send_register_super(n2n_edge_t * eee, memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); for(idx=0; idx < N2N_COOKIE_SIZE; ++idx) - eee->last_cookie[idx] = rand() % 0xff; + eee->last_cookie[idx] = n2n_rand() % 0xff; memcpy(reg.cookie, eee->last_cookie, N2N_COOKIE_SIZE); reg.auth.scheme=0; /* No auth yet */ diff --git a/example_edge_embed_quick_edge_init.c b/example_edge_embed_quick_edge_init.c index 591d830..ba0eb02 100644 --- a/example_edge_embed_quick_edge_init.c +++ b/example_edge_embed_quick_edge_init.c @@ -17,6 +17,7 @@ */ #include "n2n.h" +#include "random_numbers.h" /* This tool demonstrates how to easily embed @@ -36,7 +37,7 @@ int main(int argc, char* argv[]) { setTraceLevel(10); /* Random seed */ - srand(time(NULL)); + n2n_srand (n2n_seed()); /* NOTE @@ -51,4 +52,4 @@ int main(int argc, char* argv[]) { my_ipv4_addr, supernode, &keep_on_running)); -} \ No newline at end of file +} diff --git a/random_numbers.c b/random_numbers.c new file mode 100644 index 0000000..38d452e --- /dev/null +++ b/random_numbers.c @@ -0,0 +1,116 @@ +/* The following code offers an alterate pseudo random number generator + namely XORSHIFT128+ to use instead of C's rand(). Its performance is + on par with C's rand(). + */ + + +#include "random_numbers.h" + + +/* The state must be seeded in a way that it is not all zero, choose some + arbitrary defaults (in this case: taken from splitmix64) */ +static struct rn_generator_state_t rn_current_state = { + .a = 0x9E3779B97F4A7C15, + .b = 0xBF58476D1CE4E5B9 }; + + +/* used for mixing the initializing seed */ +static uint64_t splitmix64 (struct splitmix64_state_t *state) { + + uint64_t result = state->s; + + state->s = result + 0x9E3779B97F4A7C15; + + result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9; + result = (result ^ (result >> 27)) * 0x94D049BB133111EB; + + return result ^ (result >> 31); +} + + +int n2n_srand (uint64_t seed) { + + struct splitmix64_state_t smstate = {seed}; + + rn_current_state.a = 0; + rn_current_state.b = 0; + + rn_current_state.a = splitmix64 (&smstate); + rn_current_state.b = splitmix64 (&smstate); + + /* the following lines could be deleted as soon as it is formally prooved that + there is no seed leading to (a == b == 0). Until then, just to be safe: */ + if ( (rn_current_state.a == 0) && (rn_current_state.b == 0) ) { + rn_current_state.a = 0x9E3779B97F4A7C15; + rn_current_state.b = 0xBF58476D1CE4E5B9; + } + + /* stabilize in unlikely case of weak state with only a few bits set */ + for (uint8_t i = 0; i < 32; i++) + n2n_rand(); + + return 0; +} + + +/* The following code of xorshift128p was taken from + https://en.wikipedia.org/wiki/Xorshift as of July, 2019 + and thus is considered public domain. */ +uint64_t n2n_rand () { + + uint64_t t = rn_current_state.a; + uint64_t const s = rn_current_state.b; + + rn_current_state.a = s; + t ^= t << 23; + t ^= t >> 17; + t ^= s ^ (s >> 26); + rn_current_state.b = t; + + return t + s; +} + + +/* The following code tries to gather some entropy from several sources + for use as seed. Note, that this code does not set the random generator + state yet, a call to n2n_srand ( n2n_seed() ) would do. */ +uint64_t n2n_seed (void) { + + uint64_t seed = 0; + uint64_t ret = 0; + +#ifdef SYS_getrandom + syscall (SYS_getrandom, &seed, sizeof(seed), GRND_NONBLOCK); + ret += seed; +#endif + +// __RDRND__ is set only if architecturual feature is set, e.g. compile with -march=native +#ifdef __RDRND__ + _rdrand64_step ((unsigned long long*)&seed); + ret += seed; +#endif + +// __RDSEED__ ist set only if architecturual feature is set, e.g. compile with -march=native +#ifdef __RDSEED__ + _rdseed64_step((unsigned long long*)&seed); + ret += seed; +#endif + +/* The WIN32 code is still untested and thus commented +#ifdef WIN32 + HCRYPTPROV crypto_provider; + CryptAcquireContext (&crypto_provider, NULL, (LPCWSTR)L"Microsoft Base Cryptographic Provider v1.0", + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + CryptGenRandom (crypto_provider, 8, &seed); + CryptReleaseContext (crypto_provider, 0); + ret += seed; +#endif */ + + seed = time(NULL); /* UTC in seconds */ + ret += seed; + + seed = clock() * 8996146197; /* clock() = ticks since program start */ + ret += seed; + + return ret; +} diff --git a/random_numbers.h b/random_numbers.h new file mode 100644 index 0000000..aa0b0a0 --- /dev/null +++ b/random_numbers.h @@ -0,0 +1,34 @@ +#include +#include + + +#if defined (__linux__) + #include + #include + #define GRND_NONBLOCK 1 +#endif + +#if defined (__RDRND__) || defined (__RDSEED__) + #include +#endif + +/* The WIN32 code is still untested and thus commented +#if defined (WIN32) + #include +#endif */ + + +struct rn_generator_state_t { + uint64_t a, b; +}; + +struct splitmix64_state_t { + uint64_t s; +}; + + +int n2n_srand (uint64_t seed); + +uint64_t n2n_rand (); + +uint64_t n2n_seed (); diff --git a/transform_aes.c b/transform_aes.c index ca4f1d8..40d652a 100644 --- a/transform_aes.c +++ b/transform_aes.c @@ -18,6 +18,7 @@ #include "n2n.h" #include "n2n_transforms.h" +#include "random_numbers.h" #ifdef N2N_HAVE_AES @@ -169,17 +170,17 @@ static int transop_encode_aes(n2n_trans_op_t * arg, /* Encode the aes format version. */ encode_uint8(outbuf, &idx, N2N_AES_TRANSFORM_VERSION); - /* Generate and encode the IV seed using as many calls to rand() as neccessary. + /* Generate and encode the IV seed using as many calls to n2n_rand() as neccessary. * Note: ( N2N_AES_IV_SEED_SIZE % sizeof(rand_value) ) not neccessarily equals 0. */ - uint32_t rand_value; + uint64_t rand_value; int8_t i; for (i = TRANSOP_AES_IV_SEED_SIZE; i >= sizeof(rand_value); i -= sizeof(rand_value)) { - rand_value = rand(); // CONCERN: rand() is not consideren cryptographicly secure, REPLACE later + rand_value = n2n_rand(); memcpy(iv_seed + TRANSOP_AES_IV_SEED_SIZE - i, &rand_value, sizeof(rand_value)); } /* Are there bytes left to fill? */ if (i != 0) { - rand_value = rand(); // CONCERN: rand() is not consideren cryptographicly secure, REPLACE later + rand_value = n2n_rand(); memcpy(iv_seed, &rand_value, i); } encode_buf(outbuf, &idx, iv_seed, TRANSOP_AES_IV_SEED_SIZE); diff --git a/transform_cc20.c b/transform_cc20.c index f937775..90c92b2 100644 --- a/transform_cc20.c +++ b/transform_cc20.c @@ -18,6 +18,7 @@ #include "n2n.h" #include "n2n_transforms.h" +#include "random_numbers.h" #ifdef HAVE_OPENSSL_1_1 @@ -79,9 +80,9 @@ static char *openssl_err_as_string (void) { static void set_cc20_iv(transop_cc20_t *priv, n2n_cc20_ivec_t ivec) { // keep in mind the following condition: N2N_CC20_IVEC_SIZE % sizeof(rand_value) == 0 ! - uint32_t rand_value; + uint64_t rand_value; for (uint8_t i = 0; i < N2N_CC20_IVEC_SIZE; i += sizeof(rand_value)) { - rand_value = rand(); // CONCERN: rand() is not consideren cryptographicly secure, REPLACE later + rand_value = n2n_rand(); memcpy(ivec + i, &rand_value, sizeof(rand_value)); } } diff --git a/transform_speck.c b/transform_speck.c index 9e00e77..093475e 100644 --- a/transform_speck.c +++ b/transform_speck.c @@ -19,6 +19,7 @@ #include "n2n.h" #include "n2n_transforms.h" #include "speck.h" +#include "random_numbers.h" #define N2N_SPECK_TRANSFORM_VERSION 1 /* version of the transform encoding */ #define N2N_SPECK_IVEC_SIZE 16 @@ -53,11 +54,11 @@ static int transop_deinit_speck(n2n_trans_op_t *arg) { 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; + uint64_t rand_value; uint8_t i; for (i = 0; i < N2N_SPECK_IVEC_SIZE; i += sizeof(rand_value)) { - rand_value = rand(); // CONCERN: rand() is not considered cryptographicly secure, REPLACE later + rand_value = n2n_rand(); memcpy(ivec + i, &rand_value, sizeof(rand_value)); } } diff --git a/transform_tf.c b/transform_tf.c index 817b09f..412f65f 100644 --- a/transform_tf.c +++ b/transform_tf.c @@ -19,6 +19,7 @@ #include "n2n.h" #include "n2n_transforms.h" #include "twofish.h" +#include "random_numbers.h" #ifndef _MSC_VER /* Not included in Visual Studio 2008 */ #include /* index() */ @@ -89,7 +90,7 @@ static int transop_encode_twofish( n2n_trans_op_t * arg, * written in first followed by the packet payload. The whole * contents of assembly are encrypted. */ pnonce = (uint32_t *)assembly; - *pnonce = rand(); + *pnonce = n2n_rand(); memcpy( assembly + TRANSOP_TF_NONCE_SIZE, inbuf, in_len ); /* Encrypt the assembly contents and write the ciphertext after the SA. */ diff --git a/tuntap_linux.c b/tuntap_linux.c index b3f6fe5..6e1e770 100644 --- a/tuntap_linux.c +++ b/tuntap_linux.c @@ -25,6 +25,7 @@ #include #include #include +#include "random_numbers.h" /* ********************************** */ @@ -152,7 +153,7 @@ int tuntap_open(tuntap_dev *device, int i; for(i = 0; i < 6; i++) - device->mac_addr[i] = rand(); + device->mac_addr[i] = n2n_rand(); device->mac_addr[0] &= ~0x01; /* Clear multicast bit */ device->mac_addr[0] |= 0x02; /* Set locally-assigned bit */ diff --git a/twofish.c b/twofish.c index a1f9a9b..7c7b8de 100644 --- a/twofish.c +++ b/twofish.c @@ -41,6 +41,7 @@ #include #include #include "twofish.h" +#include "random_numbers.h" /* Fixed 8x8 permutation S-boxes */ static const uint8_t TwoFish_P[2][256] = @@ -403,7 +404,7 @@ uint32_t TwoFishEncrypt(uint8_t *in, *out=TwoFishAlloc(ilen,binhex,FALSE,tfdata); /* ...we'll (re-)allocate buffer space. */ if(*out!=NULL) { tfdata->output=*out; /* set output buffer. */ - tfdata->header.salt=rand()*65536+rand(); /* toss in some salt. */ + tfdata->header.salt=n2n_rand()*65536+n2n_rand(); /* toss in some salt. */ tfdata->header.length[0]= (uint8_t)(ilen); tfdata->header.length[1]= (uint8_t)(ilen>>8); tfdata->header.length[2]= (uint8_t)(ilen>>16); @@ -980,7 +981,7 @@ int main(int argc, char* argv[]) for ( i=0; i