]> jfr.im git - irc/quakenet/snircd.git/blob - ircd/random.c
Initial import of 2.10.12.01
[irc/quakenet/snircd.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,v 1.8 2004/10/06 00:22:09 entrope Exp $
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 }