#include <stdio.h>
#include <bee2/core/err.h>
#include <bee2/core/mem.h>
#include <bee2/core/prng.h>
#include <bee2/core/rng.h>
#include <bee2/core/util.h>
#include <bee2/crypto/belt.h>
#include "bee2/cmd.h"
#ifdef OS_UNIX
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
static bool_t cmdTermEcho(bool_t on)
{
bool_t prev;
struct termios attr;
fflush(stdout);
tcgetattr(STDIN_FILENO, &attr);
prev = (attr.c_lflag & ECHO) != 0;
if (on)
attr.c_lflag |= ECHO;
else
attr.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &attr);
return prev;
}
#else
static bool_t cmdTermEcho(bool_t on)
{
static bool_t state;
bool_t ret = state;
state = on;
return ret;
}
#endif
err_t cmdRngKbRead(tm_ticks_t data[128])
{
const tm_ticks_t freq = tmFreq();
const tm_ticks_t max_delay = freq * 5;
const tm_ticks_t min_delay = freq / 20;
register tm_ticks_t ticks;
register tm_ticks_t t;
err_t code;
size_t pos;
bool_t echo;
int ch;
ASSERT(memIsValid(data, sizeof(tm_ticks_t) * 128));
code = freq >= 20000000u ? ERR_OK : ERR_FILE_NOT_FOUND;
ERR_CALL_CHECK(code);
printf("Collecting entropy from keyboard...\n");
printf("Please, press different keys avoiding repetitions and long pauses:\n");
for (pos = 128; pos; pos -= 2)
printf("%c", '*');
printf("\r");
echo = cmdTermEcho(FALSE);
ASSERT(pos == 0);
for (ticks = tmTicks(), ch = 0; pos < 128; )
{
int c;
t = tmTicks();
if (t > ticks + max_delay)
{
code = ERR_TIMEOUT;
break;
}
if (!cmdTermKbhit() || t < ticks + min_delay ||
(c = cmdTermGetch()) == ch || c == 0 || c == 0xE0)
continue;
data[pos++] = t - ticks, ticks = t, ch = c;
if (pos % 2)
printf(".");
}
CLEAN2(ticks, t);
cmdTermEcho(echo);
printf("\n");
return code;
}
static err_t prngEchoRead(size_t* read, void* buf, size_t count, void* state)
{
ASSERT(memIsValid(read, O_PER_S));
prngEchoStepR(buf, count, state);
*read = count;
return ERR_OK;
}
err_t cmdRngStart(bool_t verbose)
{
err_t code;
if (rngIsValid())
return ERR_OK;
if (verbose)
{
const char* sources[] = { "trng", "trng2", "sys", "sys2", "timer" };
size_t pos;
size_t count;
size_t read;
printf("Starting RNG[");
for (pos = count = 0; pos < COUNT_OF(sources); ++pos)
if (rngESRead(&read, 0, 0, sources[pos]) == ERR_OK)
printf(count++ ? ", %s" : "%s", sources[pos]);
printf("]... ");
}
code = rngESHealth();
if (code == ERR_OK)
code = rngCreate(0, 0);
else if (code == ERR_NOT_ENOUGH_ENTROPY)
{
void* stack;
tm_ticks_t* data;
octet* hash;
void* state;
code = cmdBlobCreate(stack, 128 * sizeof(tm_ticks_t) +
MAX2(beltHash_keep(), prngEcho_keep()));
ERR_CALL_CHECK(code);
data = (tm_ticks_t*)stack;
hash = (octet*)data;
state = data + 128;
code = cmdRngKbRead(data);
ERR_CALL_HANDLE(code, cmdBlobClose(stack));
beltHashStart(state);
beltHashStepH(data, 128 * sizeof(tm_ticks_t), state);
beltHashStepG(hash, state);
prngEchoStart(state, hash, 32);
code = rngCreate(prngEchoRead, state);
cmdBlobClose(stack);
}
if (verbose)
printf("%s\n", errMsg(code));
return code;
}