Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / random.c
index 0fab4deecf9c3394269be2a462516bb71480e3f2..528b8d42c6add083305ecb7e898fa93711bda87e 100644 (file)
  * $Id$
  */
 #include "random.h"
-#include "config.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/time.h>
+#include "client.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "send.h"
 
 #include <string.h>
+#include <sys/time.h>
+
+
+char localkey[9] = "12345678";
+
+/* This devious-looking construct rolls a character to the left by r bits */
+#define char_roll(c, r)        (((c) << (r)) | ((c) >> (8 - (r))))
+
+/* this routine is intended to be called by the feature subsystem; it takes
+ * a key as found in the .conf and mashes it up for the seed for the random
+ * number generator.
+ */
+int
+random_seed_set(struct Client* from, const char* const* fields, int count)
+{
+  const char *p = 0;
+  int len, i, roll = 0;
+
+  if (count < 1) {
+    if (from) /* send an error */
+      return need_more_params(from, "SET");
+    else {
+      log_write(LS_CONFIG, L_ERROR, 0, "Not enough fields in F line");
+      return 0;
+    }
+  }
+
+  len = strlen(fields[0]);
 
-char localkey[9] = RANDOM_SEED;
+  /* logic is: go through loop at least 8 times, but use all bits of seed */
+  for (i = 0; i < (len < 8 ? 8 : len); i++, p++) {
+    if (!(i % len)) { /* if we've exceeded the string length, reset */
+      p = fields[0];
+      roll++; /* so latter part of string looks different from former */
+    }
+
+    /* set the appropriate location of localkey according to the following
+     * rules: first, roll current value by an amount depending on how many
+     * times we've touched this character.  Then take seed value and roll
+     * it by an amount depending upon how many times we've touched that
+     * character.  Finally, xor the values together.
+     */
+    localkey[i % 8] = char_roll(localkey[i % 8], (i / 8) % 8) ^
+      char_roll(*p, roll % 8);
+  }
+
+  return 1;
+}
+
+/* this is like memcpy except it xors the areas in memory. */
+static void
+memxor(void *dest, void *src, int n)
+{
+  unsigned char *d = (unsigned char *)dest;
+  unsigned char *s = (unsigned char *)src;
+
+  while (--n)
+    d[n] ^= s[n];
+}
 
 /*
  * MD5 transform algorithm, taken from code written by Colin Plumb,
@@ -39,6 +96,12 @@ char localkey[9] = RANDOM_SEED;
  * record: Cleaned up to work with ircd.  RANDOM_TOKEN is defined in
  * setup.h by the make script; if people start to "guess" your cookies,
  * consider recompiling your server with a different random token.
+ *
+ * Kev: Now the seed comes from the feature subsystem and is fed into a
+ * mash routine (random_set_seed) that depends on previous values of the
+ * localkey array; also, part of the output of the RNG is fed back into
+ * the localkey array.  Finally, the time values are xor'd with the local
+ * key to enhance non-determinability of the data fed into the MD5 core.
  */
 
 /* The four core functions - F1 is optimized somewhat */
@@ -73,11 +136,12 @@ unsigned int ircrandom(void)
   unsigned char in[16];
   struct timeval tv;
 
-  gettimeofday(&tv, NULL);
+  gettimeofday(&tv, 0);
 
   memcpy((void *)in, (void *)localkey, 8);
-  memcpy((void *)(in + 8), (void *)&tv.tv_sec, 4);
-  memcpy((void *)(in + 12), (void *)&tv.tv_usec, 4);
+  memcpy((void *)(in + 8), (void *)localkey, 8);
+  memxor((void *)(in + 8), (void *)&tv.tv_sec, 4);
+  memxor((void *)(in + 12), (void *)&tv.tv_usec, 4);
 
   a = 0x67452301;
   b = 0xefcdab89;
@@ -152,9 +216,18 @@ unsigned int ircrandom(void)
   MD5STEP(F4, c, d, a, b, (int)in[2] + 0x2ad7d2bb, 15);
   MD5STEP(F4, b, c, d, a, (int)in[9] + 0xeb86d391, 21);
 
+  /* This feeds part of the output of the random number generator into the
+   * seed to further obscure any patterns
+   */
+  memxor((void *)localkey, (void *)&a, 4);
+  memxor((void *)(localkey + 4), (void *)&b, 4);
+
   /*
    * We have 4 unsigned longs generated by the above sequence; this scrambles
    * them together so that if there is any pattern, it will be obscured.
+   *
+   * a and b are now part of the state of the random number generator;
+   * returning them is a security hazard.
    */
-  return (a ^ b ^ c ^ d);
+  return (c ^ d);
 }