sys/entropy_source: add new module for entropy sources

This commit is contained in:
PeterKietzmann 2020-06-19 17:04:00 +02:00
parent c337089de5
commit aec75b55fe
19 changed files with 1244 additions and 0 deletions

View File

@ -12,6 +12,7 @@ rsource "benchmark/Kconfig"
rsource "color/Kconfig"
rsource "div/Kconfig"
rsource "embunit/Kconfig"
rsource "entropy_source/Kconfig"
rsource "event/Kconfig"
rsource "fmt/Kconfig"
rsource "isrpipe/Kconfig"

View File

@ -706,6 +706,13 @@ ifneq (,$(filter conn_can,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter entropy_source_%,$(USEMODULE)))
USEMODULE += entropy_source
ifneq (,$(filter entropy_source_adc_noise,$(USEMODULE)))
FEATURES_REQUIRED += periph_adc
endif
endif
ifneq (,$(filter puf_sram,$(USEMODULE)))
USEMODULE += hashes
USEMODULE += random

View File

@ -0,0 +1,37 @@
# Copyright (c) 2020 HAW Hamburg
#
# 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.
menuconfig KCONFIG_USEMODULE_ENTROPY_SOURCE
bool "Configure entropy sources"
depends on USEMODULE_ENTROPY_SOURCE_ADC_NOISE || USEMODULE_ENTROPY_SOURCE_ZERO_ENTROPY
help
Configure entropy sources using Kconfig.
if KCONFIG_USEMODULE_ENTROPY_SOURCE
config ENTROPY_SOURCE_TESTS_WIN
int "Window size for Adaptive Proportion Test"
default 512
depends on ENTROPY_SOURCE_ADC_HEALTH_TEST || ENTROPY_SOURCE_ZERO_HEALTH_TEST
help
In (NIST SP 800-90B 4.4.2) a window size of 512 samples is recommended for non-binary
sources. Typically, RIOT use cases will not request as many samples, thus, it might be worth
considering a smaller window size so the test is more likely to complete a cycle. It is
noteworthy that a cutoff value calculated by @ref entropy_source_test_prop_cutoff that is
greater than the window size may lead to undetected errors.
config ENTROPY_SOURCE_NEUMANN_ABORT
int "Abort factor for von Neumann extractor"
default 5
help
Abort factor for von Neumann extractor. The algorithms runs as long as no bit
changes appear in subsequent samples. This define adds a factor that
aborts the procedure after (factor * requested length) samples.
rsource "adc_noise/Kconfig"
rsource "zero_entropy/Kconfig"
endif # KCONFIG_USEMODULE_ENTROPY_SOURCE

View File

@ -0,0 +1,9 @@
ifneq (,$(filter entropy_source_zero_entropy,$(USEMODULE)))
DIRS += zero_entropy
endif
ifneq (,$(filter entropy_source_adc_noise,$(USEMODULE)))
DIRS += adc_noise
endif
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,77 @@
# Copyright (c) 2020 HAW Hamburg
#
# 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.
menuconfig KCONFIG_USEMODULE_ENTROPY_SOURCE_ADC_NOISE
bool "Configure ADC Noise entropy source module"
depends on USEMODULE_ENTROPY_SOURCE_ADC_NOISE
help
Configure the ADC Noise entropy source using Kconfig.
if KCONFIG_USEMODULE_ENTROPY_SOURCE_ADC_NOISE
choice
bool "ADC default sampling resolution"
default ENTROPY_SOURCE_ADC_RES_10BIT
help
This parameter sets the ADC sampling resolution. Please note that not all
platforms support every value.
config ENTROPY_SOURCE_ADC_RES_6BIT
bool "6 Bit"
config ENTROPY_SOURCE_ADC_RES_8BIT
bool "8 Bit"
config ENTROPY_SOURCE_ADC_RES_10BIT
bool "10 Bit"
config ENTROPY_SOURCE_ADC_RES_12BIT
bool "12 Bit"
config ENTROPY_SOURCE_ADC_RES_14BIT
bool "14 Bit"
config ENTROPY_SOURCE_ADC_RES_16BIT
bool "16 Bit"
endchoice
config ENTROPY_SOURCE_ADC_LINE_NUM
int "ADC line"
range 0 16
default 0
help
The ADC line maps to an I/O pin. This number acts as index to an array
of predefined ADC devices that contain the pin definition. Typically,
the array is defined by a board in a periph_conf.h file. Please note that
a board is not required to specify a minimum number of lines.
config ENTROPY_SOURCE_ADC_HMIN
int "Estimated entropy per sample [2^16 * bit/sample]"
range 1 524288
default 0
help
The entropy value needs to be estimated and evaluated thoroughly before
deployment! To avoid float, the entropy value per one byte sample needs
to be manually multiplied by 2^16 before configuring it (e.g., to
an entropy value of 1 bit/sample, a value of 1 * 65536 needs to be set) .
We default to zero which is an invalid configuration to enforce a
thoughtful investigation on the actual entropy properties.
config ENTROPY_SOURCE_ADC_HEALTH_TEST
bool "Enable health test"
help
Health tests are performed on every sample, if enabled. Thus, they
slow down the entropy gathering process. Detected failures are reported by return
value but they do not stop execution.
config ENTROPY_SOURCE_ADC_COND
bool "Enable conditioning"
help
Conditioning increases runtime of the entropy generation process. Currently, a von
Neumann extractor is involved which has an nondeterministic runtime.
endif # KCONFIG_USEMODULE_ENTROPY_SOURCE_ADC_NOISE

View File

@ -0,0 +1,3 @@
MODULE := entropy_source_adc_noise
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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.
*/
/**
* @ingroup sys_entropy_source_adc
*
* @{
* @file
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
*
* @}
*/
#include "periph/adc.h"
#include "entropy_source.h"
#include "entropy_source/adc_noise.h"
entropy_source_tests_rep_t adc_state_rep;
entropy_source_tests_prop_t adc_state_prop;
static int _get_sample(uint8_t *out)
{
int ret = ENTROPY_SOURCE_OK;
uint8_t byte = 0;
for (unsigned bit = 0; bit < 8; bit++) {
int sample = adc_sample(CONFIG_ENTROPY_SOURCE_ADC_LINE,
CONFIG_ENTROPY_SOURCE_ADC_RES);
if (sample < 0) {
/* Resolution is not applicable */
return ENTROPY_SOURCE_ERR_CONFIG;
}
/* use LSB of each ADC sample and shift it to build a value */
byte |= (uint8_t)(sample & 0x01) << bit;
}
/* copy generated byte to out */
*out = byte;
if (IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ADC_HEALTH_TEST)) {
ret = entropy_source_test(&adc_state_rep, &adc_state_prop, byte);
}
return ret;
}
int entropy_source_adc_init(void)
{
/* init ADC */
if (adc_init(CONFIG_ENTROPY_SOURCE_ADC_LINE) != 0) {
return ENTROPY_SOURCE_ERR_INIT;
}
if (IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ADC_HEALTH_TEST)) {
unsigned int cutoff;
cutoff = entropy_source_test_rep_cutoff(CONFIG_ENTROPY_SOURCE_ADC_HMIN);
entropy_source_test_rep_init(&adc_state_rep, cutoff);
cutoff = entropy_source_test_prop_cutoff(CONFIG_ENTROPY_SOURCE_ADC_HMIN);
entropy_source_test_prop_init(&adc_state_prop, cutoff);
}
return ENTROPY_SOURCE_OK;
}
int entropy_source_adc_get(uint8_t *out, size_t len)
{
assert(out != NULL);
int ret = ENTROPY_SOURCE_OK;
if (IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ADC_COND)) {
entropy_source_sample_func_t p = &_get_sample;
ret = entropy_source_neumann_unbias(p, out, len);
}
else {
for (unsigned iter = 0; iter < len; iter++) {
int tmp = _get_sample(&out[iter]);
/* Remember the worst failure during
* sampling multiple values to return */
if (tmp < ret) {
ret = tmp;
}
}
}
return ret;
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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.
*/
/**
* @defgroup sys_entropy_source Entropy Sources
* @ingroup sys
* @brief Collection of different Entropy Sources
* @warning Entropy sources need to be thoroughly evaluated before deployment!
* @experimental This API is in an early state - expect changes.
* @note This API is considered as internal. Only use it if you know what
* you are doing and expect API changes without deprecation.
*
*
* @brief Collection of entropy sources.
*
*
* This module adds support for additional entropy sources next to pure peripheral sources like
* @ref drivers_periph_hwrng and @ref sys_puf_sram. The concepts implemented here are heavily
* influenced by NIST SP 800-90B. Entropy sources can be used to feed more advanced entropy
* modules for cryptographic purposes, which typically accumulate multiple sources and safely
* maintain internal sates. Alternatively, these sources can be used directly or with internal
* conditioning enabled for non-cryptographic tasks like seed generation of general purpose PRNGs,
* in the absence of a hardware random number generator. The API, however, is not meant to face a user.
*
* A common component provides optional access to health tests and conditioning
* (@ref sys_entropy_source_config) that can be run on
* parallel instantiations. The conditioning currently implements a von Neumann extractor to
* unbias samples. It adds a variable runtime (dependent on the input samples) but is lightweight.
* In future, other conditioning mechanisms such as hash based derivation functions might be
* included.
*
* Entropy sources require thorough testing and evaluation for serious deployments which is out of
* scope of this module, and we refer to <a href="https://github.com/usnistgov/
* SP800-90B_EntropyAssessment">SP800-90B_EntropyAssessment</a> for validation. Among other metrics,
* this tool will return an entropy estimation per sample that should be employed for every
* deployment scenario and must be configured in software accordingly. In the specific case
* of the ADC based entropy source, a developer needs to set @ref CONFIG_ENTROPY_SOURCE_ADC_HMIN
* accordingly.
*
*/

View File

@ -0,0 +1,125 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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.
*/
/**
* @ingroup sys_entropy_source_common
*
* @{
* @file
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include "entropy_source.h"
int entropy_source_neumann_unbias(entropy_source_sample_func_t func,
uint8_t *out, size_t len)
{
assert(func != NULL && out != NULL);
uint8_t old_sample, new_sample, sample_out = 0;
uint8_t bit1, bit2, bit_pos = 0;
size_t bytes_count = 0;
size_t sample_count = 0;
size_t abort = len * CONFIG_ENTROPY_SOURCE_NEUMANN_ABORT;
int tmp, ret = ENTROPY_SOURCE_OK;
/* Get initial sample */
tmp = func(&old_sample);
/* Only return in case of failed configuration */
if (ret == ENTROPY_SOURCE_ERR_CONFIG) {
return ret;
}
while (bytes_count < len) {
/* Increment sample counter and abort if
* exceeds maximum number of iterations */
sample_count++;
if (sample_count > abort) {
return ENTROPY_SOURCE_ERR_COND;
}
/* Get next sample */
tmp = func(&new_sample);
/* Remember the worst failure during
* sampling multiple values to return */
if (tmp < ret) {
ret = tmp;
}
/* Iterate each bit in sample */
for (unsigned j = 0; j < 8; j++) {
bit1 = (1 << j) & old_sample;
bit2 = (1 << j) & new_sample;
/* Only save information if change occurred
* 0/1 change results in 1
* 1/0 change results in 0
*/
if (bit1 < bit2) {
sample_out |= (1 << bit_pos++);
}
else if (bit1 > bit2) {
sample_out &= ~(1 << bit_pos++);
}
/* Once 8 bits have been gathered, write to output */
if (bit_pos == 8) {
out[bytes_count] = sample_out;
bit_pos = 0;
bytes_count++;
}
}
/* Store recent sample for next iteration */
old_sample = new_sample;
}
return ret;
}
int entropy_source_test_rep(entropy_source_tests_rep_t *state, uint8_t sample)
{
assert(state != NULL);
if (sample == state->old_sample && state->cnt_rep > 0) {
state->cnt_rep++;
if (state->cnt_rep >= state->c_rep) {
return ENTROPY_SOURCE_ERR_TEST_REP;
}
}
else {
state->old_sample = sample;
state->cnt_rep = 1;
}
return ENTROPY_SOURCE_OK;
}
int entropy_source_test_prop(entropy_source_tests_prop_t *state, uint8_t sample)
{
assert(state != NULL);
if (state->cnt_window == CONFIG_ENTROPY_SOURCE_TESTS_WIN) {
state->old_sample = sample;
state->cnt_prop = 0;
state->cnt_window = 0;
}
else {
state->cnt_window++;
if (state->old_sample == sample) {
state->cnt_prop++;
}
if (state->cnt_prop >= state->c_prop) {
return ENTROPY_SOURCE_ERR_TEST_PROP;
}
}
return ENTROPY_SOURCE_OK;
}

View File

@ -0,0 +1,35 @@
# Copyright (c) 2020 HAW Hamburg
#
# 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.
menuconfig KCONFIG_USEMODULE_ENTROPY_SOURCE_ZERO_ENTROPY
bool "Configure zero entropy source module"
depends on USEMODULE_ENTROPY_SOURCE_ZERO_ENTROPY
help
Configure the zero entropy source using Kconfig.
if KCONFIG_USEMODULE_ENTROPY_SOURCE_ZERO_ENTROPY
config ENTROPY_SOURCE_ZERO_HMIN
int "Estimated entropy per sample (byte)"
default 58982
help
This is a dummy default value for testing. The zero entropy module does not
contain any entropy at all.
config ENTROPY_SOURCE_ZERO_HEALTH_TEST
bool "Enable health test"
default y
help
Enable health test by default. Testing is the only purpose of this module.
config ENTROPY_SOURCE_ZERO_COND
bool "Enable conditioning"
help
Disable conditioning by default. Conditioning is useless for zeros only. The von
Neumann extractor would never finish and wait for the stop criterion given by
@ref CONFIG_ENTROPY_SOURCE_NEUMANN_ABORT.
endif # KCONFIG_USEMODULE_ENTROPY_SOURCE_ZERO_ENTROPY

View File

@ -0,0 +1,3 @@
MODULE := entropy_source_zero_entropy
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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.
*/
/**
* @ingroup sys_entropy_source_zero
* @{
* @file
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
*
* @}
*/
#include "kernel_defines.h"
#include "entropy_source.h"
#include "entropy_source/zero_entropy.h"
entropy_source_tests_rep_t zero_state_rep;
entropy_source_tests_prop_t zero_state_prop;
static int _get_sample(uint8_t *out)
{
int ret = ENTROPY_SOURCE_OK;
uint8_t byte = 0;
*out = byte;
if (IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ZERO_HEALTH_TEST)) {
ret = entropy_source_test(&zero_state_rep, &zero_state_prop, byte);
}
return ret;
}
int entropy_source_zero_init(void)
{
if (IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ZERO_HEALTH_TEST)) {
unsigned int cutoff;
cutoff = entropy_source_test_rep_cutoff(CONFIG_ENTROPY_SOURCE_ZERO_HMIN);
entropy_source_test_rep_init(&zero_state_rep, cutoff);
cutoff = entropy_source_test_prop_cutoff(CONFIG_ENTROPY_SOURCE_ZERO_HMIN);
entropy_source_test_prop_init(&zero_state_prop, cutoff);
}
return ENTROPY_SOURCE_OK;
}
int entropy_source_zero_get(uint8_t *out, size_t len)
{
assert(out != NULL);
int ret = ENTROPY_SOURCE_OK;
if (IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ZERO_COND)) {
ret = entropy_source_neumann_unbias(_get_sample, out, len);
}
else {
for (unsigned iter = 0; iter < len; iter++) {
int tmp = _get_sample(&out[iter]);
/* Remember the worst failure during
* sampling multiple values to return */
if (tmp < ret) {
ret = tmp;
}
}
}
return ret;
}

View File

@ -0,0 +1,306 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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.
*/
/**
* @defgroup sys_entropy_source_common Entropy Source Common
* @ingroup sys_entropy_source
* @brief Common definitions and functions for entropy sources
*
*
* @{
* @file
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
*/
#ifndef ENTROPY_SOURCE_H
#define ENTROPY_SOURCE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <inttypes.h>
#include <assert.h>
/**
* @brief Entropy source error codes.
*/
typedef enum {
ENTROPY_SOURCE_OK = 0, /**< Success */
ENTROPY_SOURCE_ERR_INIT = -1, /**< Source initialization error */
ENTROPY_SOURCE_ERR_CONFIG = -2, /**< Source configuration error */
ENTROPY_SOURCE_ERR_TEST_REP = -3, /**< Repetition count test error */
ENTROPY_SOURCE_ERR_TEST_PROP = -4, /**< Adaptive proportion test error */
ENTROPY_SOURCE_ERR_TEST_BOTH = -5, /**< Repetition count and Adaptive
* proportion test error */
ENTROPY_SOURCE_ERR_COND = -6, /**< Conditioning error */
} entropy_source_error_t;
/**
* @brief Data structure for Repetition Count Test (NIST SP 800-90B 4.4.1).
*/
typedef struct {
uint8_t old_sample; /**< Preceding sample to compare for repetition */
uint16_t cnt_rep; /**< Counter to count repetition */
uint8_t c_rep; /**< Cutoff threshold */
} entropy_source_tests_rep_t;
/**
* @brief Data structure for Adaptive Proportion Test (NIST SP 800-90B 4.4.2).
*/
typedef struct {
uint8_t old_sample; /**< Preceding sample to compare for repetition */
uint16_t cnt_prop; /**< Counter to count proportion */
uint16_t cnt_window; /**< Counter to count window size */
uint16_t c_prop; /**< Cutoff threshold */
} entropy_source_tests_prop_t;
/**
* @brief Scale Min. Entropy to fixed point integer to avoid float. The
* entropy per sample (8 Byte) of a noise source can likely be smaller
* than 1 bit.
*/
#define ENTROPY_SOURCE_HMIN_SCALE(x) ((x * (1UL << 16)))
/**
* @brief Scale internal fixed point Min. Entropy back to float. This macro is
* not required and only there for convenience.
*/
#define ENTROPY_SOURCE_HMIN_SCALE_BACK(x) ((float)x / (1UL << 16))
/**
* @defgroup sys_entropy_source_config Entropy Source compile configurations
* @ingroup config
* @{
*/
/**
* @brief Window size for Adaptive Proportion Test (NIST SP 800-90B 4.4.2).
*
* In (NIST SP 800-90B 4.4.2) a window size of 512 samples is recommended for
* non-binary sources. Typically, RIOT use cases will not request as many
* samples, thus, it might be worth considering a smaller window size so the
* test is more likely to complete a cycle. It is noteworthy that a cutoff value
* calculated by @ref entropy_source_test_prop_cutoff that is greater than the
* window size may lead to undetected errors.
*/
#ifndef CONFIG_ENTROPY_SOURCE_TESTS_WIN
#define CONFIG_ENTROPY_SOURCE_TESTS_WIN (512)
#endif
/**
* @brief Abort factor for von Neumann extractor. The algorithms runs as long
* as no bit changes appear in subsequent samples. This define adds a
* factor that aborts the procedure after (factor * requested length)
* samples.
*/
#ifndef CONFIG_ENTROPY_SOURCE_NEUMANN_ABORT
#define CONFIG_ENTROPY_SOURCE_NEUMANN_ABORT (5)
#endif
/** @} */
/**
* @brief Get one sample of the entropy source.
*
* This function is typically used by the entropy source internally. A
* conditioning component might need an interface to request a variable number
* of samples, e.g., depending on the contained amount of entropy.
*
* @param[out] sample pointer to write sample to.
*
* @return ENTROPY_SOURCE_OK on success
* @return negative @ref entropy_source_error_t code on error
*/
typedef int (*entropy_source_sample_func_t)(uint8_t *sample);
/**
* @brief Applies von Neumann unbiasing.
*
* This function requests as many samples needed to create \p len unbiased bytes
* using \p func. The algorithm compares bits of consecutive samples. Only bit
* changes will be considered for the output value. An abort criterium stops
* sampling after (len * CONFIG_ENTROPY_SOURCE_NEUMANN_ABORT) iterations.
*
* @warning This function has a non-deterministic runtime.
*
* @param[in] func pointer to @ref entropy_source_sample_func_t function
that returns samples
* @param[out] out pointer to write unbiased bytes to
* @param[in] len number of bytes to generate
*
* @return ENTROPY_SOURCE_OK on success
* @return negative @ref entropy_source_error_t code on error
*/
int entropy_source_neumann_unbias(entropy_source_sample_func_t func,
uint8_t *out, size_t len);
/**
* @brief Calculate cutoff value for Repetition Count Test (NIST SP 800-90B 4.4.1)
*
*~~~~
* C = 1 + ( (-log2 a) / H)
*~~~~
*
* C: Cutoff value.
* H: Min. entropy of the source
* <a href="https://github.com/usnistgov/SP800-90B_EntropyAssessment">
* SP800-90B EntropyAssessment</a>.
* a: Probability of type I error. We assume 2^(-20).
*
* @param[in] entropy_per_sample Estimated min. entropy of one sample scaled
* by ENTROPY_SOURCE_HMIN_SCALE()
*
* @return Cutoff threshold
*/
static inline uint32_t entropy_source_test_rep_cutoff(uint32_t entropy_per_sample)
{
return (1 + ((20 * 65536) / entropy_per_sample));
}
/**
* @brief Calculate cutoff value for Adaptive Proportion Test
* (NIST SP 800-90B 4.4.2)
*
* @param[in] entropy_per_sample Estimated min. entropy of one sample scaled
* by ENTROPY_SOURCE_HMIN_SCALE()
*
* @return Cutoff value
* @return ENTROPY_SOURCE_ERR_CONFIG if parameter
invalid
*/
static inline int entropy_source_test_prop_cutoff(uint32_t entropy_per_sample)
{
int ret;
if (entropy_per_sample < 49152UL) { /* 0.75 bit/sample */
ret = 410;
}
else if (entropy_per_sample < 98304UL) { /* 1.5 bit/sample */
ret = 311;
}
else if (entropy_per_sample < 196608UL) { /* 3 bit/sample */
ret = 177;
}
else if (entropy_per_sample < 393216UL) { /* 6 bit/sample */
ret = 62;
}
else if (entropy_per_sample <= 524288UL) { /* 8 bit/sample */
ret = 13;
}
else {
ret = ENTROPY_SOURCE_ERR_CONFIG;
}
return ret;
}
/**
* @brief Initialize structure for Repetition Count Test
*
* @param[in, out] state Test structure of one entropy source.
* @param[in] c_rep Cutoff value calculated by
* @ref entropy_source_test_rep_cutoff.
*/
static inline void entropy_source_test_rep_init(
entropy_source_tests_rep_t *state, uint16_t c_rep)
{
assert(state != NULL);
state->old_sample = 0;
state->cnt_rep = 0;
state->c_rep = c_rep;
}
/**
* @brief Initialize structure for Adaptive Proportion Test
*
* @param[in, out] state Test structure of one entropy source.
* @param[in] c_prop Cutoff value calculated by
* @ref entropy_source_test_prop_cutoff.
*/
static inline void entropy_source_test_prop_init(
entropy_source_tests_prop_t *state, uint16_t c_prop)
{
assert(state != NULL);
state->old_sample = 0;
state->cnt_prop = 0;
state->cnt_window = CONFIG_ENTROPY_SOURCE_TESTS_WIN;
state->c_prop = c_prop;
}
/**
* @brief Performs Repetition Count Test (NIST SP 800-90B 4.4.1).
*
* This function will not block sampling. It only indicates detected errors.
*
* @param[in, out] state Test structure of one entropy source.
* @param[in] sample Current sample.
*
* @return ENTROPY_SOURCE_OK on success
* @return ENTROPY_SOURCE_ERR_TEST_REP on detected weakness
*/
int entropy_source_test_rep(entropy_source_tests_rep_t *state, uint8_t sample);
/**
* @brief Performs Adaptive Proportion Test (NIST SP 800-90B 4.4.2).
*
* This function will not block the sampling. It only indicates detected errors.
*
* @param[in, out] state Test structure of one entropy source.
* @param[in] sample current sample.
*
* @return ENTROPY_SOURCE_OK on success
* @return ENTROPY_SOURCE_ERR_TEST_PROP on detected weakness
*/
int entropy_source_test_prop(entropy_source_tests_prop_t *state,
uint8_t sample);
/**
* @brief Convenience function to perform @ref entropy_source_test_rep
* and @ref entropy_source_test_prop.
*
* This function will not block the sampling. It only indicates detected errors.
*
* @param[in, out] state_rep Repetition Count test structure of one
* entropy source.
* @param[in, out] state_prop Adaptive Proportion test structure of one
* entropy source.
* @param[in] sample Current sample.
*
* @return ENTROPY_SOURCE_OK on success
* @return negative @ref entropy_source_error_t code on error
*/
static inline int entropy_source_test(entropy_source_tests_rep_t *state_rep,
entropy_source_tests_prop_t *state_prop,
uint8_t sample)
{
int ret = ENTROPY_SOURCE_OK;
if (entropy_source_test_rep(state_rep, sample) < 0) {
ret = ENTROPY_SOURCE_ERR_TEST_REP;
}
if (entropy_source_test_prop(state_prop, sample) < 0) {
/* If repetition count failed before, indicate that both tests failed */
if (ret == ENTROPY_SOURCE_ERR_TEST_REP) {
ret = ENTROPY_SOURCE_ERR_TEST_BOTH;
}
else {
ret = ENTROPY_SOURCE_ERR_TEST_PROP;
}
}
return ret;
}
#ifdef __cplusplus
}
#endif
#endif /* ENTROPY_SOURCE_H */
/** @} */

View File

@ -0,0 +1,158 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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.
*/
/**
* @defgroup sys_entropy_source_adc ADC Noise Entropy Source
* @ingroup sys_entropy_source
* @brief Entropy Source based on LSB of ADC samples
*
*
* This module provides entropy from ADC samples. Thereby, only the LSB is considered for
* generation of output values. The available resolution as well as internal sampling rates,
* specific driver settings and device inaccuracies may lead to different behavior between
* different platforms. The configured ADC pin might be unconnected and floating,
* it can be exposed as an I/O pin or internally connected to a thermal noise source, an
* avalanche diode circuit or the receive path of an antenna. The possibilities are manifold,
* thus, configuration and deployment properties of this module need to be thoroughly
* validated.
*
* @note It is worth noting that ADC pins are typically vulnerable when physically
* accessible. Developers should consider additional tamper detection concepts
* and enclosures.
*
* @{
* @file
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
*/
#ifndef ENTROPY_SOURCE_ADC_NOISE_H
#define ENTROPY_SOURCE_ADC_NOISE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
#include <stddef.h>
#include "periph/adc.h"
/**
* @ingroup sys_entropy_source_config
* @{
*/
/**
* @brief ADC resolution default configuration.
*/
#if IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ADC_RES_6BIT)
#define CONFIG_ENTROPY_SOURCE_ADC_RES ADC_RES_6BIT
#elif IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ADC_RES_8BIT)
#define CONFIG_ENTROPY_SOURCE_ADC_RES ADC_RES_8BIT
#elif IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ADC_RES_10BIT)
#define CONFIG_ENTROPY_SOURCE_ADC_RES ADC_RES_10BIT
#elif IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ADC_RES_12BIT)
#define CONFIG_ENTROPY_SOURCE_ADC_RES ADC_RES_12BIT
#elif IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ADC_RES_14BIT)
#define CONFIG_ENTROPY_SOURCE_ADC_RES ADC_RES_14BIT
#elif IS_ACTIVE(CONFIG_ENTROPY_SOURCE_ADC_RES_16BIT)
#define CONFIG_ENTROPY_SOURCE_ADC_RES ADC_RES_16BIT
#endif
#ifndef CONFIG_ENTROPY_SOURCE_ADC_RES
#define CONFIG_ENTROPY_SOURCE_ADC_RES ADC_RES_10BIT
#endif
/**
* @brief ADC line default configuration.
*
* The ADC line maps to an I/O pin. This number acts as index to an array
* of predefined ADC devices that contain the pin definition. Typically,
* the array is defined by a board in a periph_conf.h file. Please note that
* a board is not required to specify a minimum number of lines.
*/
#ifdef CONFIG_ENTROPY_SOURCE_ADC_LINE_NUM
#define CONFIG_ENTROPY_SOURCE_ADC_LINE ADC_LINE(CONFIG_ENTROPY_SOURCE_ADC_LINE_NUM)
#else
#define CONFIG_ENTROPY_SOURCE_ADC_LINE ADC_LINE(0)
#endif
/**
* @brief ADC estimated entropy per sample [2^16 * bit/sample].
*
* The entropy value needs to be estimated and evaluated thoroughly beforehand
* deployment! To avoid float, the
* actual entropy value per one byte sample needs to be manually multiplied by
* 2^16 before before configuring it (e.g., to
* an entropy value of 1 bit/sample, a value of 1 * 65536 needs to be set) .
* We default to zero which is an invalid configuration to enforce a
* thoughtful investigation on the actual entropy properties. See
* @ref sys_entropy_source for further information about entropy source
* validation.
*/
#if !defined(CONFIG_KCONFIG_USEMODULE_ENTROPY_SOURCE_ADC_NOISE) || defined(DOXYGEN)
#ifndef CONFIG_ENTROPY_SOURCE_ADC_HMIN
#define CONFIG_ENTROPY_SOURCE_ADC_HMIN (0) /**< H_min=0 bit/sample * 2^16
* is invalid and needs to
* set manually!
*/
#endif /* !CONFIG_ENTROPY_SOURCE_ADC_HMIN */
#ifndef CONFIG_ENTROPY_SOURCE_ADC_HEALTH_TEST
#define CONFIG_ENTROPY_SOURCE_ADC_HEALTH_TEST 0 /**< Disable ADC health test
* by default.
*/
#endif
#ifndef CONFIG_ENTROPY_SOURCE_ADC_COND
#define CONFIG_ENTROPY_SOURCE_ADC_COND 0 /**< Disable ADC conditioning
* test by default.
*/
#endif
#endif /* !CONFIG_KCONFIG_USEMODULE_ENTROPY_SOURCE_ADC_NOISE || DOXYGEN */
/* Throw warning if H_min has not been re-configured */
#if !CONFIG_ENTROPY_SOURCE_ADC_HMIN
#warning The min. provided entropy must be set before using this module
#endif
/** @} */
/**
* @brief Initialize ADC and test structures, if tests are enabled.
*
* @return ENTROPY_SOURCE_OK on success
* @return ENTROPY_SOURCE_ERR_INIT on ADC initialization failure
*/
int entropy_source_adc_init(void);
/**
* @brief Generates bytes from ADC noise
*
* @param[out] buf pointer to write noisy bytes to
* @param[in] len number of bytes to generate
*
* @return ENTROPY_SOURCE_OK on success
* @return negative @ref entropy_source_error_t code on error
*/
int entropy_source_adc_get(uint8_t *buf, size_t len);
/**
* @brief Static entropy per sample value for this source
* [bit/sample * 2^16]
*
* @return entropy per sample
*/
static inline uint32_t entropy_source_adc_entropy_per_sample(void)
{
return CONFIG_ENTROPY_SOURCE_ADC_HMIN;
}
#ifdef __cplusplus
}
#endif
#endif /* ENTROPY_SOURCE_ADC_NOISE_H */
/** @} */

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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.
*/
/**
* @defgroup sys_entropy_source_zero Zero Entropy Source
* @ingroup sys_entropy_source
* @brief Zero Entropy Source for testing.
*
* This module produces zeros only and should be used for testing purposes only.
*
* @{
* @file
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
*/
#ifndef ENTROPY_SOURCE_ZERO_ENTROPY_H
#define ENTROPY_SOURCE_ZERO_ENTROPY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
#include <stddef.h>
/**
* @ingroup sys_entropy_source_config
* @{
*/
/**
* @brief Min. Entropy value for zero entropy module.
*
* H_min=0.9 bit/sample * 2^16 fake for testing!
*/
#if !defined(CONFIG_KCONFIG_USEMODULE_ENTROPY_SOURCE_ZERO_ENTROPY) || defined(DOXYGEN)
#ifndef CONFIG_ENTROPY_SOURCE_ZERO_ENTROPY_HMIN
#define CONFIG_ENTROPY_SOURCE_ZERO_HMIN (58982)
#endif
/**
* @brief Enable health test by default.
*
* Testing is the only purpose of this module.
*/
#ifndef CONFIG_ENTROPY_SOURCE_ZERO_HEALTH_TEST
#define CONFIG_ENTROPY_SOURCE_ZERO_HEALTH_TEST 1
#endif
/**
* @brief Disable conditioning by default.
*
* Conditioning is useless for zeros only. The von Neumann extractor would
* never finish and wait for the stop criterion given by
* @ref CONFIG_ENTROPY_SOURCE_NEUMANN_ABORT.
*/
#ifndef CONFIG_ENTROPY_SOURCE_ZERO_COND
#define CONFIG_ENTROPY_SOURCE_ZERO_COND 0
#endif
#endif /* !CONFIG_KCONFIG_USEMODULE_ENTROPY_SOURCE_ZERO_ENTROPY || DOXYGEN */
/** @} */
/**
* @brief Initializes test structures, if tests are enabled.
*
* @return ENTROPY_SOURCE_OK always
*/
int entropy_source_zero_init(void);
/**
* @brief Generates zeros.
*
* @param[out] buf pointer to write zeros to
* @param[in] len number of bytes to generate
*
* @return ENTROPY_SOURCE_OK on success
* @return negative @ref entropy_source_error_t code on error
*/
int entropy_source_zero_get(uint8_t *buf, size_t len);
#ifdef __cplusplus
}
#endif
#endif /* ENTROPY_SOURCE_ZERO_ENTROPY_H */
/** @} */

View File

@ -0,0 +1,10 @@
DEVELHELP ?= 0
include ../Makefile.tests_common
BOARD ?= native
USEMODULE += fmt
USEMODULE += entropy_source_zero_entropy
USEMODULE += xtimer
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,13 @@
# Only include adc noise source if BOARD has an adc
FEATURES_OPTIONAL += periph_adc
ifneq (,$(filter periph_adc,$(FEATURES_USED)))
USEMODULE += entropy_source_adc_noise
ifndef CONFIG_KCONFIG_USEMODULE_ENTROPY_SOURCE_ADC_NOISE
# set a dummy default value for the provided amount of entropy
CFLAGS += -DCONFIG_ENTROPY_SOURCE_ADC_HMIN=65536
# enable ADC health tests and conditioning
CFLAGS += -DCONFIG_ENTROPY_SOURCE_ADC_COND=1
CFLAGS += -DCONFIG_ENTROPY_SOURCE_ADC_HEALTH_TEST=1
endif
endif

View File

@ -0,0 +1,62 @@
# About
This test compiles and runs entropy sources. The first `zero entropy` source can be run on
`native` and does not provide real entropy values, though, it tests execution of the main
module and its common components including the optional health tests. Additional sources are
requested subsequently. As indicated in the documentation of the [entropy module](../../sys/entropy_source/doc.txt),
entropy is vulnerable and specific hardware sources require a priori validation.
The `ADC noise` source requires the `periph_adc` feature of a board. Its properties can vary widely as
depicted in the documentation of the [`ADC noise`](../../sys/include/entropy_source/adc_noise.h)
modules and proper testing and parametrization need to take place for every single platform and ideally
environmental properties before deployment. The test simply initializes the ADC noise entropy source
with the default ADC pin, requests and dumps many samples with enabled health tests of the source and
conditioning.
# Expected results
The `zero entropy` is expected to indicate different errors after requesting more samples than
the cutoff value of the Repetition Count Test (NIST SP 800-90B 4.4.1) and the Adaptive
Proportion Test (NIST SP 800-90B 4.4.2). The expected output is:
## native
```
# main(): This is RIOT! (Version: <version>)
# Zero entropy single request 0/311 returned: 0
...
# Zero entropy single request 20/311 returned: -3
...
# Zero entropy single request 310/311 returned: -3
# Zero entropy single request 311/311 returned: -5
# Zero entropy request 64 Bytes: -5
```
## Board
The `ADC noise` source test should dump unpredictable values. The *von Neumann* conditioning internally
requests multiple samples so that subsequent values include bit changes. Thus, it has
a variable runtime. To explore this, one test requests a buffer with entropy values
and it measures the processing time. If no changes are in place, the conditioning function
will abort after exceeding a threshold.
Otherwise, no health test errors should be indicated. Please note that
missing errors do **not** reveal information about the quality of an entropy source.
```
# main(): This is RIOT! (Version: <version>)
# Zero entropy single request 0/311 returned: 0
...
# Zero entropy single request 20/311 returned: -3
...
# Zero entropy single request 311/311 returned: -5
# Zero entropy request 64 Bytes: -5
# ADC noise source entropy/sample: 65536 [2^16 * bit / sample]
# ADC noise source entropy/sample: 1 [bit / sample]
# 95
# 9f
# a5
# 01
# e1
# 3e
# 73
...
# ADC noise request 64 Bytes returned: 0. Time: <time>us
```

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2020 HAW Hamburg
*
* 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.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for Entropy Sources
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>
#include "fmt.h"
#include "xtimer.h"
#include "entropy_source.h"
#include "entropy_source/zero_entropy.h"
#if MODULE_PERIPH_ADC
#include "entropy_source/adc_noise.h"
#endif
#ifndef NUM_BYTES
#define NUM_BYTES (64)
#endif
int main(void)
{
uint8_t buf1;
uint8_t buf2[NUM_BYTES];
int ret, prop_cutorr;
/* Get Adaptive Proportion Test cutoff value and use as max. number of requests */
prop_cutorr = entropy_source_test_prop_cutoff(
CONFIG_ENTROPY_SOURCE_ZERO_HMIN);
/* Initialize zero entropy source */
entropy_source_zero_init();
/* Request single bytes*/
for (int i = 0; i < prop_cutorr + 1; i++) {
ret = entropy_source_zero_get(&buf1, 1);
printf("Zero entropy single request %i/%i returned: %i\n", i,
prop_cutorr, ret);
}
/* Request a buffer */
ret = entropy_source_zero_get(buf2, NUM_BYTES);
printf("Zero entropy request %i Bytes: %i\n", NUM_BYTES, ret);
#if MODULE_PERIPH_ADC
uint32_t start, stop;
uint32_t entropy;
entropy = entropy_source_adc_entropy_per_sample();
printf("ADC noise source entropy/sample: %"PRIu32" [2^16 * bit / sample]\n", \
entropy);
print_str("ADC noise source entropy/sample: ");
print_float(ENTROPY_SOURCE_HMIN_SCALE_BACK(entropy), 6);
print_str(" [bit / sample]\n");
/* Initialize ADC noise source */
entropy_source_adc_init();
for (unsigned i = 0; i < NUM_BYTES; i++) {
/*Request single bytes*/
ret = entropy_source_adc_get(&buf1, 1);
if (ret < 0) {
printf("ADC noise single request %u/%i: %i\n", i, NUM_BYTES, ret);
}
else {
printf("%02x\n", buf1);
}
}
/* Request a buffer and measure time */
start = xtimer_now_usec();
ret = entropy_source_adc_get(buf2, NUM_BYTES);
stop = xtimer_now_usec();
for (unsigned i = 0; i < sizeof(buf2); i++) {
printf("%02x\n", buf2[i]);
}
printf("ADC noise request %i Bytes returned: %i. Time: %" PRIu32 "us\n", \
NUM_BYTES, ret, stop - start);
#endif
return 0;
}