/*	$NetBSD: rnd_keys.c,v 1.5 1999/07/30 19:41:06 mycroft Exp $	*/

#include "des_locl.h"
#include <sys/time.h>
#include <sys/types.h>

#include <fcntl.h>
#include <unistd.h>

#include <sha1.h>

void
des_set_random_generator_seed(des_cblock *seed)
{
	des_random_seed(*seed);
}

/*
 * Generate a sequence of random des keys
 * using the random block sequence, fixup
 * parity and skip weak keys.
 */
int
des_new_random_key(des_cblock *key)
{
  int urandom;

    again:

    urandom = open("/dev/urandom", O_RDONLY);

    if (urandom < 0) 
	des_random_key(*key);
    else {
	if (read(urandom, key, sizeof(des_cblock)) != sizeof(des_cblock)) {
	    close(urandom);
	    des_random_key(*key);
        } else
	    close(urandom);
    }

    /* random key must have odd parity and not be weak */
    des_set_odd_parity(key);
    if (des_is_weak_key(key)) goto again;

  return(0);
}

/*
 * des_init_random_number_generator:
 *
 *    This routine takes a secret key possibly shared by a number
 * of servers and uses it to generate a random number stream that is
 * not shared by any of the other servers.  It does this by using the current
 * process id, host id, and the current time to the nearest second.  The
 * resulting stream seed is not useful information for cracking the secret
 * key.   Moreover, this routine keeps no copy of the secret key.
 *
 */
void 
des_init_random_number_generator(des_cblock *seed)
{
  SHA1_CTX sha;

  u_char results[20];
  char hname[64], accum[512];

  struct timeval when;

  SHA1Init(&sha);

  gethostname(hname, 63);
  gettimeofday(&when, (struct timezone *)NULL);

  snprintf(accum, 512, "%ld%ld%d%s%d%qd", when.tv_sec, when.tv_usec,
				     getpid(), hname, getuid(), *seed);

  memset(accum, 0, 512);
 
  SHA1Update(&sha, (u_char *)accum, strlen(accum));

  SHA1Final(results, &sha);

  des_random_seed(results);	/* XXX uses only first 8 bytes! */

  memset(results, 0, 20);

}
