1 /*-
2 * Copyright (c) 2010, 2011, 2012, 2014
3 * Thorsten Glaser <tg@mirbsd.org>
4 *
5 * Provided that these terms and disclaimer and all copyright notices
6 * are retained or reproduced in an accompanying document, permission
7 * is granted to deal in this work without restriction, including un-
8 * limited rights to use, publicly perform, distribute, sell, modify,
9 * merge, give away, or sublicence.
10 *
11 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
12 * the utmost extent permitted by applicable law, neither express nor
13 * implied; without malicious intent or gross negligence. In no event
14 * may a licensor, author or contributor be held liable for indirect,
15 * direct, other damage, loss, or other issues arising in any way out
16 * of dealing in the work, even if advised of the possibility of such
17 * damage or existence of a defect, except proven that it results out
18 * of said person's immediate fault when using the work as intended.
19 *-
20 * The idea of an arc4random(3) stems from David Mazieres for OpenBSD
21 * but this has been reimplemented, improved, corrected, modularised.
22 * The idea of pushing entropy back to the kernel on stir and after a
23 * fork or before an exit is MirBSD specific.
24 */
25
26 #include <sys/param.h>
27 #include <sys/sysctl.h>
28 #include <sys/time.h>
29 #include <syskern/libckern.h>
30 #include <syskern/mirhash.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include "arc4random.h"
35 #include "thread_private.h"
36
37 __RCSID("$MirOS: src/lib/libc/crypt/arc4random_base.c,v 1.15 2014/04/09 23:10:51 tg Exp $");
38
39 /* zero-initialises */
40 struct arc4random_status a4state;
41
42 void
arc4random_atexit(void)43 arc4random_atexit(void)
44 {
45 arc4random_ctl(1);
46 }
47
48 u_int32_t
arc4random(void)49 arc4random(void)
50 {
51 uint32_t v;
52 pid_t mypid = 0;
53
54 _ARC4_LOCK();
55
56 /* reinitialise after fork, (count) bytes or if not initialised */
57 a4state.a4s_count -= 4;
58 if (a4state.a4s_count <= 0 || !a4state.a4s_initialised ||
59 (a4state.a4s_stir_pid != (mypid = getpid())))
60 arc4random_stir_locked(mypid);
61
62 /* randomly skip a byte or two */
63 /*XXX this should be constant-time */
64 if (arcfour_byte(&a4state.cipher) & 1)
65 (void)arcfour_byte(&a4state.cipher);
66
67 v = ((uint32_t)arcfour_byte(&a4state.cipher) << 24) |
68 ((uint32_t)arcfour_byte(&a4state.cipher) << 16) |
69 ((uint32_t)arcfour_byte(&a4state.cipher) << 8) |
70 ((uint32_t)arcfour_byte(&a4state.cipher));
71
72 _ARC4_UNLOCK();
73 return (v);
74 }
75
76 void
arc4random_stir_locked(pid_t mypid)77 arc4random_stir_locked(pid_t mypid)
78 {
79 size_t n;
80 unsigned int carry;
81 int mib[2];
82 union {
83 uint8_t charbuf[256];
84 uint32_t intbuf[64];
85 struct {
86 struct timespec rtime;
87 #if 0
88 struct timespec vtime;
89 struct timespec ptime;
90 #endif
91 struct timespec ntime;
92 pid_t thepid;
93 } tmpbuf;
94 } sbuf;
95
96 if (!a4state.a4s_initialised) {
97 arcfour_init(&a4state.cipher);
98 a4state.a4s_poolptr = 0;
99 }
100 carry = arcfour_byte(&a4state.cipher);
101 /* throw stuff into the roundhash pool */
102 arc4random_roundhash(a4state.pool, &a4state.a4s_poolptr,
103 &a4state.otherinfo, sizeof(a4state.otherinfo));
104 clock_gettime(CLOCK_REALTIME, &sbuf.tmpbuf.rtime);
105 #if 0
106 clock_gettime(CLOCK_VIRTUAL, &sbuf.tmpbuf.vtime);
107 clock_gettime(CLOCK_PROF, &sbuf.tmpbuf.ptime);
108 #endif
109 clock_gettime(CLOCK_MONOTONIC, &sbuf.tmpbuf.ntime);
110 sbuf.tmpbuf.thepid = mypid = mypid ? mypid : getpid();
111 arc4random_roundhash(a4state.pool, &a4state.a4s_poolptr,
112 &sbuf.tmpbuf, sizeof(sbuf.tmpbuf));
113
114 /* fill first 128 bytes with roundhash pool */
115 n = 1 + (carry & 1);
116 carry >>= 1;
117 while (n--)
118 (void)arcfour_byte(&a4state.cipher);
119 for (n = 0; n < 32; ++n) {
120 register uint32_t h;
121
122 h = a4state.pool[n];
123 /* mask and mix */
124 BAFHUpdateOctet_reg(h, arcfour_byte(&a4state.cipher));
125 BAFHFinish_reg(h);
126 sbuf.intbuf[n] = h;
127 }
128
129 /* fill second 128 bytes with local random stuff */
130 n = 1 + (carry & 1);
131 carry >>= 1;
132 while (n--)
133 (void)arcfour_byte(&a4state.cipher);
134 for (n = 128; n < 256; ++n)
135 sbuf.charbuf[n] = arcfour_byte(&a4state.cipher);
136 n = carry & 3;
137 carry &= 0x3C;
138 while (n--)
139 (void)arcfour_byte(&a4state.cipher);
140
141 /* exchange full 256 bytes with kernel */
142 mib[0] = CTL_KERN;
143 mib[1] = KERN_ARND;
144 n = sizeof(sbuf);
145 sysctl(mib, 2, sbuf.charbuf, &n, sbuf.charbuf, sizeof(sbuf));
146 /* if (n != sizeof(sbuf)) something went wrong inside the kernel */
147
148 /* mix first 128 bytes with/into roundhash pool */
149 for (n = 0; n < 32; ++n) {
150 register uint32_t ha, hr;
151
152 ha = (a4state.pool[n] & 0xFFFF0000) |
153 (sbuf.intbuf[n] & 0x0000FFFF);
154 hr = (a4state.pool[n] & 0x0000FFFF) |
155 (sbuf.intbuf[n] & 0xFFFF0000);
156 /* mix then mask for arc4random */
157 BAFHFinish_reg(ha);
158 BAFHUpdateOctet_reg(ha, arcfour_byte(&a4state.cipher));
159 sbuf.intbuf[n] = ha;
160 /* mix then mask for roundhash */
161 BAFHFinish_reg(hr);
162 BAFHUpdateOctet_reg(hr, arcfour_byte(&a4state.cipher));
163 a4state.pool[n] = hr;
164 }
165 /* mix full 256 bytes into arc4random pool */
166 arcfour_ksa(&a4state.cipher, sbuf.charbuf, 256);
167
168 /* trash stack */
169 bzero(sbuf.charbuf, sizeof(sbuf));
170
171 /* discard early keystream */
172 carry += 256 * 12 + (arcfour_byte(&a4state.cipher) & 0x1F);
173 while (carry--)
174 (void)arcfour_byte(&a4state.cipher);
175
176 a4state.a4s_poolptr = 0;
177 a4state.a4s_initialised = 1;
178 a4state.a4s_stir_pid = mypid;
179 a4state.a4s_count = 1600000;
180 }
181
182 /*
183 * This is a deliberately undocumented internal API.
184 * - whence & 7 = mode
185 * + 0 = shuffle user-space only
186 * + 1 = move stuff to kernel (e.g. for reboot)
187 * + 2 = schedule stirring upon next access
188 * - rest MBZ
189 */
190 void
arc4random_ctl(unsigned int whence)191 arc4random_ctl(unsigned int whence)
192 {
193 size_t n;
194 uint8_t *buf;
195 struct {
196 struct timespec tp;
197 const void *dp, *sp;
198 unsigned int wi;
199 struct arcfour_otherinfo oi;
200 } pbuf;
201 int mib[2];
202
203 clock_gettime(CLOCK_MONOTONIC, &pbuf.tp);
204 pbuf.sp = &pbuf;
205 pbuf.dp = &whence;
206 pbuf.wi = whence;
207 _ARC4_LOCK();
208 memcpy(&pbuf.oi, &a4state.otherinfo, sizeof(struct arcfour_otherinfo));
209 if (!a4state.a4s_initialised)
210 arc4random_stir_locked(0);
211 arc4random_roundhash(a4state.pool, &a4state.a4s_poolptr,
212 &pbuf, sizeof(pbuf));
213
214 switch (whence /* & 7 */) {
215 default:
216 break;
217 case 2:
218 a4state.a4s_count = -1;
219 break;
220 case 1:
221 /* first put everything we have into the pool */
222 arc4random_roundhash(a4state.pool, &a4state.a4s_poolptr,
223 &a4state.cipher, sizeof(a4state.cipher));
224 /* then write the pool into the kernel and overwrite it */
225 mib[0] = CTL_KERN;
226 mib[1] = KERN_ARND;
227 n = sizeof(a4state.pool);
228 sysctl(mib, 2, a4state.pool, &n, a4state.pool,
229 sizeof(a4state.pool));
230 /* then blind a bit for continued use, just in case */
231 a4state.a4s_count = n * 24 + 1024;
232 /* FALLTHROUGH */
233 case 0:
234 n = arcfour_byte(&a4state.cipher);
235 buf = (void *)a4state.pool;
236 arcfour_ksa(&a4state.cipher, buf, sizeof(a4state.pool));
237 while (n--)
238 (void)arcfour_byte(&a4state.cipher);
239 n = sizeof(a4state.pool);
240 while (n--)
241 *buf++ = arcfour_byte(&a4state.cipher);
242 a4state.a4s_poolptr = 0;
243 break;
244 }
245 _ARC4_UNLOCK();
246 }
247