xref: /freebsd/sys/dev/random/unit_test.c (revision 276da39af92f48350aa01091a2b8b3e735217eea)
1 /*-
2  * Copyright (c) 2000-2015 Mark R V Murray
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 /*
30  Build this by going:
31 
32 cc -g -O0 -pthread -DRANDOM_<alg> -DRANDOM_DEBUG -I../.. -lstdthreads -Wall \
33 	unit_test.c \
34 	yarrow.c \
35 	fortuna.c \
36 	hash.c \
37 	../../crypto/rijndael/rijndael-api-fst.c \
38 	../../crypto/rijndael/rijndael-alg-fst.c \
39 	../../crypto/sha2/sha2.c \
40         -lz \
41 	-o unit_test
42 ./unit_test
43 
44 Where <alg> is YARROW or FORTUNA.
45 */
46 
47 #include <sys/types.h>
48 #include <inttypes.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <threads.h>
52 #include <unistd.h>
53 #include <zlib.h>
54 
55 #include "unit_test.h"
56 
57 #ifdef RANDOM_YARROW
58 #include "dev/random/yarrow.h"
59 #endif
60 #ifdef RANDOM_FORTUNA
61 #include "dev/random/fortuna.h"
62 #endif
63 
64 #define	NUM_THREADS	  3
65 #define	DEBUG
66 
67 static volatile int stopseeding = 0;
68 
69 static __inline void
70 check_err(int err, const char *func)
71 {
72 	if (err != Z_OK) {
73 		fprintf(stderr, "Compress error in %s: %d\n", func, err);
74 		exit(0);
75 	}
76 }
77 
78 void *
79 myalloc(void *q, unsigned n, unsigned m)
80 {
81 	q = Z_NULL;
82 	return (calloc(n, m));
83 }
84 
85 void myfree(void *q, void *p)
86 {
87 	q = Z_NULL;
88 	free(p);
89 }
90 
91 size_t
92 block_deflate(uint8_t *uncompr, uint8_t *compr, const size_t len)
93 {
94 	z_stream c_stream;
95 	int err;
96 
97 	if (len == 0)
98 		return (0);
99 
100 	c_stream.zalloc = myalloc;
101 	c_stream.zfree = myfree;
102 	c_stream.opaque = NULL;
103 
104 	err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
105 	check_err(err, "deflateInit");
106 
107 	c_stream.next_in  = uncompr;
108 	c_stream.next_out = compr;
109 	c_stream.avail_in = len;
110 	c_stream.avail_out = len*2u +512u;
111 
112 	while (c_stream.total_in != len && c_stream.total_out < (len*2u + 512u)) {
113 		err = deflate(&c_stream, Z_NO_FLUSH);
114 #ifdef DEBUG
115 		printf("deflate: len = %zd  total_in = %lu  total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
116 #endif
117 		check_err(err, "deflate(..., Z_NO_FLUSH)");
118 	}
119 
120 	for (;;) {
121 		err = deflate(&c_stream, Z_FINISH);
122 #ifdef DEBUG
123 		printf("deflate: len = %zd  total_in = %lu  total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
124 #endif
125 		if (err == Z_STREAM_END) break;
126 		check_err(err, "deflate(..., Z_STREAM_END)");
127 	}
128 
129 	err = deflateEnd(&c_stream);
130 	check_err(err, "deflateEnd");
131 
132 	return ((size_t)c_stream.total_out);
133 }
134 
135 void
136 random_adaptor_unblock(void)
137 {
138 
139 #if 0
140 	if (mtx_trylock(&random_reseed_mtx) == thrd_busy)
141 		printf("Mutex held. Good.\n");
142 	else {
143 		printf("Mutex not held. PANIC!!\n");
144 		thrd_exit(0);
145 	}
146 #endif
147 	printf("random: unblocking device.\n");
148 }
149 
150 static int
151 RunHarvester(void *arg __unused)
152 {
153 	int i, r;
154 	struct harvest_event e;
155 
156 	for (i = 0; ; i++) {
157 		if (stopseeding)
158 			break;
159 		if (i % 1000 == 0)
160 			printf("Harvest: %d\n", i);
161 		r = random()%10;
162 		e.he_somecounter = i;
163 		*((uint64_t *)e.he_entropy) = random();
164 		e.he_size = 8;
165 		e.he_bits = random()%4;
166 		e.he_destination = i;
167 		e.he_source = (i + 3)%7;
168 		e.he_next = NULL;
169 #ifdef RANDOM_YARROW
170 		random_yarrow_process_event(&e);
171 #endif
172 #ifdef RANDOM_FORTUNA
173 		random_fortuna_process_event(&e);
174 #endif
175 		usleep(r);
176 	}
177 
178 	printf("Thread #0 ends\n");
179 
180 	thrd_exit(0);
181 
182 	return (0);
183 }
184 
185 static int
186 WriteCSPRNG(void *threadid)
187 {
188 	uint8_t *buf;
189 	int i;
190 
191 	printf("Thread #1 starts\n");
192 
193 	for (i = 0; ; i++) {
194 		if (stopseeding)
195 			break;
196 		buf = malloc(4096);
197 		if (i % 1000 == 0)
198 			printf("Thread write 1 - %d\n", i);
199 		if (buf != NULL) {
200 			printf("Thread 1 writing.\n");
201 #ifdef RANDOM_YARROW
202 			random_yarrow_write(buf, i);
203 #endif
204 #ifdef RANDOM_FORTUNA
205 			random_fortuna_write(buf, i);
206 #endif
207 			free(buf);
208 		}
209 		usleep(1000000);
210 	}
211 
212 	printf("Thread #1 ends\n");
213 
214 	thrd_exit(0);
215 
216 	return (0);
217 }
218 
219 static int
220 ReadCSPRNG(void *threadid)
221 {
222 	size_t tid, zsize;
223 	uint8_t *buf, *zbuf;
224 	int i;
225 #ifdef DEBUG
226 	int j;
227 #endif
228 
229 	tid = (size_t)threadid;
230 	printf("Thread #%zd starts\n", tid);
231 
232 #ifdef RANDOM_YARROW
233 	while (!random_yarrow_seeded())
234 #endif
235 #ifdef RANDOM_FORTUNA
236 	while (!random_fortuna_seeded())
237 #endif
238 	{
239 #ifdef RANDOM_YARROW
240 		random_yarrow_pre_read();
241 		random_yarrow_post_read();
242 #endif
243 #ifdef RANDOM_FORTUNA
244 		random_fortuna_pre_read();
245 		random_fortuna_post_read();
246 #endif
247 		usleep(100);
248 	}
249 
250 	for (i = 0; i < 100000; i++) {
251 		buf = malloc(i);
252 		zbuf = malloc(2*i + 1024);
253 		if (i % 1000 == 0)
254 			printf("Thread read %zd - %d\n", tid, i);
255 		if (buf != NULL && zbuf != NULL) {
256 #ifdef RANDOM_YARROW
257 			random_yarrow_pre_read();
258 			random_yarrow_read(buf, i);
259 			random_yarrow_post_read();
260 #endif
261 #ifdef RANDOM_FORTUNA
262 			random_fortuna_pre_read();
263 			random_fortuna_read(buf, i);
264 			random_fortuna_post_read();
265 #endif
266 			zsize = block_deflate(buf, zbuf, i);
267 			if (zsize < i)
268 				printf("ERROR!! Compressible RNG output!\n");
269 #ifdef DEBUG
270 			printf("RNG output:\n");
271 			for (j = 0; j < i; j++) {
272 				printf(" %02X", buf[j]);
273 				if (j % 32 == 31 || j == i - 1)
274 					printf("\n");
275 			}
276 			printf("Compressed output:\n");
277 			for (j = 0; j < zsize; j++) {
278 				printf(" %02X", zbuf[j]);
279 				if (j % 32 == 31 || j == zsize - 1)
280 					printf("\n");
281 			}
282 #endif
283 			free(zbuf);
284 			free(buf);
285 		}
286 		usleep(100);
287 	}
288 
289 	printf("Thread #%zd ends\n", tid);
290 
291 	thrd_exit(0);
292 
293 	return (0);
294 }
295 
296 int
297 main(int argc, char *argv[])
298 {
299 	thrd_t threads[NUM_THREADS];
300 	int rc;
301 	long t;
302 
303 #ifdef RANDOM_YARROW
304 	random_yarrow_init_alg();
305 #endif
306 #ifdef RANDOM_FORTUNA
307 	random_fortuna_init_alg();
308 #endif
309 
310 	for (t = 0; t < NUM_THREADS; t++) {
311 		printf("In main: creating thread %ld\n", t);
312 		rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : (t == 1 ? WriteCSPRNG : ReadCSPRNG)), NULL);
313 		if (rc != thrd_success) {
314 			printf("ERROR; return code from thrd_create() is %d\n", rc);
315 			exit(-1);
316 		}
317 	}
318 
319 	for (t = 2; t < NUM_THREADS; t++)
320 		thrd_join(threads[t], &rc);
321 
322 	stopseeding = 1;
323 
324 	thrd_join(threads[1], &rc);
325 	thrd_join(threads[0], &rc);
326 
327 #ifdef RANDOM_YARROW
328 	random_yarrow_deinit_alg();
329 #endif
330 #ifdef RANDOM_FORTUNA
331 	random_fortuna_deinit_alg();
332 #endif
333 
334 	/* Last thing that main() should do */
335 	thrd_exit(0);
336 
337 	return (0);
338 }
339