You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
458 lines
12 KiB
458 lines
12 KiB
/***************************************************************************
|
|
* The yarrow pseudo-randomness genrator *
|
|
* extracted from nettle, the low-level cryptographics library *
|
|
* *
|
|
* Copyright (C) 2007 Tarek Saidi <tarek.saidi@arcor.de> *
|
|
* Copyright (C) 2001 Niels Müler *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; version 2 of the License. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
***************************************************************************/
|
|
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <ctime>
|
|
|
|
#include "yarrow.h"
|
|
#include "random.h"
|
|
|
|
#ifndef YARROW_DEBUG
|
|
#define YARROW_DEBUG 0
|
|
#endif
|
|
|
|
#if YARROW_DEBUG
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
#define SHA256_DIGEST_SIZE 32
|
|
#define AES_MAX_KEY_SIZE 32
|
|
|
|
/* Parameters */
|
|
|
|
/* An upper limit on the entropy (in bits) in one octet of sample
|
|
* data. */
|
|
#define YARROW_MULTIPLIER 4
|
|
|
|
/* Entropy threshold for reseeding from the fast pool */
|
|
#define YARROW_FAST_THRESHOLD 100
|
|
|
|
/* Entropy threshold for reseeding from the fast pool */
|
|
#define YARROW_SLOW_THRESHOLD 160
|
|
|
|
/* Number of sources that must exceed the threshold for slow reseed */
|
|
#define YARROW_SLOW_K 2
|
|
|
|
/* The number of iterations when reseeding, P_t in the yarrow paper.
|
|
* Should be chosen so that reseeding takes on the order of 0.1-1
|
|
* seconds. */
|
|
#define YARROW_RESEED_ITERATIONS 1500
|
|
|
|
/* Entropy estimates sticks to this value, it is treated as infinity
|
|
* in calculations. It should fit comfortably in an uint32_t, to avoid
|
|
* overflows. */
|
|
#define YARROW_MAX_ENTROPY 0x100000
|
|
|
|
/* Forward declarations */
|
|
|
|
static void
|
|
yarrow_fast_reseed(struct yarrow256_ctx *ctx);
|
|
|
|
static void
|
|
yarrow_gate(struct yarrow256_ctx *ctx);
|
|
|
|
void
|
|
yarrow256_init(struct yarrow256_ctx *ctx,
|
|
unsigned n,
|
|
struct yarrow_source *s)
|
|
{
|
|
unsigned i;
|
|
|
|
sha256_starts(&ctx->pools[0]);
|
|
sha256_starts(&ctx->pools[1]);
|
|
|
|
ctx->seeded = 0;
|
|
|
|
/* Not strictly, necessary, but it makes it easier to see if the
|
|
* values are sane. */
|
|
memset(ctx->seed_file, 0, YARROW256_SEED_FILE_SIZE);
|
|
memset(ctx->counter, 0, sizeof(ctx->counter));
|
|
|
|
ctx->nsources = n;
|
|
ctx->sources = s;
|
|
|
|
for (i = 0; i<n; i++)
|
|
{
|
|
ctx->sources[i].estimate[YARROW_FAST] = 0;
|
|
ctx->sources[i].estimate[YARROW_SLOW] = 0;
|
|
ctx->sources[i].next = YARROW_FAST;
|
|
}
|
|
}
|
|
|
|
void
|
|
yarrow256_seed(struct yarrow256_ctx *ctx,
|
|
unsigned length,
|
|
const quint8 *seed_file)
|
|
{
|
|
/* FIXME: Perhaps it's better to use assert ? */
|
|
if (!length)
|
|
return;
|
|
|
|
sha256_update(&ctx->pools[YARROW_FAST], seed_file, length);
|
|
yarrow_fast_reseed(ctx);
|
|
|
|
ctx->seeded = 1;
|
|
}
|
|
|
|
/* FIXME: Generalize so that it generates a few more blocks at a
|
|
* time. */
|
|
static void
|
|
yarrow_generate_block(struct yarrow256_ctx *ctx,
|
|
quint8 *block)
|
|
{
|
|
unsigned i;
|
|
//aes_encrypt(&ctx->key, sizeof(ctx->counter), block, ctx->counter);
|
|
aes_ecb_encrypt(ctx->counter,block,sizeof(ctx->counter),&ctx->key);
|
|
|
|
/* Increment counter, treating it as a big-endian number. This is
|
|
* machine independent, and follows appendix B of the NIST
|
|
* specification of cipher modes of operation.
|
|
*
|
|
* We could keep a representation of thy counter as 4 32-bit values,
|
|
* and write entire words (in big-endian byteorder) into the counter
|
|
* block, whenever they change. */
|
|
for (i = sizeof(ctx->counter); i--; )
|
|
{
|
|
if (++ctx->counter[i])
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
yarrow_iterate(quint8 *digest)
|
|
{
|
|
quint8 v0[SHA256_DIGEST_SIZE];
|
|
unsigned i;
|
|
|
|
memcpy(v0, digest, SHA256_DIGEST_SIZE);
|
|
|
|
/* When hashed inside the loop, i should run from 1 to
|
|
* YARROW_RESEED_ITERATIONS */
|
|
for (i = 0; ++i < YARROW_RESEED_ITERATIONS; )
|
|
{
|
|
quint8 count[4];
|
|
sha256_context hash;
|
|
|
|
sha256_starts(&hash);
|
|
|
|
/* Hash v_i | v_0 | i */
|
|
WRITE_UINT32(count, i);
|
|
sha256_update(&hash, digest, SHA256_DIGEST_SIZE);
|
|
sha256_update(&hash, v0, sizeof(v0));
|
|
sha256_update(&hash, count, sizeof(count));
|
|
sha256_finish(&hash,digest);
|
|
}
|
|
}
|
|
|
|
/* NOTE: The SHA-256 digest size equals the AES key size, so we need
|
|
* no "size adaptor". */
|
|
|
|
static void
|
|
yarrow_fast_reseed(struct yarrow256_ctx *ctx)
|
|
{
|
|
quint8 digest[SHA256_DIGEST_SIZE];
|
|
unsigned i;
|
|
|
|
#if YARROW_DEBUG
|
|
fprintf(stderr, "yarrow_fast_reseed\n");
|
|
#endif
|
|
|
|
/* We feed two block of output using the current key into the pool
|
|
* before emptying it. */
|
|
if (ctx->seeded)
|
|
{
|
|
quint8 blocks[AES_BLOCK_SIZE * 2];
|
|
|
|
yarrow_generate_block(ctx, blocks);
|
|
yarrow_generate_block(ctx, blocks + AES_BLOCK_SIZE);
|
|
sha256_update(&ctx->pools[YARROW_FAST],blocks,sizeof(blocks));
|
|
}
|
|
|
|
sha256_finish(&ctx->pools[YARROW_FAST],digest);
|
|
|
|
/* Iterate */
|
|
yarrow_iterate(digest);
|
|
|
|
aes_encrypt_key256(digest,&ctx->key);
|
|
|
|
/* Derive new counter value */
|
|
memset(ctx->counter, 0, sizeof(ctx->counter));
|
|
//aes_encrypt(&ctx->key, sizeof(ctx->counter), ctx->counter, ctx->counter);
|
|
aes_ecb_encrypt(ctx->counter,ctx->counter,sizeof(ctx->counter),&ctx->key);
|
|
|
|
/* Reset estimates. */
|
|
for (i = 0; i<ctx->nsources; i++)
|
|
ctx->sources[i].estimate[YARROW_FAST] = 0;
|
|
|
|
/* New seed file. */
|
|
/* FIXME: Extract this into a function of its own. */
|
|
for (i = 0; i < sizeof(ctx->seed_file); i+= AES_BLOCK_SIZE)
|
|
yarrow_generate_block(ctx, ctx->seed_file + i);
|
|
|
|
yarrow_gate(ctx);
|
|
}
|
|
|
|
static void
|
|
yarrow_slow_reseed(struct yarrow256_ctx *ctx)
|
|
{
|
|
quint8 digest[SHA256_DIGEST_SIZE];
|
|
unsigned i;
|
|
|
|
#if YARROW_DEBUG
|
|
fprintf(stderr, "yarrow_slow_reseed\n");
|
|
#endif
|
|
|
|
/* Get digest of the slow pool*/
|
|
|
|
sha256_finish(&ctx->pools[YARROW_SLOW], digest);
|
|
|
|
/* Feed it into the fast pool */
|
|
sha256_update(&ctx->pools[YARROW_FAST],digest, sizeof(digest));
|
|
|
|
yarrow_fast_reseed(ctx);
|
|
|
|
/* Reset estimates. */
|
|
for (i = 0; i<ctx->nsources; i++)
|
|
ctx->sources[i].estimate[YARROW_SLOW] = 0;
|
|
}
|
|
|
|
int
|
|
yarrow256_update(struct yarrow256_ctx *ctx,
|
|
unsigned source_index, unsigned entropy,
|
|
unsigned length, const quint8 *data)
|
|
{
|
|
enum yarrow_pool_id current;
|
|
struct yarrow_source *source;
|
|
|
|
assert(source_index < ctx->nsources);
|
|
|
|
if (!length)
|
|
/* Nothing happens */
|
|
return 0;
|
|
|
|
source = &ctx->sources[source_index];
|
|
|
|
if (!ctx->seeded)
|
|
/* While seeding, use the slow pool */
|
|
current = YARROW_SLOW;
|
|
else
|
|
{
|
|
current = source->next;
|
|
source->next = (yarrow_pool_id)!source->next;
|
|
}
|
|
|
|
sha256_update(&ctx->pools[current],data,length);
|
|
|
|
/* NOTE: We should be careful to avoid overflows in the estimates. */
|
|
if (source->estimate[current] < YARROW_MAX_ENTROPY)
|
|
{
|
|
if (entropy > YARROW_MAX_ENTROPY)
|
|
entropy = YARROW_MAX_ENTROPY;
|
|
|
|
if ( (length < (YARROW_MAX_ENTROPY / YARROW_MULTIPLIER))
|
|
&& (entropy > YARROW_MULTIPLIER * length) )
|
|
entropy = YARROW_MULTIPLIER * length;
|
|
|
|
/* FIXME: Calling a more sophisticated estimater should be done
|
|
* here. */
|
|
|
|
entropy += source->estimate[current];
|
|
if (entropy > YARROW_MAX_ENTROPY)
|
|
entropy = YARROW_MAX_ENTROPY;
|
|
|
|
source->estimate[current] = entropy;
|
|
}
|
|
|
|
/* Check for seed/reseed */
|
|
switch(current)
|
|
{
|
|
case YARROW_FAST:
|
|
#if YARROW_DEBUG
|
|
fprintf(stderr,
|
|
"yarrow256_update: source_index = %d,\n"
|
|
" fast pool estimate = %d\n",
|
|
source_index, source->estimate[YARROW_FAST]);
|
|
#endif
|
|
if (source->estimate[YARROW_FAST] >= YARROW_FAST_THRESHOLD)
|
|
{
|
|
yarrow_fast_reseed(ctx);
|
|
return 1;
|
|
}
|
|
else
|
|
return 0;
|
|
|
|
case YARROW_SLOW:
|
|
{
|
|
/* FIXME: This is somewhat inefficient. It would be better to
|
|
* either maintain the count, or do this loop only if the
|
|
* current source just crossed the threshold. */
|
|
|
|
if (!yarrow256_needed_sources(ctx))
|
|
{
|
|
yarrow_slow_reseed(ctx);
|
|
ctx->seeded = 1;
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
static void
|
|
yarrow_gate(struct yarrow256_ctx *ctx)
|
|
{
|
|
quint8 key[AES_MAX_KEY_SIZE];
|
|
unsigned i;
|
|
|
|
for (i = 0; i < sizeof(key); i+= AES_BLOCK_SIZE)
|
|
yarrow_generate_block(ctx, key + i);
|
|
|
|
aes_encrypt_key256(key,&ctx->key);
|
|
}
|
|
|
|
void
|
|
yarrow256_random(struct yarrow256_ctx *ctx, unsigned length, quint8 *dst)
|
|
{
|
|
assert(ctx->seeded);
|
|
|
|
while (length >= AES_BLOCK_SIZE)
|
|
{
|
|
yarrow_generate_block(ctx, dst);
|
|
dst += AES_BLOCK_SIZE;
|
|
length -= AES_BLOCK_SIZE;
|
|
}
|
|
if (length)
|
|
{
|
|
quint8 buffer[AES_BLOCK_SIZE];
|
|
|
|
assert(length < AES_BLOCK_SIZE);
|
|
yarrow_generate_block(ctx, buffer);
|
|
memcpy(dst, buffer, length);
|
|
}
|
|
yarrow_gate(ctx);
|
|
}
|
|
|
|
int
|
|
yarrow256_is_seeded(struct yarrow256_ctx *ctx)
|
|
{
|
|
return ctx->seeded;
|
|
}
|
|
|
|
unsigned
|
|
yarrow256_needed_sources(struct yarrow256_ctx *ctx)
|
|
{
|
|
/* FIXME: This is somewhat inefficient. It would be better to
|
|
* either maintain the count, or do this loop only if the
|
|
* current source just crossed the threshold. */
|
|
unsigned k, i;
|
|
|
|
for (i = k = 0; i < ctx->nsources; i++)
|
|
if (ctx->sources[i].estimate[YARROW_SLOW] >= YARROW_SLOW_THRESHOLD)
|
|
k++;
|
|
|
|
#if YARROW_DEBUG
|
|
fprintf(stderr,
|
|
"yarrow256_needed_sources: source_index = %d,\n"
|
|
" slow pool estimate = %d,\n"
|
|
" number of sources above threshold = %d\n",
|
|
source_index, source->estimate[YARROW_SLOW], k);
|
|
#endif
|
|
|
|
return (k < YARROW_SLOW_K) ? (YARROW_SLOW_K - k) : 0;
|
|
}
|
|
|
|
void
|
|
yarrow256_force_reseed(struct yarrow256_ctx *ctx)
|
|
{
|
|
yarrow_slow_reseed(ctx);
|
|
}
|
|
|
|
struct yarrow256_ctx WeakCtx;
|
|
struct yarrow256_ctx StrongCtx;
|
|
struct yarrow_source WeakSrc[2];
|
|
struct yarrow_source StrongSrc[2];
|
|
|
|
void initYarrow(){
|
|
yarrow256_init(&WeakCtx,2,WeakSrc);
|
|
yarrow256_init(&StrongCtx,2,StrongSrc);
|
|
|
|
quint8 buffer[100];
|
|
for (int i=0; i<2; i++){
|
|
getEntropy(buffer,100);
|
|
yarrowUpdateWeak(i,100*8,100,buffer);
|
|
}
|
|
}
|
|
|
|
void yarrowUpdateWeak(unsigned source, unsigned entropy, unsigned length, const quint8 *data){
|
|
yarrow256_update(&WeakCtx,source,entropy,length,data);
|
|
}
|
|
|
|
void yarrowUpdateStrong(unsigned source, unsigned entropy, unsigned length, const quint8 *data){
|
|
yarrow256_update(&StrongCtx,source,entropy,length,data);
|
|
}
|
|
|
|
void randomize(void* buffer, unsigned int length){
|
|
if(!yarrow256_is_seeded(&StrongCtx))
|
|
yarrow256_random(&WeakCtx,length,(quint8*)buffer);
|
|
else
|
|
yarrow256_random(&StrongCtx,length,(quint8*)buffer);
|
|
}
|
|
|
|
void strongRandomize(void* buffer, unsigned int length){
|
|
Q_ASSERT(yarrow256_is_seeded(&StrongCtx));
|
|
for(uint i=0; i<length;i++)
|
|
yarrow256_random(&StrongCtx,1,(quint8*)buffer+i);
|
|
}
|
|
|
|
void reseedStrongPool(quint8* buffer1,int l1,quint8* buffer2,int l2){
|
|
if(l1>l2*4){
|
|
yarrow256_update(&StrongCtx,0,100,100,buffer1);
|
|
buffer1=buffer1+100;
|
|
l1=l1-100;
|
|
}
|
|
else{
|
|
yarrow256_update(&StrongCtx,1,100,25,buffer2);
|
|
buffer2=buffer2+25;
|
|
l2=l2-25;
|
|
}
|
|
|
|
if(l1>l2*4){
|
|
yarrow256_update(&StrongCtx,0,160,160,buffer1);
|
|
l1-=160;
|
|
buffer1+=160;
|
|
yarrow256_update(&StrongCtx,1,l1,l1,buffer1);
|
|
yarrow256_update(&StrongCtx,1,4*l2,l2,buffer2);
|
|
}
|
|
else{
|
|
yarrow256_update(&StrongCtx,0,160,40,buffer2);
|
|
l2-=40;
|
|
buffer2+=40;
|
|
yarrow256_update(&StrongCtx,1,l2*4,l2,buffer2);
|
|
yarrow256_update(&StrongCtx,1,l1,l1,buffer1);
|
|
}
|
|
}
|
|
|