]> git.pld-linux.org Git - packages/mksh.git/blob - arc4random.c
- use %lua_{remove|add}_etc_shells macros
[packages/mksh.git] / arc4random.c
1 /* $MirOS: contrib/code/Snippets/arc4random.c,v 1.2 2007/09/09 22:14:04 tg Exp $ */
2
3 /*-
4  * Arc4 random number generator for OpenBSD.
5  * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
6  *
7  * Modification and redistribution in source and binary forms is
8  * permitted provided that due credit is given to the author and the
9  * OpenBSD project by leaving this copyright notice intact.
10  */
11
12 /*-
13  * This code is derived from section 17.1 of Applied Cryptography,
14  * second edition, which describes a stream cipher allegedly
15  * compatible with RSA Labs "RC4" cipher (the actual description of
16  * which is a trade secret).  The same algorithm is used as a stream
17  * cipher called "arcfour" in Tatu Ylonen's ssh package.
18  *
19  * Here the stream cipher has been modified always to include the time
20  * when initializing the state.  That makes it impossible to
21  * regenerate the same random sequence twice, so this can't be used
22  * for encryption, but will generate good random numbers.
23  *
24  * RC4 is a registered trademark of RSA Laboratories.
25  */
26
27 /*-
28  * Modified by Robert Connolly from OpenBSD lib/libc/crypt/arc4random.c v1.11.
29  * This is arc4random(3) using urandom.
30  */
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #if HAVE_SYS_SYSCTL_H
36 #include <sys/sysctl.h>
37 #endif
38 #include <fcntl.h>
39 #if HAVE_STDINT_H
40 #include <stdint.h>
41 #endif
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45
46 struct arc4_stream {
47         uint8_t i;
48         uint8_t j;
49         uint8_t s[256];
50 };
51
52 static int rs_initialized;
53 static struct arc4_stream rs;
54 static pid_t arc4_stir_pid;
55
56 static uint8_t arc4_getbyte(struct arc4_stream *);
57
58 u_int32_t arc4random(void);
59 void arc4random_addrandom(u_char *, int);
60 void arc4random_stir(void);
61
62 static void
63 arc4_init(struct arc4_stream *as)
64 {
65         int     n;
66
67         for (n = 0; n < 256; n++)
68                 as->s[n] = n;
69         as->i = 0;
70         as->j = 0;
71 }
72
73 static void
74 arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
75 {
76         int     n;
77         uint8_t si;
78
79         as->i--;
80         for (n = 0; n < 256; n++) {
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
90 static void
91 arc4_stir(struct arc4_stream *as)
92 {
93         int     n, fd;
94         struct {
95                 struct timeval tv;
96                 u_int rnd[(128 - sizeof(struct timeval)) / sizeof(u_int)];
97         }       rdat;
98
99         gettimeofday(&rdat.tv, NULL);
100
101         /* /dev/urandom is a multithread interface, sysctl is not. */
102         /* Try to use /dev/urandom before sysctl. */
103         fd = open("/dev/urandom", O_RDONLY);
104         if (fd != -1) {
105                 read(fd, rdat.rnd, sizeof(rdat.rnd));
106                 close(fd);
107         } else {
108                 /* /dev/urandom failed? Maybe we're in a chroot. */
109 //#if defined(CTL_KERN) && defined(KERN_RANDOM) && defined(RANDOM_UUID)
110 #ifdef _LINUX_SYSCTL_H
111                 /* XXX this is for Linux, which uses enums */
112
113                 int mib[3];
114                 size_t i, len;
115
116                 mib[0] = CTL_KERN;
117                 mib[1] = KERN_RANDOM;
118                 mib[2] = RANDOM_UUID;
119
120                 for (i = 0; i < sizeof(rdat.rnd) / sizeof(u_int); i ++) {
121                         len = sizeof(u_int);
122                         if (sysctl(mib, 3, &rdat.rnd[i], &len, NULL, 0) == -1) {
123                                 fprintf(stderr, "warning: no entropy source\n");
124                                 break;
125                         }
126                 }
127 #else
128                 /* XXX kFreeBSD doesn't seem to have KERN_ARND or so */
129                 ;
130 #endif
131         }
132
133         arc4_stir_pid = getpid();
134         /*
135          * Time to give up. If no entropy could be found then we will just
136          * use gettimeofday.
137          */
138         arc4_addrandom(as, (void *)&rdat, sizeof(rdat));
139
140         /*
141          * Discard early keystream, as per recommendations in:
142          * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
143          * We discard 256 words. A long word is 4 bytes.
144          */
145         for (n = 0; n < 256 * 4; n ++)
146                 arc4_getbyte(as);
147 }
148
149 static uint8_t
150 arc4_getbyte(struct arc4_stream *as)
151 {
152         uint8_t si, sj;
153
154         as->i = (as->i + 1);
155         si = as->s[as->i];
156         as->j = (as->j + si);
157         sj = as->s[as->j];
158         as->s[as->i] = sj;
159         as->s[as->j] = si;
160         return (as->s[(si + sj) & 0xff]);
161 }
162
163 static uint32_t
164 arc4_getword(struct arc4_stream *as)
165 {
166         uint32_t val;
167         val = arc4_getbyte(as) << 24;
168         val |= arc4_getbyte(as) << 16;
169         val |= arc4_getbyte(as) << 8;
170         val |= arc4_getbyte(as);
171         return val;
172 }
173
174 void
175 arc4random_stir(void)
176 {
177         if (!rs_initialized) {
178                 arc4_init(&rs);
179                 rs_initialized = 1;
180         }
181         arc4_stir(&rs);
182 }
183
184 void
185 arc4random_addrandom(u_char *dat, int datlen)
186 {
187         if (!rs_initialized)
188                 arc4random_stir();
189         arc4_addrandom(&rs, dat, datlen);
190 }
191
192 u_int32_t
193 arc4random(void)
194 {
195         if (!rs_initialized || arc4_stir_pid != getpid())
196                 arc4random_stir();
197         return arc4_getword(&rs);
198 }
This page took 0.059155 seconds and 3 git commands to generate.