Buffer overflow fix.
[silc.git] / lib / silccrypt / silcrng.c
index 06340066165b94cb1dfd6371e88750a2b1d13ff0..620ebecfba182d14445520bf738bb76f820afdda 100644 (file)
@@ -44,7 +44,7 @@ extern pid_t getpgid (pid_t __pid);
 #define SILC_RNG_STATE_NUM 4
 
 /* Byte size of the random data pool. */
-#define SILC_RNG_POOLSIZE 1024
+#define SILC_RNG_POOLSIZE 1024 + 1
 
 static SilcUInt32 silc_rng_get_position(SilcRng rng);
 static void silc_rng_stir_pool(SilcRng rng);
@@ -158,6 +158,8 @@ SilcRng silc_rng_alloc(void)
 void silc_rng_free(SilcRng rng)
 {
   if (rng) {
+    SilcRngState t, n;
+
     memset(rng->pool, 0, sizeof(rng->pool));
     memset(rng->key, 0, sizeof(rng->key));
     silc_hash_free(rng->sha1);
@@ -166,6 +168,13 @@ void silc_rng_free(SilcRng rng)
     if (rng->fd_devurandom != -1)
       close(rng->fd_devurandom);
 
+    for (t = rng->state->next; t != rng->state; ) {
+      n = t->next;
+      silc_free(t);
+      t = n;
+    }
+    silc_free(rng->state);
+
     silc_free(rng);
   }
 }
@@ -399,7 +408,7 @@ static void silc_rng_stir_pool(SilcRng rng)
 
   /* First CFB pass */
   for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) {
-    rng->sha1->hash->transform(iv, rng->key);
+    silc_hash_transform(rng->sha1, iv, rng->key);
     iv[0] = rng->pool[i] ^= iv[0];
     iv[1] = rng->pool[i + 1] ^= iv[1];
     iv[2] = rng->pool[i + 2] ^= iv[2];
@@ -412,7 +421,7 @@ static void silc_rng_stir_pool(SilcRng rng)
 
   /* Second CFB pass */
   for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) {
-    rng->sha1->hash->transform(iv, rng->key);
+    silc_hash_transform(rng->sha1, iv, rng->key);
     iv[0] = rng->pool[i] ^= iv[0];
     iv[1] = rng->pool[i + 1] ^= iv[1];
     iv[2] = rng->pool[i + 2] ^= iv[2];
@@ -466,6 +475,30 @@ SilcUInt8 silc_rng_get_byte(SilcRng rng)
   return rng->pool[silc_rng_get_position(rng)];
 }
 
+/* Return random byte as fast as possible. Reads from /dev/urandom if
+   available. If not then return from normal RNG (not so fast). */
+
+SilcUInt8 silc_rng_get_byte_fast(SilcRng rng)
+{
+#ifndef SILC_WIN32
+  unsigned char buf[1];
+
+  if (rng->fd_devurandom == -1) {
+    rng->fd_devurandom = open("/dev/urandom", O_RDONLY);
+    if (rng < 0)
+      return silc_rng_get_byte(rng);
+    fcntl(rng->fd_devurandom, F_SETFL, O_NONBLOCK);
+  }
+
+  if (read(rng->fd_devurandom, buf, sizeof(buf)) < 0)
+    return silc_rng_get_byte(rng);
+
+  return buf[0];
+#else
+  return silc_rng_get_byte(rng);
+#endif
+}
+
 /* Returns 16 bit random number */
 
 SilcUInt16 silc_rng_get_rn16(SilcRng rng)
@@ -570,26 +603,7 @@ SilcUInt8 silc_rng_global_get_byte(void)
 
 SilcUInt8 silc_rng_global_get_byte_fast(void)
 {
-#ifndef SILC_WIN32
-  unsigned char buf[1];
-
-  if (!global_rng)
-    return 0;
-
-  if (global_rng->fd_devurandom == -1) {
-    global_rng->fd_devurandom = open("/dev/urandom", O_RDONLY);
-    if (global_rng < 0)
-      return silc_rng_global_get_byte();
-    fcntl(global_rng->fd_devurandom, F_SETFL, O_NONBLOCK);
-  }
-
-  if (read(global_rng->fd_devurandom, buf, sizeof(buf)) < 0)
-    return silc_rng_global_get_byte();
-
-  return buf[0];
-#else
-  return silc_rng_global_get_byte();
-#endif
+  return global_rng ? silc_rng_get_byte_fast(global_rng) : 0;
 }
 
 SilcUInt16 silc_rng_global_get_rn16(void)