1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

sys/random: add SHA1PRNG

This commit is contained in:
PeterKietzmann 2018-06-19 18:42:25 +02:00
parent d49e0d2f79
commit 3c4360eddb
3 changed files with 149 additions and 0 deletions

View File

@ -631,6 +631,10 @@ ifneq (,$(filter random,$(USEMODULE)))
USEMODULE += tinymt32
endif
ifneq (,$(filter prng_sha1prng,$(USEMODULE)))
USEMODULE += hashes
endif
USEMODULE += luid
endif

143
sys/random/sha1prng.c Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2018 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.
*
* Code referring to Docjar
* (http://www.docjar.net/html/api/gnu/java/security/provider/SHA1PRNG.java.html)
*/
/**
* @ingroup sys_random
* @{
* @file
*
* @brief SHA1PRNG random number generator implementation
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
* @}
*/
#include <stdint.h>
#include <string.h>
#include "hashes/sha1.h"
#define SEED_SIZE (20)
static sha1_context ctx;
static uint32_t datapos = SEED_SIZE;
static int8_t digestdata[SEED_SIZE];
static int8_t prng_state[SEED_SIZE];
void _updatestate(int8_t *state)
{
signed last = 1;
char zf = 0;
for (int i = 0; i < 20; i++) {
signed v;
char t;
/* add two bytes */
v = (int)state[i] + (int)digestdata[i] + last;
/* result is lower 8 bits */
t = (char)(v & 0xff);
/* check for state collision */
zf = zf | (state[i] != t);
/* store result, */
state[i] = t;
/* high 8 bits are carry, store for next iteration */
last = (v >> 8);
}
/* make sure at least one bit changes! */
if (!zf) {
state[0]++;
}
/* update SHA1 state */
sha1_update(&ctx, (void *)state, sizeof(state));
}
void _random_bytes(uint8_t *bytes, size_t size) /* TODO: use with global API */
{
uint32_t loc = 0;
while (loc < size)
{
int copy;
/* find min between remaining out bytes and so far unused seed bytes */
if ( (size-loc) < (SEED_SIZE - datapos) )
{
copy = size-loc;
}
else
{
/* in first iteration this will be 0 */
copy = SEED_SIZE - datapos;
}
if (copy > 0)
{
/* directly copy data to out buffer */
memcpy(bytes + loc, digestdata + datapos, copy);
datapos += copy;
loc += copy;
}
/* no out data ready, (re)fill internal buffer */
else
{
/* reset SHA1 internal state */
sha1_init(&ctx);
/* update SHA1 internal state with PRNG state */
sha1_update(&ctx, (void *)prng_state, sizeof(prng_state));
/* get the digest */
sha1_final(&ctx, digestdata);
/* update PRNG state for next round */
_updatestate(prng_state);
/* reset counter for buffer position */
datapos = 0;
}
}
}
void random_init(uint32_t seed)
{
sha1_init(&ctx);
sha1_update(&ctx, (void *)&seed, sizeof(uint32_t));
sha1_final(&ctx, digestdata);
/* copy seeded SHA1 state to PRNG state */
memcpy(prng_state, &ctx.state, 20);
}
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);
/* copy seeded SHA1 state to PRNG state */
memcpy(prng_state, &ctx.state, 20);
}
uint32_t random_uint32(void)
{
uint32_t ret;
int8_t bytes[sizeof(uint32_t)];
_random_bytes((uint8_t *)bytes, sizeof(uint32_t));
ret = ((bytes[0] & 0xff) << 24)
| ((bytes[1] & 0xff) << 16)
| ((bytes[2] & 0xff) << 8)
| (bytes[3] & 0xff);
return ret;
}

View File

@ -59,6 +59,8 @@ static void test_init(char *name)
puts("Park & Miller Minimal Standard PRNG.\n");
#elif MODULE_PRNG_MUSL_LCG
puts("Musl C PRNG.\n");
#elif MODULE_PRNG_SHA1PRNG
puts("SHA1 PRNG.\n");
#elif MODULE_PRNG_TINYMT32
puts("Tiny Mersenne Twister PRNG.\n");
#elif MODULE_PRNG_XORSHIFT