lx_emul/random: re-seed the local PRNG regularly

With this commit, the Xoroshiro128+ PRNG in lx_emul/random.cc gets wrapped
by a new class that automatically re-seeds the PRNG with jitterentropy every
1024 * 1024 + random(0..4095) bytes of generated output.

Ref #4397
This commit is contained in:
Martin Stein 2022-05-19 18:12:20 +02:00 committed by Christian Helmuth
parent ab0bce77ec
commit 03349f9fff
2 changed files with 97 additions and 24 deletions

View File

@ -11,8 +11,7 @@
* the lx_emul randomness functions has known statistical problems (see * the lx_emul randomness functions has known statistical problems (see
* https://en.wikipedia.org/wiki/Xoroshiro128%2B#Statistical_Quality). * https://en.wikipedia.org/wiki/Xoroshiro128%2B#Statistical_Quality).
* Furthermore, the integration of Xoroshir128+ with the lx_emul code was not * Furthermore, the integration of Xoroshir128+ with the lx_emul code was not
* reviewed/audited for its security-related properties, so far, and has the * reviewed/audited for its security-related properties, so far. Thus,
* known deficiency of seeding the PRNG only once during initialization. Thus,
* we strongly advise against the use of the lx_emul randomness functions for * we strongly advise against the use of the lx_emul randomness functions for
* security-critical purposes. * security-critical purposes.
*/ */

View File

@ -11,8 +11,7 @@
* the lx_emul randomness functions has known statistical problems (see * the lx_emul randomness functions has known statistical problems (see
* https://en.wikipedia.org/wiki/Xoroshiro128%2B#Statistical_Quality). * https://en.wikipedia.org/wiki/Xoroshiro128%2B#Statistical_Quality).
* Furthermore, the integration of Xoroshir128+ with the lx_emul code was not * Furthermore, the integration of Xoroshir128+ with the lx_emul code was not
* reviewed/audited for its security-related properties, so far, and has the * reviewed/audited for its security-related properties, so far. Thus,
* known deficiency of seeding the PRNG only once during initialization. Thus,
* we strongly advise against the use of the lx_emul randomness functions for * we strongly advise against the use of the lx_emul randomness functions for
* security-critical purposes. * security-critical purposes.
*/ */
@ -87,29 +86,105 @@ class Xoroshiro_128_plus
} }
}; };
static uint64_t jitterentropy_gen_random_u64()
class Entropy_source : Interface
{ {
static rand_data *jent { nullptr }; public:
if (jent == nullptr) {
jitterentropy_init(Lx_kit::env().heap); virtual uint64_t gen_random_u64() = 0;
};
/*
* A wrapper for the Xoroshiro128+ PRNG that reseeds the PRNG every
* 1024 * 1024 + random(0..4095) bytes of generated output.
*/
class Xoroshiro_128_plus_reseeding
{
private:
enum { NR_OF_GEN_BYTES_BASE_LIMIT = 1024 * 1024 };
Entropy_source &_entropy_src;
uint64_t _seed { 0 };
size_t _nr_of_gen_bytes { 0 };
size_t _nr_of_gen_bytes_limit { 0 };
Constructible<Xoroshiro_128_plus> _xoroshiro { };
void _reseed()
{
_seed = _entropy_src.gen_random_u64();
_nr_of_gen_bytes = 0;
_nr_of_gen_bytes_limit =
NR_OF_GEN_BYTES_BASE_LIMIT + (_seed & 0xfff);
_xoroshiro.construct(_seed);
}
public:
Xoroshiro_128_plus_reseeding(Entropy_source &entropy_src)
:
_entropy_src { entropy_src }
{
_reseed();
}
uint64_t get_u64()
{
_nr_of_gen_bytes += 8;
if (_nr_of_gen_bytes >= _nr_of_gen_bytes_limit) {
_reseed();
_nr_of_gen_bytes += 8;
}
return _xoroshiro->get_u64();
}
};
class Jitterentropy : public Entropy_source
{
private:
rand_data *_rand_data { nullptr };
Jitterentropy(Jitterentropy const &) = delete;
Jitterentropy & operator = (Jitterentropy const &) = delete;
public:
Jitterentropy(Allocator &alloc)
{
jitterentropy_init(alloc);
if (jent_entropy_init() != 0) { if (jent_entropy_init() != 0) {
Genode::error("jitterentropy library could not be initialized!"); error("jitterentropy library could not be initialized!");
} }
jent = jent_entropy_collector_alloc(0, 0); _rand_data = jent_entropy_collector_alloc(0, 0);
if (jent == nullptr) { if (_rand_data == nullptr) {
Genode::error("jitterentropy could not allocate entropy collector!"); error("jitterentropy could not allocate entropy collector!");
} }
} }
/********************
** Entropy_source **
********************/
uint64_t gen_random_u64() override
{
uint64_t result; uint64_t result;
jent_read_entropy(jent, (char*)&result, sizeof(result)); jent_read_entropy(_rand_data, (char*)&result, sizeof(result));
return result; return result;
} }
};
static Xoroshiro_128_plus &xoroshiro() static Xoroshiro_128_plus_reseeding &xoroshiro()
{ {
static Xoroshiro_128_plus xoroshiro { jitterentropy_gen_random_u64() }; static Jitterentropy jitterentropy { Lx_kit::env().heap };
static Xoroshiro_128_plus_reseeding xoroshiro { jitterentropy };
return xoroshiro; return xoroshiro;
} }
@ -119,7 +194,7 @@ void lx_emul_gen_random_bytes(void *dst,
{ {
/* validate arguments */ /* validate arguments */
if (dst == nullptr || nr_of_bytes == 0) { if (dst == nullptr || nr_of_bytes == 0) {
Genode::error("lx_emul_gen_random_bytes called with invalid args!"); error("lx_emul_gen_random_bytes called with invalid args!");
return; return;
} }
/* fill up the destination with random 64-bit values as far as possible */ /* fill up the destination with random 64-bit values as far as possible */
@ -138,7 +213,6 @@ void lx_emul_gen_random_bytes(void *dst,
} }
uint64_t const rand_u64 { xoroshiro().get_u64() }; uint64_t const rand_u64 { xoroshiro().get_u64() };
Genode::memcpy(dst_char, &rand_u64, nr_of_bytes); Genode::memcpy(dst_char, &rand_u64, nr_of_bytes);
} }