updates.
[silc.git] / lib / silccrypt / silcrng.c
index 5f0230ccc167de1edf0f52f29872a76504df8abe..e9fe1c81ffe3d596b1572aeafa355104f388a2dc 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2001 Pekka Riikonen
 
   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
 /*
  * Created: Sun Mar  9 00:09:18 1997
  *
- * This RNG is based on Secure Shell's random number generator.
+ * The original RNG was based on Secure Shell's random number generator
+ * by Tatu Ylönen and was used as reference when programming this RNG.  
+ * This RNG has been rewritten twice since the creation.
  */
-/* XXX: Some operations block resulting slow initialization.
- * XXX: I have some pending changes to make this better. */
 
 #include "silcincludes.h"
 
 #undef SILC_RNG_DEBUG
-/* #define SILC_RNG_DEBUG */
+/*#define SILC_RNG_DEBUG*/
+
+/* Number of states to fetch data from pool. */
+#define SILC_RNG_STATE_NUM 4
+
+/* Byte size of the random data pool. */
+#define SILC_RNG_POOLSIZE 1024
 
 static uint32 silc_rng_get_position(SilcRng rng);
 static void silc_rng_stir_pool(SilcRng rng);
 static void silc_rng_xor(SilcRng rng, uint32 val, unsigned int pos);
-static void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, 
-                              uint32 len);
 static void silc_rng_exec_command(SilcRng rng, char *command);
 static void silc_rng_get_hard_noise(SilcRng rng);
 static void silc_rng_get_medium_noise(SilcRng rng);
@@ -98,12 +102,19 @@ typedef struct SilcRngStateContext {
        random pool. This is allocated when RNG object is allocated and
        free'd when RNG object is free'd.
 
+   uint8 threshhold
+
+       Threshhold to indicate when it is required to acquire more
+       noise from the environment.  More soft noise is acquired after
+       64 bits of output and hard noise every 160 bits of output.
+
 */
 typedef struct SilcRngObjectStruct {
   unsigned char pool[SILC_RNG_POOLSIZE];
   unsigned char key[64];
   SilcRngState state;
   SilcHash sha1;
+  uint8 threshhold;
 } SilcRngObject;
 
 /* Allocates new RNG object. */
@@ -173,39 +184,69 @@ void silc_rng_init(SilcRng rng)
   silc_rng_get_soft_noise(rng);
   silc_rng_get_medium_noise(rng);
   silc_rng_get_hard_noise(rng);
+  silc_rng_get_soft_noise(rng);
 }
 
 /* This function gets 'soft' noise from environment. */
 
 static void silc_rng_get_soft_noise(SilcRng rng)
 {
+#ifndef SILC_WIN32
   struct tms ptime;
+#endif
+  uint32 pos;
   
+  pos = silc_rng_get_position(rng);
+
   silc_rng_xor(rng, clock(), 0);
+#ifndef SILC_WIN32
+#ifdef HAVE_GETPID
   silc_rng_xor(rng, getpid(), 1);
-  silc_rng_xor(rng, getpgid(getpid() << 8), 2);
-  silc_rng_xor(rng, getpgid(getpid() << 8), 3);
+#ifdef HAVE_GETPGID
+  silc_rng_xor(rng, getpgid(getpid()) << 8, 2);
+  silc_rng_xor(rng, getpgid(getpid()) << 8, 3);
+#endif
   silc_rng_xor(rng, getgid(), 4);
+#endif
+#ifdef HAVE_GETPGRP
   silc_rng_xor(rng, getpgrp(), 5);
-  silc_rng_xor(rng, getsid(getpid() << 16), 6);
+#endif
+#ifdef HAVE_GETSID
+  silc_rng_xor(rng, getsid(getpid()) << 16, 6);
+#endif
   silc_rng_xor(rng, times(&ptime), 7);
   silc_rng_xor(rng, ptime.tms_utime, 8);
-  silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 9);
-  silc_rng_xor(rng, (ptime.tms_stime + ptime.tms_cutime), 10);
-  silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), 11);
-  silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_stime), 12);
-  silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_cstime), 13);
-  silc_rng_xor(rng, (ptime.tms_utime ^ ptime.tms_stime), 14);
-  silc_rng_xor(rng, (ptime.tms_stime ^ ptime.tms_cutime), 15);
-  silc_rng_xor(rng, (ptime.tms_cutime + ptime.tms_stime), 16);
-  silc_rng_xor(rng, (ptime.tms_stime << 8), 17);
-  silc_rng_xor(rng, clock() << 4, 18);
-  silc_rng_xor(rng, getpgid(getpid() << 8), 19);
-  silc_rng_xor(rng, getpgrp(), 20);
-  silc_rng_xor(rng, getsid(getpid() << 16), 21);
-  silc_rng_xor(rng, times(&ptime), 22);
-  silc_rng_xor(rng, ptime.tms_utime, 23);
-  silc_rng_xor(rng, getpgrp(), 24);
+  silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), pos++);
+  silc_rng_xor(rng, (ptime.tms_stime + ptime.tms_cutime), pos++);
+  silc_rng_xor(rng, (ptime.tms_utime + ptime.tms_stime), pos++);
+  silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_stime), pos++);
+  silc_rng_xor(rng, (ptime.tms_cutime ^ ptime.tms_cstime), pos++);
+  silc_rng_xor(rng, (ptime.tms_utime ^ ptime.tms_stime), pos++);
+  silc_rng_xor(rng, (ptime.tms_stime ^ ptime.tms_cutime), pos++);
+  silc_rng_xor(rng, (ptime.tms_cutime + ptime.tms_stime), pos++);
+  silc_rng_xor(rng, (ptime.tms_stime << 8), pos++);
+#endif
+  silc_rng_xor(rng, clock() << 4, pos++);
+#ifndef SILC_WIN32
+#ifdef HAVE_GETPGID
+  silc_rng_xor(rng, getpgid(getpid()) << 8, pos++);
+#endif
+#ifdef HAVE_GETPGRP
+  silc_rng_xor(rng, getpgrp(), pos++);
+#endif
+#ifdef HAVE_SETSID
+  silc_rng_xor(rng, getsid(getpid()) << 16, pos++);
+#endif
+  silc_rng_xor(rng, times(&ptime), pos++);
+  silc_rng_xor(rng, ptime.tms_utime, pos++);
+#ifdef HAVE_GETPGRP
+  silc_rng_xor(rng, getpgrp(), pos++);
+#endif
+#endif
+
+#ifdef SILC_RNG_DEBUG
+  SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool));
+#endif
 
   /* Stir random pool */
   silc_rng_stir_pool(rng);
@@ -215,14 +256,14 @@ static void silc_rng_get_soft_noise(SilcRng rng)
 
 static void silc_rng_get_medium_noise(SilcRng rng)
 {
-  silc_rng_exec_command(rng, "ps -lefaww 2> /dev/null");
-  silc_rng_exec_command(rng, "ls -afiln 2> /dev/null");
-  silc_rng_exec_command(rng, "ps -asww 2> /dev/null");
+  silc_rng_exec_command(rng, "ps -leaww 2> /dev/null");
+  silc_rng_exec_command(rng, "ls -afiln ~ 2> /dev/null");
   silc_rng_exec_command(rng, "ls -afiln /proc 2> /dev/null");
-  /*
-  silc_rng_exec_command(rng, "ps -ef 2> /dev/null");
-  silc_rng_exec_command(rng, "ls -alin /dev 2> /dev/null");
-  */
+  silc_rng_exec_command(rng, "ps -axww 2> /dev/null");
+
+#ifdef SILC_RNG_DEBUG
+  SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool));
+#endif
 }
 
 /* This function gets 'hard' noise from environment. This tries to
@@ -230,6 +271,7 @@ static void silc_rng_get_medium_noise(SilcRng rng)
 
 static void silc_rng_get_hard_noise(SilcRng rng)
 {
+#ifndef SILC_WIN32
   char buf[32];
   int fd, len, i;
   
@@ -240,23 +282,29 @@ static void silc_rng_get_hard_noise(SilcRng rng)
 
   fcntl(fd, F_SETFL, O_NONBLOCK);
 
-  for (i = 0; i < 8; i++) {
+  for (i = 0; i < 2; i++) {
     len = read(fd, buf, sizeof(buf));
     if (len <= 0)
       goto out;
     silc_rng_add_noise(rng, buf, len);
   }
 
+#ifdef SILC_RNG_DEBUG
+  SILC_LOG_HEXDUMP(("pool"), rng->pool, sizeof(rng->pool));
+#endif
+
  out:
   close(fd);
   memset(buf, 0, sizeof(buf));
+#endif
 }
 
 /* Execs command and gets noise from its output */
 
 static void silc_rng_exec_command(SilcRng rng, char *command)
 {
-  char buf[2048];
+#ifndef SILC_WIN32
+  char buf[1024];
   FILE *fd;
   int i;
   int c;
@@ -282,13 +330,13 @@ static void silc_rng_exec_command(SilcRng rng, char *command)
   /* Add the buffer into random pool */
   silc_rng_add_noise(rng, buf, strlen(buf));
   memset(buf, 0, sizeof(buf));
+#endif
 }
 
 /* This function adds the contents of the buffer as noise into random 
    pool. After adding the noise the pool is stirred. */
 
-static void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, 
-                              uint32 len)
+void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, uint32 len)
 {
   uint32 i, pos;
 
@@ -365,7 +413,7 @@ static uint32 silc_rng_get_position(SilcRng rng)
     rng->state->pos = rng->state->low;
 
 #ifdef SILC_RNG_DEBUG
-    fprintf(stderr, "state: %p: low: %d, pos: %d\n", 
+    fprintf(stderr, "state: %p: low: %lu, pos: %lu\n", 
            rng->state, rng->state->low, rng->state->pos);
 #endif
 
@@ -374,10 +422,22 @@ static uint32 silc_rng_get_position(SilcRng rng)
   return pos;
 }
 
-/* returns random byte. Every two byte is from pools low or high state. */
+/* Returns random byte. */
 
 unsigned char silc_rng_get_byte(SilcRng rng)
 {
+  rng->threshhold++;
+
+  /* Get more soft noise after 64 bits threshhold */
+  if (rng->threshhold >= 8)
+    silc_rng_get_soft_noise(rng);
+
+  /* Get hard noise after 160 bits threshhold, zero the threshhold. */
+  if (rng->threshhold >= 20) {
+    rng->threshhold = 0;
+    silc_rng_get_hard_noise(rng);
+  }
+
   return rng->pool[silc_rng_get_position(rng)];
 }
 
@@ -499,3 +559,9 @@ unsigned char *silc_rng_global_get_rn_data(uint32 len)
 {
   return global_rng ? silc_rng_get_rn_data(global_rng, len) : NULL;
 }
+
+void silc_rng_global_add_noise(unsigned char *buffer, uint32 len)
+{
+  if (global_rng)
+    silc_rng_add_noise(global_rng, buffer, len);
+}