]> jfr.im git - irc/rqf/shadowircd.git/blame - libratbox/src/arc4random.c
Copied libratbox and related stuff from shadowircd upstream.
[irc/rqf/shadowircd.git] / libratbox / src / arc4random.c
CommitLineData
94b4fbf9 1/* $Id: arc4random.c 26092 2008-09-19 15:13:52Z androsyn $ */
4414eb3c
VY
2/* $$$: arc4random.c 2005/02/08 robert */
3/* $NetBSD: arc4random.c,v 1.5.2.1 2004/03/26 22:52:50 jmc Exp $ */
4/* $OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $ */
5
6/*
7 * Arc4 random number generator for OpenBSD.
8 * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
9 *
10 * Modification and redistribution in source and binary forms is
11 * permitted provided that due credit is given to the author and the
12 * OpenBSD project by leaving this copyright notice intact.
13 */
14
15/*
16 * This code is derived from section 17.1 of Applied Cryptography,
17 * second edition, which describes a stream cipher allegedly
18 * compatible with RSA Labs "RC4" cipher (the actual description of
19 * which is a trade secret). The same algorithm is used as a stream
20 * cipher called "arcfour" in Tatu Ylonen's ssh package.
21 *
22 * Here the stream cipher has been modified always to include the time
23 * when initializing the state. That makes it impossible to
24 * regenerate the same random sequence twice, so this can't be used
25 * for encryption, but will generate good random numbers.
26 *
27 * RC4 is a registered trademark of RSA Laboratories.
28 */
29
30
31#include <libratbox_config.h>
32#include <ratbox_lib.h>
33
34#if !defined(HAVE_OPENSSL) && !defined(HAVE_GNUTLS) && !defined(HAVE_ARC4RANDOM)
35
36#include "arc4random.h"
37
38#ifdef HAVE_GETRUSAGE
39#include <sys/resource.h>
40#endif
41
42
43
94b4fbf9
VY
44struct arc4_stream
45{
4414eb3c
VY
46 uint8_t i;
47 uint8_t j;
48 uint8_t s[256];
49};
50
51
94b4fbf9 52static int rs_initialized;
4414eb3c
VY
53static struct arc4_stream rs;
54
55static inline void arc4_init(struct arc4_stream *);
56static inline void arc4_addrandom(struct arc4_stream *, uint8_t *, int);
57static void arc4_stir(struct arc4_stream *);
58static inline uint8_t arc4_getbyte(struct arc4_stream *);
59static inline uint32_t arc4_getword(struct arc4_stream *);
60
61static inline void
62arc4_init(struct arc4_stream *as)
63{
94b4fbf9 64 int n;
4414eb3c 65
94b4fbf9 66 for(n = 0; n < 256; n++)
4414eb3c
VY
67 as->s[n] = n;
68 as->i = 0;
69 as->j = 0;
70}
71
72static inline void
73arc4_addrandom(struct arc4_stream *as, uint8_t *dat, int datlen)
74{
94b4fbf9 75 int n;
4414eb3c
VY
76 uint8_t si;
77
78 as->i--;
94b4fbf9
VY
79 for(n = 0; n < 256; n++)
80 {
4414eb3c
VY
81 as->i = (as->i + 1);
82 si = as->s[as->i];
83 as->j = (as->j + si + dat[n % datlen]);
84 as->s[as->i] = as->s[as->j];
85 as->s[as->j] = si;
86 }
87 as->j = as->i;
88}
89
90static void
91arc4_stir(struct arc4_stream *as)
92{
93 struct timeval tv;
94 pid_t pid;
95 int n;
96 /* XXX this doesn't support egd sources or similiar */
97
98 pid = getpid();
94b4fbf9 99 arc4_addrandom(as, (void *)&pid, sizeof(pid));
4414eb3c
VY
100
101 rb_gettimeofday(&tv, NULL);
102 arc4_addrandom(as, (void *)&tv.tv_sec, sizeof(&tv.tv_sec));
103 arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec));
104 rb_gettimeofday(&tv, NULL);
105 arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec));
94b4fbf9 106
4414eb3c
VY
107#if defined(HAVE_GETRUSAGE) && RUSAGE_SELF
108 {
109 struct rusage buf;
110 getrusage(RUSAGE_SELF, &buf);
111 arc4_addrandom(as, (void *)&buf, sizeof(buf));
94b4fbf9
VY
112 memset(&buf, 0, sizeof(buf))}
113#endif
4414eb3c 114
94b4fbf9 115#if !defined(_WIN32)
4414eb3c
VY
116 {
117 uint8_t rnd[128];
118 int fd;
119 fd = open("/dev/urandom", O_RDONLY);
94b4fbf9 120 if(fd != -1)
4414eb3c
VY
121 {
122 read(fd, rnd, sizeof(rnd));
123 close(fd);
124 arc4_addrandom(as, (void *)rnd, sizeof(rnd));
94b4fbf9 125 memset(&rnd, 0, sizeof(rnd));
4414eb3c 126 }
94b4fbf9 127
4414eb3c
VY
128 }
129#else
130 {
131 LARGE_INTEGER performanceCount;
94b4fbf9 132 if(QueryPerformanceCounter(&performanceCount))
4414eb3c
VY
133 {
134 arc4_addrandom(as, (void *)&performanceCount, sizeof(performanceCount));
135 }
94b4fbf9
VY
136 HMODULE lib = LoadLibrary("ADVAPI32.DLL");
137 if(lib)
138 {
139 uint8_t rnd[128];
140 BOOLEAN(APIENTRY * pfn) (void *, ULONG) =
141 (BOOLEAN(APIENTRY *) (void *, ULONG))GetProcAddress(lib,
142 "SystemFunction036");
143 if(pfn)
144 {
145 if(pfn(rnd, sizeof(rnd)) == TRUE)
146 arc4_addrandom(as, (void *)rnd, sizeof(rnd));
147 memset(&rnd, 0, sizeof(rnd));
148 }
149 }
4414eb3c
VY
150 }
151#endif
152
153
154 /*
155 * Throw away the first N words of output, as suggested in the
156 * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
157 * by Fluher, Mantin, and Shamir.
158 * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
159 * N = 256 in our case.
160 */
94b4fbf9 161 for(n = 0; n < 256 * 4; n++)
4414eb3c
VY
162 arc4_getbyte(as);
163}
164
165static inline uint8_t
166arc4_getbyte(struct arc4_stream *as)
167{
168 uint8_t si, sj;
169
170 as->i = (as->i + 1);
171 si = as->s[as->i];
172 as->j = (as->j + si);
173 sj = as->s[as->j];
174 as->s[as->i] = sj;
175 as->s[as->j] = si;
176 return (as->s[(si + sj) & 0xff]);
177}
178
179static inline uint32_t
180arc4_getword(struct arc4_stream *as)
181{
182 uint32_t val;
183 val = arc4_getbyte(as) << 24;
184 val |= arc4_getbyte(as) << 16;
185 val |= arc4_getbyte(as) << 8;
186 val |= arc4_getbyte(as);
187 return val;
188}
189
190void
191arc4random_stir(void)
192{
94b4fbf9
VY
193 if(!rs_initialized)
194 {
4414eb3c
VY
195 arc4_init(&rs);
196 rs_initialized = 1;
197 }
198 arc4_stir(&rs);
199}
200
201void
202arc4random_addrandom(uint8_t *dat, int datlen)
203{
94b4fbf9 204 if(!rs_initialized)
4414eb3c
VY
205 arc4random_stir();
206 arc4_addrandom(&rs, dat, datlen);
207}
208
209uint32_t
210arc4random(void)
211{
94b4fbf9 212 if(!rs_initialized)
4414eb3c
VY
213 arc4random_stir();
214 return arc4_getword(&rs);
215}
216
217#endif