mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #14488 from PeterKietzmann/pr_add_sha256prng
sys/random: add SHA256 mode to SHA1PRNG & tests
This commit is contained in:
commit
05b13f5029
@ -778,7 +778,8 @@ ifneq (,$(filter random,$(USEMODULE)))
|
||||
USEMODULE += tinymt32
|
||||
endif
|
||||
|
||||
ifneq (,$(filter prng_sha1prng,$(USEMODULE)))
|
||||
ifneq (,$(filter prng_sha%prng,$(USEMODULE)))
|
||||
USEMODULE += prng_shaxprng
|
||||
USEMODULE += hashes
|
||||
endif
|
||||
|
||||
|
32
sys/random/doc.txt
Normal file
32
sys/random/doc.txt
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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_random_shaxprng SHAX random number generator
|
||||
* @ingroup sys_random
|
||||
*
|
||||
* @brief SHA based random number generator implementation(CSPRNG).
|
||||
*
|
||||
* The generator bases on an internal structure that has been presented in
|
||||
* FIPS 186-1 Appendix 3.2, which is why it is sometimes named as "DSA PRNG" or
|
||||
* "FIPS PRNG" in the literature. Outputs are generated by hashing the internal
|
||||
* generator state, and the feedback path applies a linear transformation to the
|
||||
* state which is hashed again to create further next outputs. Thus, a potential
|
||||
* state compromise may allow recovering preceding generator outputs, because
|
||||
* linear operations in the feedback path are invertible. Thereby, this generator
|
||||
* gets along with a single hash computation per block which makes the generator
|
||||
* lightweight in comparison to more advanced CSPRNGs.
|
||||
*
|
||||
* This implementation can be run with the SHA-1 or SHA-256 hash function
|
||||
* for creating outputs. SHA-1 has been deprecated by NIST in 2011 due to
|
||||
* a collision- and potential brute-force attack. Thus, SHA-256 can be used as
|
||||
* an alternative. To select one or the other, export
|
||||
* `USEMODULE += prng_sha1prng` or
|
||||
* `USEMODULE += prng_sha256prng`
|
||||
* during compilation.
|
||||
*/
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 HAW Hamburg
|
||||
* Copyright (C) 2018, 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
|
||||
@ -10,12 +10,10 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup sys_random
|
||||
* @ingroup sys_random_shaxprng
|
||||
* @{
|
||||
* @file
|
||||
*
|
||||
* @brief SHA1PRNG random number generator implementation
|
||||
*
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
* @}
|
||||
*/
|
||||
@ -24,10 +22,52 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "hashes/sha1.h"
|
||||
#include "hashes/sha256.h"
|
||||
#include "kernel_defines.h"
|
||||
|
||||
#define STATE_SIZE (SHA1_DIGEST_LENGTH)
|
||||
#if IS_USED(MODULE_PRNG_SHA1PRNG)
|
||||
/* state size is digset length of SHA-1 */
|
||||
#define STATE_SIZE (SHA1_DIGEST_LENGTH)
|
||||
typedef sha1_context shax_context_t;
|
||||
#elif IS_USED(MODULE_PRNG_SHA256PRNG)
|
||||
/* state size is digest length of SHA-256 */
|
||||
#define STATE_SIZE (SHA256_DIGEST_LENGTH)
|
||||
typedef sha256_context_t shax_context_t;
|
||||
#endif
|
||||
|
||||
static inline void _shax_init(shax_context_t *ctx)
|
||||
{
|
||||
if (IS_USED(MODULE_PRNG_SHA1PRNG)) {
|
||||
sha1_init((sha1_context *)ctx);
|
||||
}
|
||||
else if (IS_USED(MODULE_PRNG_SHA256PRNG)) {
|
||||
sha256_init((sha256_context_t *)ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _shax_update(shax_context_t *ctx, const void *data, size_t len)
|
||||
{
|
||||
if (IS_USED(MODULE_PRNG_SHA1PRNG)) {
|
||||
sha1_update((sha1_context *)ctx, data, len);
|
||||
}
|
||||
else if (IS_USED(MODULE_PRNG_SHA256PRNG)) {
|
||||
sha256_update((sha256_context_t *)ctx, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _shax_final(shax_context_t *ctx, void *digest)
|
||||
{
|
||||
if (IS_USED(MODULE_PRNG_SHA1PRNG)) {
|
||||
sha1_final((sha1_context *)ctx, digest);
|
||||
}
|
||||
else if (IS_USED(MODULE_PRNG_SHA256PRNG)) {
|
||||
sha256_final((sha256_context_t *)ctx, digest);
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate SHA context */
|
||||
static shax_context_t ctx;
|
||||
|
||||
static sha1_context ctx;
|
||||
static uint32_t datapos = STATE_SIZE;
|
||||
static int8_t digestdata[STATE_SIZE];
|
||||
static int8_t prng_state[STATE_SIZE];
|
||||
@ -62,7 +102,7 @@ void _updatestate(int8_t *state)
|
||||
}
|
||||
}
|
||||
|
||||
void _random_bytes(uint8_t *bytes, size_t size) /* TODO: use with global API */
|
||||
void _random_bytes(uint8_t *bytes, size_t size)
|
||||
{
|
||||
uint32_t loc = 0;
|
||||
while (loc < size)
|
||||
@ -88,14 +128,14 @@ void _random_bytes(uint8_t *bytes, size_t size) /* TODO: use with global API */
|
||||
/* no out data ready, (re)fill internal buffer */
|
||||
else
|
||||
{
|
||||
/* reset SHA1 internal state */
|
||||
sha1_init(&ctx);
|
||||
/* reset SHA internal state */
|
||||
_shax_init(&ctx);
|
||||
|
||||
/* update SHA1 internal state with PRNG state */
|
||||
sha1_update(&ctx, (void *)prng_state, sizeof(prng_state));
|
||||
/* update SHA internal state with PRNG state */
|
||||
_shax_update(&ctx, prng_state, sizeof(prng_state));
|
||||
|
||||
/* get the digest */
|
||||
sha1_final(&ctx, digestdata);
|
||||
_shax_final(&ctx, digestdata);
|
||||
|
||||
/* update PRNG state for next round */
|
||||
_updatestate(prng_state);
|
||||
@ -108,12 +148,15 @@ void _random_bytes(uint8_t *bytes, size_t size) /* TODO: use with global API */
|
||||
|
||||
void random_init_by_array(uint32_t init_key[], int key_length)
|
||||
{
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, (void *)init_key, key_length);
|
||||
sha1_final(&ctx, digestdata);
|
||||
_shax_init(&ctx);
|
||||
_shax_update(&ctx, init_key, key_length);
|
||||
_shax_final(&ctx, digestdata);
|
||||
|
||||
/* copy seeded SHA1 state to PRNG state */
|
||||
memcpy(prng_state, &ctx.state, STATE_SIZE);
|
||||
/* copy SHA digestdata to PRNG state */
|
||||
memcpy(prng_state, digestdata, STATE_SIZE);
|
||||
|
||||
/* reset position indicator */
|
||||
datapos = STATE_SIZE;
|
||||
}
|
||||
|
||||
void random_init(uint32_t seed)
|
||||
@ -124,13 +167,13 @@ void random_init(uint32_t seed)
|
||||
uint32_t random_uint32(void)
|
||||
{
|
||||
uint32_t ret;
|
||||
int8_t bytes[sizeof(uint32_t)];
|
||||
_random_bytes((uint8_t *)bytes, sizeof(uint32_t));
|
||||
uint8_t bytes[sizeof(uint32_t)];
|
||||
_random_bytes(bytes, sizeof(bytes));
|
||||
|
||||
ret = ((bytes[0] & 0xff) << 24)
|
||||
| ((bytes[1] & 0xff) << 16)
|
||||
| ((bytes[2] & 0xff) << 8)
|
||||
| (bytes[3] & 0xff);
|
||||
ret = ((uint32_t)(bytes[0] & 0xff) << 24)
|
||||
| ((uint32_t)(bytes[1] & 0xff) << 16)
|
||||
| ((uint32_t)(bytes[2] & 0xff) << 8)
|
||||
| ((uint32_t)(bytes[3] & 0xff));
|
||||
|
||||
return ret;
|
||||
}
|
6
tests/prng_sha1prng/Makefile
Normal file
6
tests/prng_sha1prng/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
USEMODULE += random
|
||||
USEMODULE += prng_sha1prng
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
82
tests/prng_sha1prng/main.c
Normal file
82
tests/prng_sha1prng/main.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file
|
||||
* @brief Test cases for the SHA1PRNG pseudo random number generator
|
||||
*
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kernel_defines.h"
|
||||
#include "random.h"
|
||||
|
||||
/**
|
||||
* @brief expected sequence for seed=1. This sequence was generated running the
|
||||
* following java program (openjdk 11.0.7) as a reference.
|
||||
*
|
||||
*~~~~
|
||||
* import java.security.SecureRandom;
|
||||
*
|
||||
* public class SHA1PRNGTEST {
|
||||
* public static void main(String args[]) throws Exception {
|
||||
* SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
|
||||
* random.setSeed(1);
|
||||
* int number = 0;
|
||||
* for (int i = 0; i < 20; i++) {
|
||||
* number = random.nextInt();
|
||||
* System.out.print(Integer.toUnsignedString(number) + " ");
|
||||
* }
|
||||
* System.out.println("");
|
||||
* }
|
||||
* }
|
||||
*~~~~
|
||||
*/
|
||||
static const uint32_t seq_seed1[] =
|
||||
{2529905901, 3336014406, 1714755920, 3709666991, 1432426612, 554064022,
|
||||
1614405352, 861636861, 3689098857, 3893737371, 3138964692, 506954022,
|
||||
3469584855, 4144207589, 2031557795, 3248917850, 2384338299, 3341545824,
|
||||
2454801916, 3985646079};
|
||||
|
||||
static void test_prng_sha1prng_java_u32(void)
|
||||
{
|
||||
uint32_t seed[2] = {1, 0};
|
||||
|
||||
uint32_t test32[ARRAY_SIZE(seq_seed1)];
|
||||
|
||||
/* seed the generator with 8 bytes similar to the java reference
|
||||
* implementation
|
||||
*/
|
||||
random_init_by_array(seed, sizeof(seed));
|
||||
|
||||
/* request random samples */
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(seq_seed1); i++) {
|
||||
test32[i] = random_uint32();
|
||||
}
|
||||
|
||||
/* compare generator output and reference */
|
||||
if (!(memcmp(test32, seq_seed1, sizeof(seq_seed1)))) {
|
||||
printf("%s:SUCCESS\n", __func__);
|
||||
}
|
||||
else {
|
||||
printf("%s:FAILURE\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
test_prng_sha1prng_java_u32();
|
||||
|
||||
return 0;
|
||||
}
|
18
tests/prng_sha1prng/tests/01-run.py
Executable file
18
tests/prng_sha1prng/tests/01-run.py
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
from testrunner import run
|
||||
|
||||
|
||||
def testfunc(child):
|
||||
child.expect("test_prng_sha1prng_java_u32:SUCCESS\r\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run(testfunc))
|
6
tests/prng_sha256prng/Makefile
Normal file
6
tests/prng_sha256prng/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
USEMODULE += random
|
||||
USEMODULE += prng_sha256prng
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
91
tests/prng_sha256prng/main.c
Normal file
91
tests/prng_sha256prng/main.c
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @file
|
||||
* @brief Test cases for the SHA256PRNG pseudo random number generator
|
||||
*
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kernel_defines.h"
|
||||
#include "random.h"
|
||||
|
||||
/**
|
||||
* @brief expected sequence for seed=1. This is only a regression test. The
|
||||
* expected output was generated while porting the SHA256PRNG to RIOT.
|
||||
*/
|
||||
static const uint32_t seq_seed1[] =
|
||||
{1106729202, 3855353741, 932558076, 213257261, 1935649068, 3223344939,
|
||||
3700960722, 3580154139, 3802991633, 3783537878, 3862557448, 3401019389,
|
||||
3269475530, 260491589, 2254706846, 3754733214, 1693392656, 3020931263,
|
||||
2202015546, 2031345158};
|
||||
/**
|
||||
* @brief expected sequence for seed=11799121 (generated at random.org). This is
|
||||
* only a regression test. The expected output was generated while porting
|
||||
* the SHA256PRNG to RIOT.
|
||||
*/
|
||||
static const uint8_t seq_seed2[] =
|
||||
{0x04, 0x8b, 0xc0, 0x91, 0x7b, 0x08, 0x4a, 0x2f, 0x8f, 0x9a, 0xd0, 0xa6, 0x65, 0x18,
|
||||
0x7b, 0x89, 0x9b, 0x74, 0x52, 0x45, 0x44, 0x74, 0xbd, 0x4a, 0x0c, 0x74, 0x8a, 0x0e,
|
||||
0xee, 0xdc, 0x76, 0x50, 0x67, 0xe8, 0x50, 0xce, 0x26, 0xdb, 0x0d, 0xef, 0x33, 0x38,
|
||||
0xba, 0x6b, 0x68, 0x8d, 0x5d, 0x83, 0xfd, 0xe3, 0xef, 0x19, 0x20, 0x59, 0xd9, 0xc9,
|
||||
0x12, 0x6b, 0x5f, 0x8c, 0xf9, 0x05, 0x36, 0x8f};
|
||||
|
||||
static void test_prng_sha256prng_seed1_u32(void)
|
||||
{
|
||||
uint32_t seed = 1;
|
||||
uint32_t test32[ARRAY_SIZE(seq_seed1)];
|
||||
|
||||
random_init(seed);
|
||||
|
||||
/* request random samples */
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(seq_seed1); i++) {
|
||||
test32[i] = random_uint32();
|
||||
}
|
||||
|
||||
/* compare generator output and reference */
|
||||
if (!(memcmp(test32, seq_seed1, sizeof(seq_seed1)))) {
|
||||
printf("%s:SUCCESS\n", __func__);
|
||||
}
|
||||
else {
|
||||
printf("%s:FAILURE\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_prng_sha256prng_seed2_u8(void)
|
||||
{
|
||||
uint32_t seed = 11799121;
|
||||
uint8_t test8[sizeof(seq_seed2)];
|
||||
|
||||
random_init(seed);
|
||||
|
||||
/* request random bytes */
|
||||
random_bytes(test8, sizeof(seq_seed2));
|
||||
|
||||
/* compare generator output and reference */
|
||||
if (!(memcmp(test8, seq_seed2, sizeof(seq_seed2)))) {
|
||||
printf("%s:SUCCESS\n", __func__);
|
||||
}
|
||||
else {
|
||||
printf("%s:FAILURE\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_prng_sha256prng_seed1_u32();
|
||||
test_prng_sha256prng_seed2_u8();
|
||||
|
||||
return 0;
|
||||
}
|
19
tests/prng_sha256prng/tests/01-run.py
Executable file
19
tests/prng_sha256prng/tests/01-run.py
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
from testrunner import run
|
||||
|
||||
|
||||
def testfunc(child):
|
||||
child.expect("test_prng_sha256prng_seed1_u32:SUCCESS\r\n")
|
||||
child.expect("test_prng_sha256prng_seed2_u8:SUCCESS\r\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run(testfunc))
|
@ -61,6 +61,8 @@ static void test_init(char *name)
|
||||
puts("Musl C PRNG.\n");
|
||||
#elif MODULE_PRNG_SHA1PRNG
|
||||
puts("SHA1 PRNG.\n");
|
||||
#elif MODULE_PRNG_SHA256PRNG
|
||||
puts("SHA256 PRNG.\n");
|
||||
#elif MODULE_PRNG_TINYMT32
|
||||
puts("Tiny Mersenne Twister PRNG.\n");
|
||||
#elif MODULE_PRNG_XORSHIFT
|
||||
|
Loading…
Reference in New Issue
Block a user