Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sys: random: add entropy collector #4294

Closed
wants to merge 11 commits into from
4 changes: 4 additions & 0 deletions Makefile.pseudomodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ PSEUDOMODULES += conn
PSEUDOMODULES += conn_ip
PSEUDOMODULES += conn_tcp
PSEUDOMODULES += conn_udp
PSEUDOMODULES += entropy
PSEUDOMODULES += gnrc_netif_default
PSEUDOMODULES += gnrc_ipv6_default
PSEUDOMODULES += gnrc_ipv6_router
Expand All @@ -23,3 +24,6 @@ PSEUDOMODULES += netif
# include variants of the AT86RF2xx drivers as pseudo modules
PSEUDOMODULES += at86rf23%
PSEUDOMODULES += at86rf21%

# add all pseudo random number generator variants as pseudomodules
PSEUDOMODULES += prng_%
37 changes: 37 additions & 0 deletions dist/tools/test_random/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
RIOTBASE := ../../..
INCLUDES := $(RIOTBASE)/sys/include

CFLAGS += $(patsubst %,-I%,$(INCLUDES))
CFLAGS += -Wall -O3

PRNGS ?= mersenne minstd musl_lcg

comma:= ,
empty:=
space:= $(empty) $(empty)
PRNGS_CSV:= $(subst $(space),$(comma),$(PRNGS))

all: $(PRNGS:%=test_%) $(PRNGS:%=test_%_entropy)

clean:
rm -f test_*_entropy
rm -f test_{$(PRNGS_CSV)}

test_%: test_random.c $(RIOTBASE)/sys/random/%.c
$(CC) $(CFLAGS) $^ -o $@$(SUFFIX)

test_%_entropy: test_random.c $(RIOTBASE)/sys/random/%.c $(RIOTBASE)/sys/random/entropy.c
$(CC) $(CFLAGS) -DMODULE_ENTROPY -DURANDOM $^ -o $@$(SUFFIX)

MODIFIED_ENT:=""#"Chi-percent,"

run_tests: all
echo "prng,Entropy_injection_freq,unused,File-bytes,Entropy,Chi-square,$(MODIFIED_ENT)Mean,Monte-Carlo-Pi,Serial-Correlation" > ent_results.txt
for prng in $(PRNGS) ; do \
./test_$${prng} > test_$${prng}_out ; \
echo $${prng},-1,$$(ent -t test_$${prng}_out | tail -n 1) >> ent_results.txt; \
for freq in 1024 4096 16384 65536 262144 1048576 4194304 16777216; do \
./test_$${prng}_entropy $${freq}> test_$${prng}_entropy_freq_$${freq}_out ; \
echo $${prng},$${freq},$$(ent -t test_$${prng}_entropy_freq_$${freq}_out | tail -n 1) >> ent_results.txt; \
done ; \
done
46 changes: 46 additions & 0 deletions dist/tools/test_random/test_random.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>

#ifdef MODULE_ENTROPY
#include "entropy.h"
#define ENTROPY_FREQ_DEFAULT 1024
#endif

uint32_t genrand_uint32(void);
void genrand_init(uint32_t s);

#define N_WORDS (2<<24)

int main(int argc, char *argv[]) {
uint32_t random;
uint32_t n = N_WORDS;

#ifdef MODULE_ENTROPY
uint32_t entropy_freq;

if (argc>1) {
entropy_freq = atoi(argv[1]);
} else {
entropy_freq = ENTROPY_FREQ_DEFAULT;
}

fprintf(stderr, "Injecting a random byte every %u times.\n", entropy_freq);
#endif

while(n--) {

#ifdef MODULE_ENTROPY
if (! (n % entropy_freq)) {
fprintf(stderr, "Collecting entropy... %u\n", n);
entropy_collect();
}
#endif

random = genrand_uint32();
write(STDOUT_FILENO, &random, 4);
}

return 0;
}
22 changes: 22 additions & 0 deletions sys/include/div.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,28 @@ static inline uint32_t div_u32_by_15625div512(uint32_t val)
return ((uint64_t)(val) * 0x431bde83ul) >> (12 + 32 - 9);
}

/**
* @brief Integer divide val by 44488
*
* @param[in] val dividend
* @return (val / 44488)
*/
static inline uint32_t div_u32_by_44488(uint32_t val)
{
return ((uint64_t)val * 0xBC8F1391UL) >> (15 + 32);
}

/**
* @brief Modulo 44488
*
* @param[in] val dividend
* @return (val % 44488)
*/
static inline uint32_t div_u32_mod_44488(uint32_t val)
{
return val - (div_u32_by_44488(val)*44488);
}

#ifdef __cplusplus
}
#endif
Expand Down
9 changes: 9 additions & 0 deletions sys/include/entropy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef ENTROPY_H
#define ENTROPY_H

#include <stdint.h>

extern uint32_t entropy;
void entropy_collect(void);

#endif /* ENTROPY_H */
13 changes: 13 additions & 0 deletions sys/random/Makefile
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
ifeq (,$(filter prng_%,$(USEMODULE)))
USEMODULE += prng_mersenne
endif
ifneq (,$(filter prng_mersenne,$(USEMODULE)))
SRC += mersenne.c
endif
ifneq (,$(filter prng_minstd,$(USEMODULE)))
SRC += minstd.c
endif
ifneq (,$(filter prng_musl_lcg,$(USEMODULE)))
SRC += musl_lcg.c
endif

include $(RIOTBASE)/Makefile.base
36 changes: 36 additions & 0 deletions sys/random/entropy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <stdint.h>

#ifdef MODULE_XTIMER
#include "xtimer.h"
static uint32_t _last_event;
#endif

#if defined(URANDOM)
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif

uint32_t entropy;
static unsigned _n = 0;

#ifndef ENTROPY_OP
#define ENTROPY_OP(x) (x & 0xFF)
#endif

void entropy_collect(void)
{
#ifdef MODULE_XTIMER
uint32_t now = _lltimer_now();
uint32_t diff = now - _last_event;
_last_event = now;
#elif defined(URANDOM)
int fd = open("/dev/urandom", O_RDONLY);
char randbyte;
read(fd, &randbyte, 1);
uint32_t diff = (uint8_t) randbyte;
close(fd);
#endif

entropy ^= ((ENTROPY_OP(diff)) << ((_n++ & 0x3) * 8));
}
9 changes: 9 additions & 0 deletions sys/random/mersenne.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
static uint32_t mt[N]; /** the array for the state vector */
static uint16_t mti = MTI_UNINITIALIZED;

#ifdef MODULE_ENTROPY
#include "entropy.h"
#endif

void genrand_init(uint32_t s)
{
mt[0] = s;
Expand Down Expand Up @@ -129,7 +133,12 @@ uint32_t genrand_uint32(void)
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= y >> 18;

#ifdef MODULE_ENTROPY
return y + entropy;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the entropy introduced as a seed, rather then messing with the deterministic qualities of the PNR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I felt that adding something halfway random is less predictive than setting a halfway random starting point. lets ask a mathematician, though.

-----Original Message-----
From: Martine Lenders notifications@github.com
To: RIOT-OS/RIOT RIOT@noreply.github.com
Cc: Kaspar Schleiser kaspar@schleiser.de
Sent: Di., 17 Nov. 2015 18:16
Subject: Re: [RIOT] sys: random: add entropy collector (#4294)

@@ -129,7 +133,12 @@ uint32_t genrand_uint32(void)
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= y >> 18;
+
+#ifdef MODULE_ENTROPY

  • return y + entropy;

Shouldn't the entropy introduced as a seed, rather then messing with the deterministic qualities of the PNR?


Reply to this email directly or view it on GitHub:
https://github.com/RIOT-OS/RIOT/pull/4294/files#r45088799

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Speaking as a mathematician: Entropy is not randomness, but something like 'unpredictability'. It is mostly needed for crypto.
It is the continuous experience that adding something 'that looks random' is rather harmful than helpful. A colleague, who is a crypto-mathematician, just recently told me that (with NXP) they had performed a larger study on common sources of 'entropy' (typing, perturbed wireless signals, other hardware fluctuations) and results were disastrous: no reliable unpredictability nowhere.

Practically speaking, a pseudo-random number generator basically reproduces certain statistical properties, starting it's 'randomness' from initialization (seeds). With equal seeds and common generators, number sequences deterministically repeat, which often is a desired property for debugging. I would stick to this approach and clearly state that this is not crypto-safe.
Adding 'something' to the number output, mainly produces the threat of spoiling the statistical properties ... it is very unlikely to maximize entropy by this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they had performed a larger study on common sources of 'entropy' (typing, perturbed wireless signals, other hardware fluctuations) and results were disastrous: no reliable unpredictability nowhere.

I'd like to read that study.

Apart from that, I think we have several levels of needed 'randomness'.

  • "bootup-safe" -> 1000(*n) nodes booting up at the same time will not have the same IP address if that is derived from our "random number generator"
  • "network-safe" -> "random" back-off will not collide between nodes
  • "crypto-safe" -> the higher gods of crypto math consider it "random" enough for safe crypto

Let's solve them one at a time.

This PR might help with the letter edit first edit two if used correctly. And it adds only 15 lines of code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(typing, perturbed wireless signals, other hardware fluctuations)

Just keep in mind, this (typing, perturbed wireless signals, other hardware fluctuations) is what e.g., Linux is using as entropy. It is very probably better than nothing, and when it will be proven useless one day, we won't be able to use it anymore. But until then, it (probably) improves our "randomness".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from that, I think we have several levels of needed 'randomness'.

  • "bootup-safe" -> 1000(*n) nodes booting up at the same time will not have the same IP address > if that is derived from our "random number generator"
  • "network-safe" -> "random" back-off will not collide between nodes
  • "crypto-safe" -> the higher gods of crypto math consider it "random" enough for safe crypto

I guess that's exactly why "the big OSs" have varying degrees of RNGs:

  • rand() in libc for quick, but deterministic PRNG values
  • /dev/random for slow, but true randomness from outside sources
  • /dev/urandom for something in between

I saw the random module always as something like rand() and periph/random as our /dev/random. True, for boards without periph/random we still need a randomness source, and maybe this is a start, but I wouldn't touch the PRNGs for that (except that we still need some way to initialize them properly).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi again Kaspar,

On 18.11.2015 03:13, Kaspar Schleiser wrote:

hey had performed a larger study on common sources of 'entropy'
(typing, perturbed wireless signals, other hardware fluctuations)
and results were disastrous: no reliable unpredictability nowhere.

I'd like to read that study.

I managed to get a hold of the colleague. No official report available,
but helpful input:

First, there is a good standardized test suite of 'randomness' for
random number generators by NIST:
http://csrc.nist.gov/groups/ST/toolkit/rng/documentation_software.html -
one can use this to verify the quality of an implementation.

Second, she said that the best pseudo-randomness at reasonable effort
is achieved by coupling to nonlinear feedback shift register. This would
be feasible for crypto, as well. I have not looked at specific
implementations (and their complexity), but I guess we should keep to
this double strategy (if needed): One very lightweight simple (not
necessariyl crypto-safe) implementation and one that is crypto-compliant.

Thomas

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! I am no mathematician...
Instead of return y + entropy; (which can lead to overflows; and from a distribution/security point of view I am not sure if an adittion adds entropy to a source, I would say no.. and on the contrary you will likely have less number having a value lower than MAXINT/4),
why don't you perform an xor? return y ^ entropy;
I think it nicely uses the entropy (as a one time pad) to modify y.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is still the only problem I have with this PR. The entropy should only manipulate the seed, not the return value of the PNRG.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, I gave it a thought, and indeed, adding a random variable to another, has nefarious consequences (or at best not the expected ones I think).
For instance the sum of two uniformly distributed variables, is not uniform anymore:
http://math.stackexchange.com/questions/357672/density-of-sum-of-two-uniform-random-variables-0-1
http://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter7.pdf figure 7.2.

Assuming "y" and "entropy" variables are random. After adding them we have a probability of 1/2 of having a value >= MaxInt. Better not rely on how overflow is handled by each platform.

#else
return y;
#endif
}

#if PRNG_FLOAT
Expand Down
84 changes: 84 additions & 0 deletions sys/random/minstd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
* Code taken from C FAQ (http://c-faq.com/lib/rand.html).
*/

/**
* @ingroup sys_random
* @{
* @file
*
* @brief Simple Park & Miller "minimal standard" PRNG
*
* This file contains a simple Park-Miller pseudo random number generator.
*
* While not very random when considering crypto requirements, this is probably
* random enough anywhere where pseudo-randomness is sufficient, e.g., when
* provided with a sensible seed source, for MAC algorithms.
*
* The implementation is taken from the C FAQ, but modified to use magic number
* division and adapted to RIOT's coding conventions..
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @}
*/

#include <stdint.h>

#include "div.h"

#ifdef MODULE_ENTROPY
#include "entropy.h"
#endif

#define a 48271
#define m 2147483647
#define q (m / a) /* 44488 */
#define r (m % a) /* 3399 */

static uint32_t _seed = 1;

int rand_minstd(void)
{
uint32_t hi = div_u32_by_44488(_seed);
uint32_t lo = div_u32_mod_44488(_seed);
uint32_t test = (a * lo) - (r * hi);

if(test > 0) {
_seed = test;
}
else {
_seed = test + m;
}

return _seed;
}

uint32_t genrand_uint32(void)
{
/* minstd as implemented returns only values from 1 to 2147483647,
* so run it two times to get 32bits */
uint16_t A = (rand_minstd() >> 15);
uint16_t B = (rand_minstd() >> 15);

uint32_t res = (((uint32_t)A) << 16) | B;

#ifdef MODULE_ENTROPY
return res ^ entropy;
#else
return res;
#endif
}

void genrand_init(uint32_t val)
{
if (!val) {
val = 1;
}
_seed = val;
}
53 changes: 53 additions & 0 deletions sys/random/musl_lcg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
* Code taken from Musl C library. Original copyright notice:
*
* Copyright © 2005-2014 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:

* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <stdint.h>

#ifdef MODULE_ENTROPY
#include "entropy.h"
#endif

static uint64_t _seed;

void genrand_init(uint32_t s)
{
_seed = s-1;
}

uint32_t genrand_uint32(void)
{
_seed = 6364136223846793005ULL*_seed + 1;
#ifdef MODULE_ENTROPY
return (_seed>>31) ^ entropy;
#else
return _seed>>31;
#endif
}
2 changes: 1 addition & 1 deletion sys/shell/commands/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ ifneq (,$(filter lpc2387,$(USEMODULE)))
SRC += sc_heap.c
endif
ifneq (,$(filter random,$(USEMODULE)))
SRC += sc_mersenne.c
SRC += sc_random.c
endif
ifeq ($(CPU),x86)
SRC += sc_x86_lspci.c
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* @{
*
* @file
* @brief Shell commands for mersenne twister
* @brief Shell commands for random generators
*
* @author Christian Mehlis <mehlis@inf.fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
Expand All @@ -30,7 +30,7 @@

#include "random.h"

int _mersenne_init(int argc, char **argv)
int _random_init(int argc, char **argv)
{
int initval;

Expand All @@ -53,7 +53,7 @@ int _mersenne_init(int argc, char **argv)
return 0;
}

int _mersenne_get(int argc, char **argv)
int _random_get(int argc, char **argv)
{
(void) argc;
(void) argv;
Expand Down
Loading