mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
180 lines
4.4 KiB
C
180 lines
4.4 KiB
C
/*
|
|
* 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
|
|
* directory for more details.
|
|
*
|
|
* Code referring to Docjar
|
|
* (http://www.docjar.net/html/api/gnu/java/security/provider/SHA1PRNG.java.html)
|
|
*/
|
|
|
|
/**
|
|
* @ingroup sys_random_shaxprng
|
|
* @{
|
|
* @file
|
|
*
|
|
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
|
* @}
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "hashes/sha1.h"
|
|
#include "hashes/sha256.h"
|
|
#include "kernel_defines.h"
|
|
|
|
#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 uint32_t datapos = STATE_SIZE;
|
|
static int8_t digestdata[STATE_SIZE];
|
|
static int8_t prng_state[STATE_SIZE];
|
|
|
|
void _updatestate(int8_t *state)
|
|
{
|
|
signed last = 1;
|
|
char zf = 0;
|
|
|
|
for (int i = 0; i < STATE_SIZE; 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]++;
|
|
}
|
|
}
|
|
|
|
void _random_bytes(uint8_t *bytes, size_t size)
|
|
{
|
|
uint32_t loc = 0;
|
|
while (loc < size)
|
|
{
|
|
int copy;
|
|
/* find min between remaining out bytes and so far unused seed bytes */
|
|
if ( (size-loc) < (STATE_SIZE - datapos) )
|
|
{
|
|
copy = size-loc;
|
|
}
|
|
else
|
|
{
|
|
/* in first iteration this will be 0 */
|
|
copy = STATE_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 SHA internal state */
|
|
_shax_init(&ctx);
|
|
|
|
/* update SHA internal state with PRNG state */
|
|
_shax_update(&ctx, prng_state, sizeof(prng_state));
|
|
|
|
/* get the digest */
|
|
_shax_final(&ctx, digestdata);
|
|
|
|
/* update PRNG state for next round */
|
|
_updatestate(prng_state);
|
|
|
|
/* reset counter for buffer position */
|
|
datapos = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void random_init_by_array(uint32_t init_key[], int key_length)
|
|
{
|
|
_shax_init(&ctx);
|
|
_shax_update(&ctx, init_key, key_length);
|
|
_shax_final(&ctx, digestdata);
|
|
|
|
/* copy SHA digestdata to PRNG state */
|
|
memcpy(prng_state, digestdata, STATE_SIZE);
|
|
|
|
/* reset position indicator */
|
|
datapos = STATE_SIZE;
|
|
}
|
|
|
|
void random_init(uint32_t seed)
|
|
{
|
|
random_init_by_array((uint32_t *)&seed, sizeof(seed));
|
|
}
|
|
|
|
uint32_t random_uint32(void)
|
|
{
|
|
uint32_t ret;
|
|
uint8_t bytes[sizeof(uint32_t)];
|
|
_random_bytes(bytes, sizeof(bytes));
|
|
|
|
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;
|
|
}
|