]>
Commit | Line | Data |
---|---|---|
4414eb3c VY |
1 | /* $Id: arc4random.c 25705 2008-07-11 18:21:57Z androsyn $ */ |
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 | ||
44 | struct arc4_stream { | |
45 | uint8_t i; | |
46 | uint8_t j; | |
47 | uint8_t s[256]; | |
48 | }; | |
49 | ||
50 | ||
51 | static int rs_initialized; | |
52 | static struct arc4_stream rs; | |
53 | ||
54 | static inline void arc4_init(struct arc4_stream *); | |
55 | static inline void arc4_addrandom(struct arc4_stream *, uint8_t *, int); | |
56 | static void arc4_stir(struct arc4_stream *); | |
57 | static inline uint8_t arc4_getbyte(struct arc4_stream *); | |
58 | static inline uint32_t arc4_getword(struct arc4_stream *); | |
59 | ||
60 | static inline void | |
61 | arc4_init(struct arc4_stream *as) | |
62 | { | |
63 | int n; | |
64 | ||
65 | for (n = 0; n < 256; n++) | |
66 | as->s[n] = n; | |
67 | as->i = 0; | |
68 | as->j = 0; | |
69 | } | |
70 | ||
71 | static inline void | |
72 | arc4_addrandom(struct arc4_stream *as, uint8_t *dat, int datlen) | |
73 | { | |
74 | int n; | |
75 | uint8_t si; | |
76 | ||
77 | as->i--; | |
78 | for (n = 0; n < 256; n++) { | |
79 | as->i = (as->i + 1); | |
80 | si = as->s[as->i]; | |
81 | as->j = (as->j + si + dat[n % datlen]); | |
82 | as->s[as->i] = as->s[as->j]; | |
83 | as->s[as->j] = si; | |
84 | } | |
85 | as->j = as->i; | |
86 | } | |
87 | ||
88 | static void | |
89 | arc4_stir(struct arc4_stream *as) | |
90 | { | |
91 | struct timeval tv; | |
92 | pid_t pid; | |
93 | int n; | |
94 | /* XXX this doesn't support egd sources or similiar */ | |
95 | ||
96 | pid = getpid(); | |
97 | arc4_addrandom(as, (void *)&pid, sizeof(pid)); | |
98 | ||
99 | rb_gettimeofday(&tv, NULL); | |
100 | arc4_addrandom(as, (void *)&tv.tv_sec, sizeof(&tv.tv_sec)); | |
101 | arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec)); | |
102 | rb_gettimeofday(&tv, NULL); | |
103 | arc4_addrandom(as, (void *)&tv.tv_usec, sizeof(&tv.tv_usec)); | |
104 | ||
105 | #if defined(HAVE_GETRUSAGE) && RUSAGE_SELF | |
106 | { | |
107 | struct rusage buf; | |
108 | getrusage(RUSAGE_SELF, &buf); | |
109 | arc4_addrandom(as, (void *)&buf, sizeof(buf)); | |
110 | memset(&buf, 0, sizeof(buf)) | |
111 | } | |
112 | #endif | |
113 | ||
114 | #if !defined(WIN32) | |
115 | { | |
116 | uint8_t rnd[128]; | |
117 | int fd; | |
118 | fd = open("/dev/urandom", O_RDONLY); | |
119 | if (fd != -1) | |
120 | { | |
121 | read(fd, rnd, sizeof(rnd)); | |
122 | close(fd); | |
123 | arc4_addrandom(as, (void *)rnd, sizeof(rnd)); | |
124 | } | |
125 | } | |
126 | #else | |
127 | { | |
128 | LARGE_INTEGER performanceCount; | |
129 | if (QueryPerformanceCounter (&performanceCount)) | |
130 | { | |
131 | arc4_addrandom(as, (void *)&performanceCount, sizeof(performanceCount)); | |
132 | } | |
133 | } | |
134 | #endif | |
135 | ||
136 | ||
137 | /* | |
138 | * Throw away the first N words of output, as suggested in the | |
139 | * paper "Weaknesses in the Key Scheduling Algorithm of RC4" | |
140 | * by Fluher, Mantin, and Shamir. | |
141 | * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps | |
142 | * N = 256 in our case. | |
143 | */ | |
144 | for (n = 0; n < 256 * 4; n++) | |
145 | arc4_getbyte(as); | |
146 | } | |
147 | ||
148 | static inline uint8_t | |
149 | arc4_getbyte(struct arc4_stream *as) | |
150 | { | |
151 | uint8_t si, sj; | |
152 | ||
153 | as->i = (as->i + 1); | |
154 | si = as->s[as->i]; | |
155 | as->j = (as->j + si); | |
156 | sj = as->s[as->j]; | |
157 | as->s[as->i] = sj; | |
158 | as->s[as->j] = si; | |
159 | return (as->s[(si + sj) & 0xff]); | |
160 | } | |
161 | ||
162 | static inline uint32_t | |
163 | arc4_getword(struct arc4_stream *as) | |
164 | { | |
165 | uint32_t val; | |
166 | val = arc4_getbyte(as) << 24; | |
167 | val |= arc4_getbyte(as) << 16; | |
168 | val |= arc4_getbyte(as) << 8; | |
169 | val |= arc4_getbyte(as); | |
170 | return val; | |
171 | } | |
172 | ||
173 | void | |
174 | arc4random_stir(void) | |
175 | { | |
176 | if (!rs_initialized) { | |
177 | arc4_init(&rs); | |
178 | rs_initialized = 1; | |
179 | } | |
180 | arc4_stir(&rs); | |
181 | } | |
182 | ||
183 | void | |
184 | arc4random_addrandom(uint8_t *dat, int datlen) | |
185 | { | |
186 | if (!rs_initialized) | |
187 | arc4random_stir(); | |
188 | arc4_addrandom(&rs, dat, datlen); | |
189 | } | |
190 | ||
191 | uint32_t | |
192 | arc4random(void) | |
193 | { | |
194 | if (!rs_initialized) | |
195 | arc4random_stir(); | |
196 | return arc4_getword(&rs); | |
197 | } | |
198 | ||
199 | #endif | |
200 |