lx_emul & wireguard & wifi: centralized random.cc

Both the Wifi driver and the WireGuard port used local implementations for
their source of randomness. Wifi used a Xoroshiro128+ PRNG for rapid generation
of random values but initialized this PRNG always with the same static seed
value. WireGuard, in contrast, requested each random byte directly from the
jitterentropy lib, which is considered to be very time intensive.

This commit removes the local variants of random.cc and introduces a new
centralized lx_emul/random.cc . The new variant combines the former approaches,
so, that jitterentropy is accessed only in order to generate a random seed for
a Xoroshiro128+ PRNG. Front-end requests for random values are then fulfilled
efficiently via the PRNG.

:Warning:

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

Ref #4397
This commit is contained in:
Martin Stein 2022-05-19 16:54:36 +02:00 committed by Christian Helmuth
parent 63b0f1a2f7
commit ab0bce77ec
11 changed files with 213 additions and 189 deletions

View File

@ -19,7 +19,7 @@
void get_random_bytes(void * buf,int nbytes)
{
lx_emul_random_bytes(buf, nbytes);
lx_emul_gen_random_bytes(buf, nbytes);
}
@ -37,7 +37,7 @@ int wait_for_random_bytes(void)
u32 get_random_u32(void)
{
u8 buf[4];
lx_emul_random_bytes(buf, sizeof(buf));
lx_emul_gen_random_bytes(buf, sizeof(buf));
return *((u32*)&buf);
}
@ -47,7 +47,7 @@ u32 get_random_u32(void)
u32 prandom_u32(void)
{
u8 buf[4];
lx_emul_random_bytes(buf, sizeof(buf));
lx_emul_gen_random_bytes(buf, sizeof(buf));
return *((u32*)&buf);
}
@ -56,7 +56,7 @@ u32 prandom_u32(void)
int __must_check get_random_bytes_arch(void * buf,int nbytes)
{
lx_emul_random_bytes(buf, nbytes);
lx_emul_gen_random_bytes(buf, nbytes);
return 0;
}

View File

@ -1,27 +0,0 @@
/**
* \brief Randomness generation of lx_emul
* \author Stefan Kalkowski
* \date 2022-01-12
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LX_EMUL__RANDOM_H_
#define _LX_EMUL__RANDOM_H_
#ifdef __cplusplus
extern "C" {
#endif
void lx_emul_random_bytes(void * buf, int bytes);
#ifdef __cplusplus
}
#endif
#endif /* _LX_EMUL__RANDOM_H_ */

View File

@ -1,36 +0,0 @@
/*
* \brief Randomness backend for lx_emul
* \author Stefan Kalkowski
* \date 2022-01-12
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <base/log.h>
#include <lx_kit/env.h>
#include <lx_emul/random.h>
#include <jitterentropy.h>
extern "C" void lx_emul_random_bytes(void * buf, int bytes)
{
static rand_data * jent = nullptr;
if (!jent) {
jitterentropy_init(Lx_kit::env().heap);
if (jent_entropy_init() != 0)
Genode::error("jitterentropy library could not be initialized!");
jent = jent_entropy_collector_alloc(0, 0);
if (!jent)
Genode::error("jitterentropy could not allocate entropy collector!");
}
jent_read_entropy(jent, (char*)buf, bytes);
}

View File

@ -13,9 +13,10 @@ SRC_CC += ipv4_config.cc
SRC_CC += irq.cc
SRC_CC += main.cc
SRC_CC += nic_connection.cc
SRC_CC += random.cc
SRC_CC += lx_emul/random.cc
SRC_CC += uplink_connection.cc
vpath %.cc $(GEN_DIR)
vpath %.cc $(REP_DIR)/src/lib
CC_CXX_WARN_STRICT_CONVERSION =

View File

@ -0,0 +1,50 @@
/**
* \brief Source of randomness in lx_emul
* \author Josef Soentgen
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2022-05-19
*
* :Warning:
*
* The output of the Xoroshiro128+ PRNG that is used in the implementation of
* the lx_emul randomness functions has known statistical problems (see
* https://en.wikipedia.org/wiki/Xoroshiro128%2B#Statistical_Quality).
* Furthermore, the integration of Xoroshir128+ with the lx_emul code was not
* reviewed/audited for its security-related properties, so far, and has the
* known deficiency of seeding the PRNG only once during initialization. Thus,
* we strongly advise against the use of the lx_emul randomness functions for
* security-critical purposes.
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LX_EMUL__RANDOM_H_
#define _LX_EMUL__RANDOM_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* Write a certain number of consecutive, random byte values beginning at
* a given address.
*/
void lx_emul_gen_random_bytes(void *dst,
unsigned long nr_of_bytes);
/**
* Return a random unsigned integer value.
*/
unsigned int lx_emul_gen_random_uint(void);
#ifdef __cplusplus
}
#endif
#endif /* _LX_EMUL__RANDOM_H_ */

View File

@ -0,0 +1,148 @@
/*
* \brief Source of randomness in lx_emul
* \author Josef Soentgen
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2022-05-19
*
* :Warning:
*
* The output of the Xoroshiro128+ PRNG that is used in the implementation of
* the lx_emul randomness functions has known statistical problems (see
* https://en.wikipedia.org/wiki/Xoroshiro128%2B#Statistical_Quality).
* Furthermore, the integration of Xoroshir128+ with the lx_emul code was not
* reviewed/audited for its security-related properties, so far, and has the
* known deficiency of seeding the PRNG only once during initialization. Thus,
* we strongly advise against the use of the lx_emul randomness functions for
* security-critical purposes.
*/
/*
* Copyright (C) 2022 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* base/include */
#include <base/log.h>
#include <base/fixed_stdint.h>
#include <util/string.h>
/* dde_linux/src/include */
#include <lx_emul/random.h>
#include <lx_kit/env.h>
/* contrib/linux/src/linux/crypto */
#include <jitterentropy.h>
using namespace Genode;
/*
* Xoroshiro128+ written in 2014-2016 by Sebastiano Vigna (vigna@acm.org)
*
* (see http://xoroshiro.di.unimi.it/xorshift128plus.c and
* http://xoroshiro.di.unimi.it/splitmix64.c)
*/
class Xoroshiro_128_plus
{
private:
uint64_t _seed;
uint64_t _s[2];
uint64_t _splitmix64()
{
uint64_t z = (_seed += __UINT64_C(0x9E3779B97F4A7C15));
z = (z ^ (z >> 30)) * __UINT64_C(0xBF58476D1CE4E5B9);
z = (z ^ (z >> 27)) * __UINT64_C(0x94D049BB133111EB);
return z ^ (z >> 31);
}
static uint64_t _rotl(uint64_t const x, int k)
{
return (x << k) | (x >> (64 - k));
}
public:
Xoroshiro_128_plus(uint64_t seed) : _seed(seed)
{
_s[0] = _splitmix64();
_s[1] = _splitmix64();
}
uint64_t get_u64()
{
uint64_t const s0 = _s[0];
uint64_t s1 = _s[1];
uint64_t const result = s0 + s1;
s1 ^= s0;
_s[0] = _rotl(s0, 55) ^ s1 ^ (s1 << 14);
_s[1] = _rotl(s1, 36);
return result;
}
};
static uint64_t jitterentropy_gen_random_u64()
{
static rand_data *jent { nullptr };
if (jent == nullptr) {
jitterentropy_init(Lx_kit::env().heap);
if (jent_entropy_init() != 0) {
Genode::error("jitterentropy library could not be initialized!");
}
jent = jent_entropy_collector_alloc(0, 0);
if (jent == nullptr) {
Genode::error("jitterentropy could not allocate entropy collector!");
}
}
uint64_t result;
jent_read_entropy(jent, (char*)&result, sizeof(result));
return result;
}
static Xoroshiro_128_plus &xoroshiro()
{
static Xoroshiro_128_plus xoroshiro { jitterentropy_gen_random_u64() };
return xoroshiro;
}
void lx_emul_gen_random_bytes(void *dst,
unsigned long nr_of_bytes)
{
/* validate arguments */
if (dst == nullptr || nr_of_bytes == 0) {
Genode::error("lx_emul_gen_random_bytes called with invalid args!");
return;
}
/* fill up the destination with random 64-bit values as far as possible */
char *dst_char { reinterpret_cast<char*>(dst) };
unsigned long const nr_of_rounds { nr_of_bytes >> 3 };
for (unsigned long round_idx { 0 }; round_idx < nr_of_rounds; round_idx++) {
uint64_t const rand_u64 { xoroshiro().get_u64() };
Genode::memcpy(dst_char, &rand_u64, 8);
dst_char += 8;
}
/* fill up remaining bytes from one additional random 64-bit value */
nr_of_bytes -= (nr_of_rounds << 3);
if (nr_of_bytes == 0) {
return;
}
uint64_t const rand_u64 { xoroshiro().get_u64() };
Genode::memcpy(dst_char, &rand_u64, nr_of_bytes);
}
unsigned int lx_emul_gen_random_uint()
{
return (unsigned int)xoroshiro().get_u64();
}

View File

@ -6,13 +6,13 @@ SHARED_LIB := yes
LD_OPT += --version-script=$(TARGET_LIB_DIR)/symbol.map
LIBS += base pc_linux_generated pc_lx_emul
LIBS += base jitterentropy pc_linux_generated pc_lx_emul
INC_DIR := $(TARGET_LIB_DIR)
SRC_CC += wlan.cc
SRC_CC += misc.cc
SRC_CC += firmware.cc
SRC_CC += socket_call.cc
SRC_CC += random.cc
SRC_CC += lx_emul/random.cc
SRC_CC += time.cc
SRC_C += dummies.c

View File

@ -1,10 +1,11 @@
base
genode_c_api
jitterentropy
libc
nic_session
openssl
os
pc_linux
nic_session
platform_session
report_session
timer_session

View File

@ -14,6 +14,7 @@
#include <lx_emul.h>
#include <linux/slab.h>
#include <lx_emul/random.h>
#include <lx_emul/alloc.h>
#include <lx_emul/io_mem.h>
@ -442,7 +443,7 @@ void __put_page(struct page * page)
u32 get_random_u32(void)
{
return lx_emul_get_random_u32();
return lx_emul_gen_random_uint();
}
@ -451,7 +452,7 @@ int __must_check get_random_bytes_arch(void *buf, int nbytes)
if (nbytes < 0)
return -1;
lx_emul_get_random_bytes(buf, (unsigned long)nbytes);
lx_emul_gen_random_bytes(buf, (unsigned long)nbytes);
return 0;
}
@ -467,13 +468,13 @@ void get_random_bytes(void *buf, int nbytes)
void prandom_bytes(void *buf, size_t bytes)
{
lx_emul_get_random_bytes(buf, bytes);
lx_emul_gen_random_bytes(buf, bytes);
}
u32 prandom_u32(void)
{
return lx_emul_get_random_u32();
return lx_emul_gen_random_uint();
}

View File

@ -28,9 +28,6 @@ void lx_backtrace(void);
void lx_emul_time_udelay(unsigned long usec);
void lx_emul_get_random_bytes(void *buf, unsigned long nbytes);
unsigned int lx_emul_get_random_u32(void);
int lx_emul_rfkill_get_any(void);
void lx_emul_rfkill_switch_all(int blocked);

View File

@ -1,111 +0,0 @@
/*
* \brief Linux random emulation code
* \author Josef Soentgen
* \date 2016-10-19
*
* For all intents and purposes this random back end should be treated
* as a gloryfied counter.
*/
/*
* Copyright (C) 2016-2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/log.h>
#include <base/fixed_stdint.h>
#include <util/string.h>
using Genode::uint64_t;
/*
* Xoroshiro128+ written in 2014-2016 by Sebastiano Vigna (vigna@acm.org)
*
* (see http://xoroshiro.di.unimi.it/xorshift128plus.c and
* http://xoroshiro.di.unimi.it/splitmix64.c)
*/
struct Xoroshiro
{
uint64_t seed;
uint64_t splitmix64()
{
uint64_t z = (seed += __UINT64_C(0x9E3779B97F4A7C15));
z = (z ^ (z >> 30)) * __UINT64_C(0xBF58476D1CE4E5B9);
z = (z ^ (z >> 27)) * __UINT64_C(0x94D049BB133111EB);
return z ^ (z >> 31);
}
Xoroshiro(uint64_t seed) : seed(seed)
{
s[0] = splitmix64();
s[1] = splitmix64();
}
uint64_t s[2];
static uint64_t rotl(uint64_t const x, int k) {
return (x << k) | (x >> (64 - k));
}
uint64_t get()
{
uint64_t const s0 = s[0];
uint64_t s1 = s[1];
uint64_t const result = s0 + s1;
s1 ^= s0;
s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14);
s[1] = rotl(s1, 36);
return result;
}
};
static Xoroshiro &xoroshiro()
{
static Xoroshiro inst(0x636864324d766931);
return inst;
}
/********************
** linux/random.h **
********************/
extern "C" void lx_emul_get_random_bytes(void *buf, unsigned long nbytes)
{
if (!buf || !nbytes)
return;
char *p = reinterpret_cast<char*>(buf);
unsigned long const rounds = nbytes / 8;
for (unsigned long i = 0; i < rounds; i++) {
uint64_t const v = xoroshiro().get();
Genode::memcpy(p, &v, 8);
p += 8;
}
unsigned long const remain = nbytes - rounds * 8;
if (!remain) {
return;
}
uint64_t const v = xoroshiro().get();
Genode::memcpy(p, &v, remain);
}
extern "C" unsigned int lx_emul_get_random_u32(void)
{
return (unsigned int)xoroshiro().get();
}