updates.
[silc.git] / lib / silccrypt / silcrng.c
index 742cb59a9da559cb0ae053e780e1a930c7771c73..e9fe1c81ffe3d596b1572aeafa355104f388a2dc 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
 
   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
 
   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
  *
 /*
  * 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
 
 #include "silcincludes.h"
 
 #undef SILC_RNG_DEBUG
-/* #define SILC_RNG_DEBUG */
+/*#define SILC_RNG_DEBUG*/
 
 
-static unsigned int silc_rng_get_position(SilcRng rng);
+/* 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_stir_pool(SilcRng rng);
-static void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos);
-static void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, 
-                              unsigned int len);
+static void silc_rng_xor(SilcRng rng, uint32 val, unsigned int pos);
 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);
 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);
@@ -50,8 +54,8 @@ static void silc_rng_get_soft_noise(SilcRng rng);
    from the same point of the pool. Short description of the fields
    following.
 
    from the same point of the pool. Short description of the fields
    following.
 
-   unsigned int low
-   unsigned int pos
+   uint32 low
+   uint32 pos
 
        The index for the random pool buffer. Lowest and current
        positions.
 
        The index for the random pool buffer. Lowest and current
        positions.
@@ -63,8 +67,8 @@ static void silc_rng_get_soft_noise(SilcRng rng);
 
 */
 typedef struct SilcRngStateContext {
 
 */
 typedef struct SilcRngStateContext {
-  unsigned int low;
-  unsigned int pos;
+  uint32 low;
+  uint32 pos;
   struct SilcRngStateContext *next;
 } *SilcRngState;
 
   struct SilcRngStateContext *next;
 } *SilcRngState;
 
@@ -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.
 
        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;
 */
 typedef struct SilcRngObjectStruct {
   unsigned char pool[SILC_RNG_POOLSIZE];
   unsigned char key[64];
   SilcRngState state;
   SilcHash sha1;
+  uint8 threshhold;
 } SilcRngObject;
 
 /* Allocates new RNG object. */
 } 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);
   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)
 {
 }
 
 /* This function gets 'soft' noise from environment. */
 
 static void silc_rng_get_soft_noise(SilcRng rng)
 {
+#ifndef SILC_WIN32
   struct tms ptime;
   struct tms ptime;
+#endif
+  uint32 pos;
   
   
+  pos = silc_rng_get_position(rng);
+
   silc_rng_xor(rng, clock(), 0);
   silc_rng_xor(rng, clock(), 0);
+#ifndef SILC_WIN32
+#ifdef HAVE_GETPID
   silc_rng_xor(rng, getpid(), 1);
   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);
   silc_rng_xor(rng, getgid(), 4);
+#endif
+#ifdef HAVE_GETPGRP
   silc_rng_xor(rng, getpgrp(), 5);
   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, 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);
 
   /* 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)
 {
 
 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, "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
 }
 
 /* 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)
 {
 
 static void silc_rng_get_hard_noise(SilcRng rng)
 {
+#ifndef SILC_WIN32
   char buf[32];
   int fd, len, i;
   
   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);
 
 
   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);
   }
 
     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));
  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)
 {
 }
 
 /* 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;
   FILE *fd;
   int i;
   int c;
@@ -282,15 +330,15 @@ 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));
   /* 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. */
 
 }
 
 /* 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, 
-                              unsigned int len)
+void silc_rng_add_noise(SilcRng rng, unsigned char *buffer, uint32 len)
 {
 {
-  unsigned int i, pos;
+  uint32 i, pos;
 
   pos = silc_rng_get_position(rng);
 
 
   pos = silc_rng_get_position(rng);
 
@@ -307,7 +355,7 @@ static void silc_rng_add_noise(SilcRng rng, unsigned char *buffer,
 
 /* XOR's data into the pool */
 
 
 /* XOR's data into the pool */
 
-static void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos)
+static void silc_rng_xor(SilcRng rng, uint32 val, unsigned int pos)
 {
   assert(rng != NULL);
   rng->pool[pos] ^= val + val;
 {
   assert(rng != NULL);
   rng->pool[pos] ^= val + val;
@@ -319,7 +367,7 @@ static void silc_rng_xor(SilcRng rng, unsigned int val, unsigned int pos)
 static void silc_rng_stir_pool(SilcRng rng)
 {
   int i;
 static void silc_rng_stir_pool(SilcRng rng)
 {
   int i;
-  unsigned long iv[5];
+  uint32 iv[5];
 
   /* Get the IV */
   memcpy(iv, &rng->pool[SILC_RNG_POOLSIZE - 256], sizeof(iv));
 
   /* Get the IV */
   memcpy(iv, &rng->pool[SILC_RNG_POOLSIZE - 256], sizeof(iv));
@@ -353,10 +401,10 @@ static void silc_rng_stir_pool(SilcRng rng)
 /* Returns next position where data is fetched from the pool or
    put to the pool. */
 
 /* Returns next position where data is fetched from the pool or
    put to the pool. */
 
-static unsigned int silc_rng_get_position(SilcRng rng)
+static uint32 silc_rng_get_position(SilcRng rng)
 {
   SilcRngState next;
 {
   SilcRngState next;
-  unsigned int pos;
+  uint32 pos;
 
   next = rng->state->next;
 
 
   next = rng->state->next;
 
@@ -365,7 +413,7 @@ static unsigned int silc_rng_get_position(SilcRng rng)
     rng->state->pos = rng->state->low;
 
 #ifdef SILC_RNG_DEBUG
     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
 
            rng->state, rng->state->low, rng->state->pos);
 #endif
 
@@ -374,19 +422,31 @@ static unsigned int silc_rng_get_position(SilcRng rng)
   return pos;
 }
 
   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)
 {
 
 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)];
 }
 
 /* Returns 16 bit random number */
 
   return rng->pool[silc_rng_get_position(rng)];
 }
 
 /* Returns 16 bit random number */
 
-unsigned short silc_rng_get_rn16(SilcRng rng)
+uint16 silc_rng_get_rn16(SilcRng rng)
 {
   unsigned char rn[2];
 {
   unsigned char rn[2];
-  unsigned short num;
+  uint16 num;
 
   rn[0] = silc_rng_get_byte(rng);
   rn[1] = silc_rng_get_byte(rng);
 
   rn[0] = silc_rng_get_byte(rng);
   rn[1] = silc_rng_get_byte(rng);
@@ -397,10 +457,10 @@ unsigned short silc_rng_get_rn16(SilcRng rng)
 
 /* Returns 32 bit random number */
 
 
 /* Returns 32 bit random number */
 
-unsigned int silc_rng_get_rn32(SilcRng rng)
+uint32 silc_rng_get_rn32(SilcRng rng)
 {
   unsigned char rn[4];
 {
   unsigned char rn[4];
-  unsigned short num;
+  uint16 num;
 
   rn[0] = silc_rng_get_byte(rng);
   rn[1] = silc_rng_get_byte(rng);
 
   rn[0] = silc_rng_get_byte(rng);
   rn[1] = silc_rng_get_byte(rng);
@@ -413,7 +473,7 @@ unsigned int silc_rng_get_rn32(SilcRng rng)
 
 /* Returns random number string. Returned string is in HEX format. */
 
 
 /* Returns random number string. Returned string is in HEX format. */
 
-unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len)
+unsigned char *silc_rng_get_rn_string(SilcRng rng, uint32 len)
 {
   int i;
   unsigned char *string;
 {
   int i;
   unsigned char *string;
@@ -428,7 +488,7 @@ unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len)
 
 /* Returns random number binary data. */
 
 
 /* Returns random number binary data. */
 
-unsigned char *silc_rng_get_rn_data(SilcRng rng, unsigned int len)
+unsigned char *silc_rng_get_rn_data(SilcRng rng, uint32 len)
 {
   int i;
   unsigned char *data;
 {
   int i;
   unsigned char *data;
@@ -480,22 +540,28 @@ unsigned char silc_rng_global_get_byte()
   return global_rng ? silc_rng_get_byte(global_rng) : 0;
 }
 
   return global_rng ? silc_rng_get_byte(global_rng) : 0;
 }
 
-unsigned short silc_rng_global_get_rn16()
+uint16 silc_rng_global_get_rn16()
 {
   return global_rng ? silc_rng_get_rn16(global_rng) : 0;
 }
 
 {
   return global_rng ? silc_rng_get_rn16(global_rng) : 0;
 }
 
-unsigned int silc_rng_global_get_rn32()
+uint32 silc_rng_global_get_rn32()
 {
   return global_rng ? silc_rng_get_rn32(global_rng) : 0;
 }
 
 {
   return global_rng ? silc_rng_get_rn32(global_rng) : 0;
 }
 
-unsigned char *silc_rng_global_get_rn_string(unsigned int len)
+unsigned char *silc_rng_global_get_rn_string(uint32 len)
 {
   return global_rng ? silc_rng_get_rn_string(global_rng, len) : NULL;
 }
 
 {
   return global_rng ? silc_rng_get_rn_string(global_rng, len) : NULL;
 }
 
-unsigned char *silc_rng_global_get_rn_data(unsigned int len)
+unsigned char *silc_rng_global_get_rn_data(uint32 len)
 {
   return global_rng ? silc_rng_get_rn_data(global_rng, len) : NULL;
 }
 {
   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);
+}