* Created: Sun Mar 9 00:09:18 1997
*
* The original RNG was based on Secure Shell's random number generator
- * by Tatu Ylönen. This RNG has been rewritten twice since the creation.
+ * by Tatu Ylönen and was used as reference when programming this RNG.
+ * This RNG has been rewritten twice since the creation.
*/
#include "silcincludes.h"
+#ifndef WIN32
+#ifdef HAVE_GETSID
+extern pid_t getsid (pid_t __pid);
+#endif
+
+#ifdef HAVE_GETPGID
+extern pid_t getpgid (pid_t __pid);
+#endif
+#endif
+
#undef SILC_RNG_DEBUG
/*#define SILC_RNG_DEBUG*/
random pool. This is allocated when RNG object is allocated and
free'd when RNG object is free'd.
- uint8 threshold
+ uint8 threshhold
- Threshold to indicate when it is required to acquire more
+ 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.
unsigned char key[64];
SilcRngState state;
SilcHash sha1;
- uint8 threshold;
+ uint8 threshhold;
+ char *devrandom;
+ int fd_devurandom;
} SilcRngObject;
/* Allocates new RNG object. */
SILC_LOG_DEBUG(("Allocating new RNG object"));
new = silc_calloc(1, sizeof(*new));
+ new->fd_devurandom = -1;
memset(new->pool, 0, sizeof(new->pool));
memset(new->key, 0, sizeof(new->key));
new->state = NULL;
silc_hash_alloc("sha1", &new->sha1);
+ new->devrandom = strdup("/dev/random");
+
return new;
}
if (rng) {
memset(rng->pool, 0, sizeof(rng->pool));
memset(rng->key, 0, sizeof(rng->key));
- silc_free(rng->sha1);
+ silc_hash_free(rng->sha1);
+ silc_free(rng->devrandom);
+
+ if (rng->fd_devurandom != -1)
+ close(rng->fd_devurandom);
+
silc_free(rng);
}
}
silc_rng_get_medium_noise(rng);
silc_rng_get_hard_noise(rng);
silc_rng_get_soft_noise(rng);
+ silc_free(rng->devrandom);
+ rng->devrandom = strdup("/dev/urandom");
}
/* 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);
#ifdef HAVE_GETPGID
- silc_rng_xor(rng, getpgid(getpid() << 8), 2);
- silc_rng_xor(rng, getpgid(getpid() << 8), 3);
+ silc_rng_xor(rng, getpgid(getpid()) << 8, 2);
+ silc_rng_xor(rng, getpgid(getpid()) << 8, 3);
#endif
silc_rng_xor(rng, getgid(), 4);
#endif
silc_rng_xor(rng, getpgrp(), 5);
#endif
#ifdef HAVE_GETSID
- silc_rng_xor(rng, getsid(getpid() << 16), 6);
+ 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_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++);
+ 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++);
+ 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));
static void silc_rng_get_hard_noise(SilcRng rng)
{
- char buf[32];
+#ifndef SILC_WIN32
+ unsigned char buf[32];
int fd, len, i;
- /* Get noise from /dev/random if available */
- fd = open("/dev/random", O_RDONLY);
+ /* Get noise from /dev/[u]random if available */
+ fd = open(rng->devrandom, O_RDONLY);
if (fd < 0)
return;
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[1024];
+#ifndef SILC_WIN32
+ unsigned char buf[1024];
FILE *fd;
int i;
int c;
pclose(fd);
/* Add the buffer into random pool */
- silc_rng_add_noise(rng, buf, strlen(buf));
+ silc_rng_add_noise(rng, buf, i);
memset(buf, 0, sizeof(buf));
+#endif
}
/* This function adds the contents of the buffer as noise into random
uint32 iv[5];
/* Get the IV */
- memcpy(iv, &rng->pool[SILC_RNG_POOLSIZE - 256], sizeof(iv));
+ memcpy(iv, &rng->pool[16], sizeof(iv));
/* First CFB pass */
for (i = 0; i < SILC_RNG_POOLSIZE; i += 5) {
unsigned char silc_rng_get_byte(SilcRng rng)
{
- rng->threshold++;
+ rng->threshhold++;
- /* Get more soft noise after 64 bits threshold */
- if (rng->threshold >= 8)
+ /* Get more soft noise after 64 bits threshhold */
+ if (rng->threshhold >= 8)
silc_rng_get_soft_noise(rng);
- /* Get hard noise after 160 bits threshold, zero the threshold. */
- if (rng->threshold >= 20) {
- rng->threshold = 0;
+ /* Get hard noise after 160 bits threshhold, zero the threshhold. */
+ if (rng->threshhold >= 20) {
+ rng->threshhold = 0;
silc_rng_get_hard_noise(rng);
}
return global_rng ? silc_rng_get_byte(global_rng) : 0;
}
+/* Return random byte as fast as possible. Reads from /dev/urandom if
+ available. If not then return from normal RNG (not so fast). */
+
+unsigned char silc_rng_global_get_byte_fast()
+{
+#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
+}
+
uint16 silc_rng_global_get_rn16()
{
return global_rng ? silc_rng_get_rn16(global_rng) : 0;