5 * THE BEER-WARE LICENSE
7 * <dan@FreeBSD.ORG> wrote this file. As long as you retain this notice you
8 * can do whatever you want with this stuff. If we meet some day, and you
9 * think this stuff is worth it, you can buy me a beer in return.
13 #if !defined(SOLARIS2) && !defined(__osf__)
14 # include <sys/cdefs.h>
17 #include <sys/types.h>
18 #include <sys/param.h>
20 # include <sys/kernel.h>
23 # include <sys/random.h>
26 # include <sys/libkern.h>
30 # include <sys/mutex.h>
34 #if defined(SOLARIS2) && (SOLARIS2 < 9)
35 # include <netinet/in_systm.h>
37 #include <sys/socket.h>
40 # include <net/route.h>
42 #include <netinet/in.h>
43 #include <netinet/ip.h>
44 #include "netinet/ip_compat.h"
47 #if !defined(__GNUC__)
51 #define ARC4_RESEED_BYTES 65536
52 #define ARC4_RESEED_SECONDS 300
53 #define ARC4_KEYBYTES (256 / 8)
55 static u_int8_t arc4_i
, arc4_j
;
56 static int arc4_numruns
= 0;
57 static u_int8_t arc4_sbox
[256];
58 static time_t arc4_t_reseed
;
59 static ipfmutex_t arc4_mtx
;
60 static MD5_CTX md5ctx
;
62 static u_int8_t
arc4_randbyte(void);
63 static int ipf_read_random(void *dest
, int length
);
66 arc4_swap(u_int8_t
*a
, u_int8_t
*b
)
79 arc4_randomstir (void)
83 struct timeval tv_now
;
86 * XXX read_random() returns unsafe numbers if the entropy
87 * device is not loaded -- MarkM.
89 r
= ipf_read_random(key
, ARC4_KEYBYTES
);
91 MUTEX_ENTER(&arc4_mtx
);
92 /* If r == 0 || -1, just use what was on the stack. */
94 for (n
= r
; n
< sizeof(key
); n
++)
98 for (n
= 0; n
< 256; n
++) {
99 arc4_j
= (arc4_j
+ arc4_sbox
[n
] + key
[n
]) % 256;
100 arc4_swap(&arc4_sbox
[n
], &arc4_sbox
[arc4_j
]);
103 /* Reset for next reseed cycle. */
104 arc4_t_reseed
= tv_now
.tv_sec
+ ARC4_RESEED_SECONDS
;
108 * Throw away the first N words of output, as suggested in the
109 * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
110 * by Fluher, Mantin, and Shamir. (N = 256 in our case.)
112 for (n
= 0; n
< 256*4; n
++)
114 MUTEX_EXIT(&arc4_mtx
);
118 * Initialize our S-box to its beginning defaults.
127 MUTEX_INIT(&arc4_mtx
, "arc4_mtx");
129 for (n
= 0; n
< 256; n
++)
130 arc4_sbox
[n
] = (u_int8_t
) n
;
137 * Generate a random byte.
144 arc4_i
= (arc4_i
+ 1) % 256;
145 arc4_j
= (arc4_j
+ arc4_sbox
[arc4_i
]) % 256;
147 arc4_swap(&arc4_sbox
[arc4_i
], &arc4_sbox
[arc4_j
]);
149 arc4_t
= (arc4_sbox
[arc4_i
] + arc4_sbox
[arc4_j
]) % 256;
150 return arc4_sbox
[arc4_t
];
157 arc4rand(void *ptr
, u_int len
, int reseed
)
164 (arc4_numruns
> ARC4_RESEED_BYTES
) ||
165 (tv
.tv_sec
> arc4_t_reseed
))
168 MUTEX_ENTER(&arc4_mtx
);
172 *p
++ = arc4_randbyte();
173 MUTEX_EXIT(&arc4_mtx
);
181 arc4rand(&ret
, sizeof ret
, 0);
186 static u_char pot
[ARC4_RESEED_BYTES
];
187 static u_char
*pothead
= pot
, *pottail
= pot
;
188 static int inpot
= 0;
191 * This is not very strong, and this is understood, but the aim isn't to
192 * be cryptographically strong - it is just to make up something that is
196 ipf_rand_push(void *src
, int length
)
198 static int arc4_inited
= 0;
202 if (arc4_inited
== 0) {
208 MD5Update(&md5ctx
, src
, length
);
215 #if defined(_SYS_MD5_H) && defined(SOLARIS2)
216 # define buf buf_un.buf8
218 MUTEX_ENTER(&arc4_mtx
);
219 while ((mylen
> 64) && (sizeof(pot
) - inpot
> sizeof(md5ctx
.buf
))) {
220 MD5Update(&md5ctx
, nsrc
, 64);
223 if (pottail
+ sizeof(md5ctx
.buf
) > pot
+ sizeof(pot
)) {
226 numbytes
= pot
+ sizeof(pot
) - pottail
;
227 bcopy(md5ctx
.buf
, pottail
, numbytes
);
228 left
= sizeof(md5ctx
.buf
) - numbytes
;
230 bcopy(md5ctx
.buf
+ sizeof(md5ctx
.buf
) - left
,
234 bcopy(md5ctx
.buf
, pottail
, sizeof(md5ctx
.buf
));
235 pottail
+= sizeof(md5ctx
.buf
);
239 MUTEX_EXIT(&arc4_mtx
);
240 #if defined(_SYS_MD5_H) && defined(SOLARIS2)
247 ipf_read_random(void *dest
, int length
)
252 MUTEX_ENTER(&arc4_mtx
);
253 if (pothead
+ length
> pot
+ sizeof(pot
)) {
257 numbytes
= pot
+ sizeof(pot
) - pothead
;
258 bcopy(pothead
, dest
, numbytes
);
261 bcopy(pothead
, dest
+ length
- left
, left
);
264 bcopy(pothead
, dest
, length
);
269 pothead
= pottail
= pot
;
270 MUTEX_EXIT(&arc4_mtx
);
275 #endif /* NEED_LOCAL_RAND */