ircu2.10.12 pk910 fork
[ircu2.10.12-pk.git] / ircd / random.c
1 /*
2  * IRC - Internet Relay Chat, ircd/random.c
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 1, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 /** @file
19  * @brief 32-bit pseudo-random number generator implementation.
20  * @version $Id: random.c 1235 2004-10-06 00:22:09Z entrope $
21  */
22 #include "config.h"
23
24 #include "random.h"
25 #include "client.h"
26 #include "ircd_log.h"
27 #include "ircd_md5.h"
28 #include "ircd_reply.h"
29 #include "send.h"
30
31 #include <string.h>
32 #include <sys/time.h>
33
34 /** Pseudo-random number generator state. */
35 static struct MD5Context localkey;
36 /** Next byte position in #localkey to insert at. */
37 static unsigned int localkey_pos;
38
39 /** Add bytes to #localkey.
40  * This should be fairly resistant to adding non-random bytes, but the
41  * more random the bytes are, the harder it is for an attacker to
42  * guess the internal state.
43  * @param[in] buf Buffer of bytes to add.
44  * @param[in] count Number of bytes to add.
45  */
46 static void
47 random_add_entropy(const char *buf, unsigned int count)
48 {
49   while (count--) {
50     localkey.in[localkey_pos++] ^= *buf++;
51     if (localkey_pos >= sizeof(localkey.in))
52       localkey_pos = 0;
53   }
54 }
55
56 /** Seed the PRNG with a string.
57  * @param[in] from Client setting the seed (may be NULL).
58  * @param[in] fields Input arguments (fields[0] is used).
59  * @param[in] count Number of input arguments.
60  * @return Non-zero on success, zero on error.
61  */
62 int
63 random_seed_set(struct Client* from, const char* const* fields, int count)
64 {
65   if (count < 1) {
66     if (from) /* send an error */
67       return need_more_params(from, "SET");
68     else {
69       log_write(LS_CONFIG, L_ERROR, 0, "Not enough fields in F line");
70       return 0;
71     }
72   }
73
74   random_add_entropy(fields[0], strlen(fields[0]));
75   return 1;
76 }
77
78 /** Generate a pseudo-random number.
79  * This uses the #localkey structure plus current time as input to
80  * MD5, feeding most of the MD5 output back to #localkey and using one
81  * output words as the pseudo-random output.
82  * @return A 32-bit pseudo-random number.
83  */
84 unsigned int ircrandom(void)
85 {
86   struct timeval tv;
87   char usec[3];
88
89   /* Add some randomness to the pool. */
90   gettimeofday(&tv, 0);
91   usec[0] = tv.tv_usec;
92   usec[1] = tv.tv_usec >> 8;
93   usec[2] = tv.tv_usec >> 16;
94   random_add_entropy(usec, 3);
95
96   /* Perform MD5 step. */
97   localkey.buf[0] = 0x67452301;
98   localkey.buf[1] = 0xefcdab89;
99   localkey.buf[2] = 0x98badcfe;
100   localkey.buf[3] = 0x10325476;
101   MD5Transform(localkey.buf, (uint32*)localkey.in);
102
103   /* Feed back 12 bytes of hash value into randomness pool. */
104   random_add_entropy((char*)localkey.buf, 12);
105
106   /* Return the final word of hash, which should not provide any
107    * useful insight into current pool contents. */
108   return localkey.buf[3];
109 }