/*
 random.c

 Copyright NTT MCL, 2000.

 Duncan S Wong   
 Security Group, NTT MCL
 July 2000
*/

#include "random.h"
#include "sha1.h"

#define RANDOM_BYTES_NEEDED 256

int RandomInit (RANDOM_STRUCT *randomStruct)
{
  randomStruct->bytesNeeded = RANDOM_BYTES_NEEDED;
  memset ((unsigned char *)randomStruct->state, 0, sizeof(randomStruct->state));
  randomStruct->outputAvailable = 0;
  
  return (0);
}

int RandomUpdate (RANDOM_STRUCT *randomStruct, unsigned char *block, unsigned int blockLen)
{
SHA1_CTX context;
unsigned char digest[20];
unsigned int i, x;
  
  SHA1Init (&context);
  SHA1Update (&context, block, blockLen);
  SHA1Final (digest, &context);

  /* add digest to state */
  x = 0;
  for (i = 0; i < 20; i++) {
    x += randomStruct->state[19-i] + digest[19-i];
    randomStruct->state[19-i] = (unsigned char)x;
    x >>= 8;
  }
  
  if (randomStruct->bytesNeeded < blockLen)
    randomStruct->bytesNeeded = 0;
  else
    randomStruct->bytesNeeded -= blockLen;
  
  /* Zeroize sensitive information.
   */
  memset ((unsigned char *)digest, 0, sizeof (digest));
  x = 0;
  
  return (0);
}

int GetRandomBytesNeeded (unsigned int *bytesNeeded, RANDOM_STRUCT *randomStruct)
{
  *bytesNeeded = randomStruct->bytesNeeded;
  
  return (0);
}

int GenerateBytes (block, blockLen, randomStruct)
unsigned char *block;                                 /* block */
unsigned int blockLen;                                /* length of block */
RANDOM_STRUCT *randomStruct;                          /* random structure */
{
SHA1_CTX context;
unsigned int available, i;
  
  if (randomStruct->bytesNeeded)
    return (0x0408);
  
  available = randomStruct->outputAvailable;
  
  while (blockLen > available) {
    memcpy
      ((unsigned char *)block, (unsigned char *)&randomStruct->output[20-available],
       available);
    block += available;
    blockLen -= available;

    /* generate new output */
    SHA1Init (&context);
    SHA1Update (&context, randomStruct->state, 20);
    SHA1Final (randomStruct->output, &context);
    available = 16;

    /* increment state */
    for (i = 0; i < 20; i++)
      if (randomStruct->state[19-i]++)
        break;
  }

  memcpy 
    ((unsigned char *)block,
     (unsigned char *)&randomStruct->output[16-available], blockLen);
  randomStruct->outputAvailable = available - blockLen;

  return (0);
}

void RandomFinal (randomStruct)
RANDOM_STRUCT *randomStruct;                          /* random structure */
{
  memset ((unsigned char *)randomStruct, 0, sizeof (*randomStruct));
}

