1 Submitted By: Robert Connolly <robert at linuxfromscratch dot org> (ashes)
3 Initial Package Version: 2.3.6
4 Upstream Status: Not submitted
5 Origin: http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/crypt/arc4random.c
6 Description: This patch adds the arc4random() and arc4randomII() functions
7 to Glibc, and hooks so mktemp(3) can use arc4randomII().
10 http://www.linuxfromscratch.org/hlfs/
11 http://www.linuxfromscratch.org/hints/downloads/files/entropy.txt
13 diff -Naur glibc-2.3.6.orig/manual/arc4random.3 glibc-2.3.6/manual/arc4random.3
14 --- glibc-2.3.6.orig/manual/arc4random.3 1970-01-01 00:00:00.000000000 +0000
15 +++ glibc-2.3.6/manual/arc4random.3 2006-01-01 07:48:48.000000000 +0000
17 +.TH ARC4RANDOM 3 "February 11, 2005"
19 +arc4random - arc4 random number generator
22 +.B #include <stdlib.h>
28 +.B arc4randomII(void);
31 +The \fBarc4random()\fP function generates a pseudo-random number using the
32 +ARC4 cipher key stream generator. ARCFOUR uses 8*8 8 bit S-Boxes, and can
33 +be in about (2**1700) states.
35 +The \fBarc4random()\fP function is seeded automatically from /dev/urandom,
36 +or from sysctl \fBurandom\fP if /dev/urandom is not accessible (chroot), or from
37 +sysctl random.uuid if sysctl \fBurandom\fP is not accessible. \fBgettimeofday(2)\fP
38 +is always included when initializing the state of \fBarc4random()\fP, this makes
39 +it impossible to generate the same random sequence twice. \fBarc4random()\fP
40 +is intended to be safe to use with encryption software to provide entropy.
42 +The \fBarc4randomII()\fP function is identical to \fBarc4random()\fP except
43 +that \fBarc4randomII()\fP is seeded automatically from /dev/erandom, and
44 +sysctl erandom. \fBarc4randomII()\fP is NOT intended for cryptography, but is
45 +ideal for \fBmktemp(3)\fP, and other functions with a short lifespan.
46 +\fBarc4randomII()\fP and erandom do not consume any kernel entropy.
48 +Sysctl urandom, and erandom require a modified kernel. See:
49 +http://www.linuxfromscratch.org/hlfs/
53 +Return a random number between 0 and 100.
57 +Return any random number.
62 +Sample program; this will display a number between 0 and 65536.
69 + random_number = arc4random() % 65536;
70 + printf("%d\n", random_number);
76 +.BR gettimeofday (2),
80 +An algorithm called RC4 was designed by RSA Data Security, Inc. It was
81 +considered a trade secret, but not trademarked. Because it was a trade
82 +secret, it obviously could not be patented. A clone of this was posted
83 +anonymously to USENET and confirmed to be equivalent by several sources
84 +who had access to the original cipher. Because of the trade secret situation,
85 +RSA Data Security, Inc. can do nothing about the release of the
86 +ARC4 algorithm. Since RC4 used to be a trade secret, the cipher is now
87 +referred to as ARC4 (Another RC4).
89 +These functions first appeared in OpenBSD 2.1.
91 diff -Naur glibc-2.3.6.orig/stdlib/Makefile glibc-2.3.6/stdlib/Makefile
92 --- glibc-2.3.6.orig/stdlib/Makefile 2005-02-16 11:23:58.000000000 +0000
93 +++ glibc-2.3.6/stdlib/Makefile 2006-01-01 07:48:48.000000000 +0000
97 atof atoi atol atoll \
99 + abort arc4random arc4randomII \
100 bsearch qsort msort \
101 getenv putenv setenv secure-getenv \
102 exit on_exit atexit cxa_atexit cxa_finalize old_atexit \
103 diff -Naur glibc-2.3.6.orig/stdlib/Versions glibc-2.3.6/stdlib/Versions
104 --- glibc-2.3.6.orig/stdlib/Versions 2004-05-03 21:25:53.000000000 +0000
105 +++ glibc-2.3.6/stdlib/Versions 2006-01-01 07:50:28.000000000 +0000
109 a64l; abort; abs; atexit; atof; atoi; atol; atoll;
110 + arc4random_stir; arc4random_addrandom; arc4random;
111 + arc4random_stirII; arc4random_addrandomII; arc4randomII;
115 diff -Naur glibc-2.3.6.orig/stdlib/arc4random.c glibc-2.3.6/stdlib/arc4random.c
116 --- glibc-2.3.6.orig/stdlib/arc4random.c 1970-01-01 00:00:00.000000000 +0000
117 +++ glibc-2.3.6/stdlib/arc4random.c 2006-01-01 07:48:48.000000000 +0000
120 + * Arc4 random number generator for OpenBSD.
121 + * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
123 + * Modification and redistribution in source and binary forms is
124 + * permitted provided that due credit is given to the author and the
125 + * OpenBSD project by leaving this copyright notice intact.
129 + * This code is derived from section 17.1 of Applied Cryptography,
130 + * second edition, which describes a stream cipher allegedly
131 + * compatible with RSA Labs "RC4" cipher (the actual description of
132 + * which is a trade secret). The same algorithm is used as a stream
133 + * cipher called "arcfour" in Tatu Ylonen's ssh package.
135 + * Here the stream cipher has been modified always to include the time
136 + * when initializing the state. That makes it impossible to
137 + * regenerate the same random sequence twice, so this can't be used
138 + * for encryption, but will generate good random numbers.
140 + * RC4 is a registered trademark of RSA Laboratories.
144 + * Modified by Robert Connolly from OpenBSD lib/libc/crypt/arc4random.c v1.11.
145 + * This is arc4random(3) using urandom.
151 +#include <sys/types.h>
152 +#include <sys/param.h>
153 +#include <sys/time.h>
154 +#include <sys/sysctl.h>
157 +#define inline __inline
158 +#else /* !__GNUC__ */
160 +#endif /* !__GNUC__ */
162 +struct arc4_stream {
168 +static int rs_initialized;
169 +static struct arc4_stream rs;
170 +static pid_t arc4_stir_pid;
172 +static inline u_int8_t arc4_getbyte(struct arc4_stream *);
175 +arc4_init(struct arc4_stream *as)
179 + for (n = 0; n < 256; n++)
186 +arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
192 + for (n = 0; n < 256; n++) {
193 + as->i = (as->i + 1);
195 + as->j = (as->j + si + dat[n % datlen]);
196 + as->s[as->i] = as->s[as->j];
203 +arc4_stir(struct arc4_stream *as)
208 + u_int rnd[(128 - sizeof(struct timeval)) / sizeof(u_int)];
211 + gettimeofday(&rdat.tv, NULL);
213 + /* /dev/urandom is a multithread interface, sysctl is not. */
214 + /* Try to use /dev/urandom before sysctl. */
215 + fd = open("/dev/urandom", O_RDONLY);
217 + read(fd, rdat.rnd, sizeof(rdat.rnd));
221 +#if defined(SYSCTL_URANDOM)
223 + /* /dev/urandom failed? Maybe we're in a chroot. */
224 + int mib[]={CTL_KERN, KERN_RANDOM, RANDOM_URANDOM};
228 + for (i = 0; i < sizeof(rdat.rnd) / sizeof(u_int); i ++) {
229 + len = sizeof(u_int);
230 + if (sysctl(mib, 3, &rdat.rnd[i], &len, NULL, 0) == -1)
233 + if (i < sizeof(rdat.rnd) / 4) {
234 + /* Sysctl urandom failed? Maybe we're running a vanilla kernel. */
235 + mib[2] = RANDOM_UUID;
236 + for (i = 0; i < sizeof(rdat.rnd) / sizeof(u_int); i ++) {
237 + len = sizeof(u_int);
238 + if (sysctl(mib, 3, &rdat.rnd[i], &len, NULL, 0) == -1)
245 + arc4_stir_pid = getpid();
247 + * Time to give up. If no entropy could be found then we will just
248 + * use gettimeofday.
250 + arc4_addrandom(as, (void *)&rdat, sizeof(rdat));
253 + * Discard early keystream, as per recommendations in:
254 + * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
255 + * We discard 256 words. A long word is 4 bytes.
257 + for (n = 0; n < 256 * 4; n ++)
261 +static inline u_int8_t
262 +arc4_getbyte(struct arc4_stream *as)
266 + as->i = (as->i + 1);
268 + as->j = (as->j + si);
272 + return (as->s[(si + sj) & 0xff]);
275 +static inline u_int32_t
276 +arc4_getword(struct arc4_stream *as)
279 + val = arc4_getbyte(as) << 24;
280 + val |= arc4_getbyte(as) << 16;
281 + val |= arc4_getbyte(as) << 8;
282 + val |= arc4_getbyte(as);
287 +arc4random_stir(void)
289 + if (!rs_initialized) {
291 + rs_initialized = 1;
297 +arc4random_addrandom(u_char *dat, int datlen)
299 + if (!rs_initialized)
301 + arc4_addrandom(&rs, dat, datlen);
307 + if (!rs_initialized || arc4_stir_pid != getpid())
309 + return arc4_getword(&rs);
313 +/*-------- Test code --------*/
319 + random_number = arc4random() % 65536;
320 + printf("A random number between 0 and 65536 is %d\n", random_number);
324 diff -Naur glibc-2.3.6.orig/stdlib/arc4randomII.c glibc-2.3.6/stdlib/arc4randomII.c
325 --- glibc-2.3.6.orig/stdlib/arc4randomII.c 1970-01-01 00:00:00.000000000 +0000
326 +++ glibc-2.3.6/stdlib/arc4randomII.c 2006-01-01 07:48:48.000000000 +0000
329 + * Arc4 random number generator for OpenBSD.
330 + * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
332 + * Modification and redistribution in source and binary forms is
333 + * permitted provided that due credit is given to the author and the
334 + * OpenBSD project by leaving this copyright notice intact.
338 + * This code is derived from section 17.1 of Applied Cryptography,
339 + * second edition, which describes a stream cipher allegedly
340 + * compatible with RSA Labs "RC4" cipher (the actual description of
341 + * which is a trade secret). The same algorithm is used as a stream
342 + * cipher called "arcfour" in Tatu Ylonen's ssh package.
344 + * Here the stream cipher has been modified always to include the time
345 + * when initializing the state. That makes it impossible to
346 + * regenerate the same random sequence twice, so this can't be used
347 + * for encryption, but will generate good random numbers.
349 + * RC4 is a registered trademark of RSA Laboratories.
353 + * Modified by Robert Connolly from OpenBSD lib/libc/crypt/arc4random.c v1.11.
354 + * This is arc4randomII(3) using erandom.
360 +#include <sys/types.h>
361 +#include <sys/param.h>
362 +#include <sys/time.h>
363 +#include <sys/sysctl.h>
366 +#define inline __inline
367 +#else /* !__GNUC__ */
369 +#endif /* !__GNUC__ */
371 +struct arc4_streamII {
377 +static int rs_initializedII;
378 +static struct arc4_streamII rs;
379 +static pid_t arc4_stir_pidII;
381 +static inline u_int8_t arc4_getbyteII(struct arc4_streamII *);
384 +arc4_initII(struct arc4_streamII *as)
388 + for (n = 0; n < 256; n++)
395 +arc4_addrandomII(struct arc4_streamII *as, u_char *dat, int datlen)
401 + for (n = 0; n < 256; n++) {
402 + as->i = (as->i + 1);
404 + as->j = (as->j + si + dat[n % datlen]);
405 + as->s[as->i] = as->s[as->j];
412 +arc4_stirII(struct arc4_streamII *as)
417 + u_int rnd[(128 - sizeof(struct timeval)) / sizeof(u_int)];
420 + gettimeofday(&rdat.tv, NULL);
422 + /* /dev/urandom is a multithread interface, sysctl is not. */
423 + /* Try to use /dev/urandom before sysctl. */
424 + fd = open("/dev/erandom", O_RDONLY);
426 + read(fd, rdat.rnd, sizeof(rdat.rnd));
430 +#if defined(SYSCTL_ERANDOM)
432 + /* /dev/urandom failed? Maybe we're in a chroot. */
433 + int mib[]={CTL_KERN, KERN_RANDOM, RANDOM_ERANDOM};
437 + for (i = 0; i < sizeof(rdat.rnd) / sizeof(u_int); i++) {
438 + len = sizeof(u_int);
439 + if (sysctl(mib, 3, &rdat.rnd[i], &len, NULL, 0) == -1)
445 + arc4_stir_pidII = getpid();
447 + * Time to give up. If no entropy could be found then we will just
448 + * use gettimeofday.
450 + arc4_addrandomII(as, (void *)&rdat, sizeof(rdat));
453 + * Discard early keystream, as per recommendations in:
454 + * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
455 + * We discard 256 words. A long word is 4 bytes.
457 + for (n = 0; n < 256 * 4; n ++)
458 + arc4_getbyteII(as);
461 +static inline u_int8_t
462 +arc4_getbyteII(struct arc4_streamII *as)
466 + as->i = (as->i + 1);
468 + as->j = (as->j + si);
472 + return (as->s[(si + sj) & 0xff]);
475 +static inline u_int32_t
476 +arc4_getwordII(struct arc4_streamII *as)
479 + val = arc4_getbyteII(as) << 24;
480 + val |= arc4_getbyteII(as) << 16;
481 + val |= arc4_getbyteII(as) << 8;
482 + val |= arc4_getbyteII(as);
487 +arc4random_stirII(void)
489 + if (!rs_initializedII) {
491 + rs_initializedII = 1;
497 +arc4random_addrandomII(u_char *dat, int datlen)
499 + if (!rs_initializedII)
500 + arc4random_stirII();
501 + arc4_addrandomII(&rs, dat, datlen);
507 + if (!rs_initializedII || arc4_stir_pidII != getpid())
508 + arc4random_stirII();
509 + return arc4_getwordII(&rs);
513 +/*-------- Test code --------*/
519 + random_number = arc4randomII() % 65536;
520 + printf("A random number between 0 and 65536 is %d\n", random_number);
524 diff -Naur glibc-2.3.6.orig/stdlib/stdlib.h glibc-2.3.6/stdlib/stdlib.h
525 --- glibc-2.3.6.orig/stdlib/stdlib.h 2005-07-18 01:15:30.000000000 +0000
526 +++ glibc-2.3.6/stdlib/stdlib.h 2006-01-01 07:48:48.000000000 +0000
528 extern int lcong48_r (unsigned short int __param[7],
529 struct drand48_data *__buffer)
530 __THROW __nonnull ((1, 2));
532 +#define LIBC_HAS_ARC4RANDOM
533 +u_int32_t arc4random(void);
534 +void arc4random_stir(void);
535 +void arc4random_addrandom(unsigned char *, int);
536 +u_int32_t arc4randomII(void);
537 +void arc4random_stirII(void);
538 +void arc4random_addrandomII(unsigned char *, int);
540 # endif /* Use misc. */
541 #endif /* Use SVID or X/Open. */