]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/random/unit_test.c
Add ELF Tool Chain's ar(1) and elfdump(1) to contrib
[FreeBSD/FreeBSD.git] / sys / dev / random / unit_test.c
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 "randomdev.h"
56 #include "unit_test.h"
57
58 #define NUM_THREADS       3
59 #define DEBUG
60
61 static volatile int stopseeding = 0;
62
63 static __inline void
64 check_err(int err, const char *func)
65 {
66         if (err != Z_OK) {
67                 fprintf(stderr, "Compress error in %s: %d\n", func, err);
68                 exit(0);
69         }
70 }
71
72 void *
73 myalloc(void *q, unsigned n, unsigned m)
74 {
75         q = Z_NULL;
76         return (calloc(n, m));
77 }
78
79 void myfree(void *q, void *p)
80 {
81         q = Z_NULL;
82         free(p);
83 }
84
85 size_t
86 block_deflate(uint8_t *uncompr, uint8_t *compr, const size_t len)
87 {
88         z_stream c_stream;
89         int err;
90
91         if (len == 0)
92                 return (0);
93
94         c_stream.zalloc = myalloc;
95         c_stream.zfree = myfree;
96         c_stream.opaque = NULL;
97
98         err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
99         check_err(err, "deflateInit");
100
101         c_stream.next_in  = uncompr;
102         c_stream.next_out = compr;
103         c_stream.avail_in = len;
104         c_stream.avail_out = len*2u +512u;
105
106         while (c_stream.total_in != len && c_stream.total_out < (len*2u + 512u)) {
107                 err = deflate(&c_stream, Z_NO_FLUSH);
108 #ifdef DEBUG
109                 printf("deflate progress: len = %zd  total_in = %lu  total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
110 #endif
111                 check_err(err, "deflate(..., Z_NO_FLUSH)");
112         }
113
114         for (;;) {
115                 err = deflate(&c_stream, Z_FINISH);
116 #ifdef DEBUG
117                 printf("deflate    final: len = %zd  total_in = %lu  total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
118 #endif
119                 if (err == Z_STREAM_END) break;
120                 check_err(err, "deflate(..., Z_STREAM_END)");
121         }
122
123         err = deflateEnd(&c_stream);
124         check_err(err, "deflateEnd");
125
126         return ((size_t)c_stream.total_out);
127 }
128
129 void
130 randomdev_unblock(void)
131 {
132
133 #if 0
134         if (mtx_trylock(&random_reseed_mtx) == thrd_busy)
135                 printf("Mutex held. Good.\n");
136         else {
137                 printf("Mutex not held. PANIC!!\n");
138                 thrd_exit(0);
139         }
140 #endif
141         printf("random: unblocking device.\n");
142 }
143
144 static int
145 RunHarvester(void *arg __unused)
146 {
147         int i, r;
148         struct harvest_event e;
149
150         for (i = 0; ; i++) {
151                 if (stopseeding)
152                         break;
153                 if (i % 1000 == 0)
154                         printf("Harvest: %d\n", i);
155                 r = random()%10;
156                 e.he_somecounter = i;
157                 *((uint64_t *)e.he_entropy) = random();
158                 e.he_size = 8;
159                 e.he_bits = random()%4;
160                 e.he_destination = i;
161                 e.he_source = (i + 3)%7;
162                 e.he_next = NULL;
163                 random_alg_context.ra_event_processor(&e);
164                 usleep(r);
165         }
166
167         printf("Thread #0 ends\n");
168
169         thrd_exit(0);
170
171         return (0);
172 }
173
174 static int
175 WriteCSPRNG(void *threadid)
176 {
177         uint8_t *buf;
178         int i;
179
180         printf("Thread #1 starts\n");
181
182         for (i = 0; ; i++) {
183                 if (stopseeding)
184                         break;
185                 buf = malloc(4096);
186                 if (i % 1000 == 0)
187                         printf("Thread write 1 - %d\n", i);
188                 if (buf != NULL) {
189                         printf("Thread 1 writing.\n");
190                         random_alg_context.ra_write(buf, i);
191                         free(buf);
192                 }
193                 usleep(1000000);
194         }
195
196         printf("Thread #1 ends\n");
197
198         thrd_exit(0);
199
200         return (0);
201 }
202
203 static int
204 ReadCSPRNG(void *threadid)
205 {
206         size_t tid, zsize;
207         u_int buffersize;
208         uint8_t *buf, *zbuf;
209         int i;
210 #ifdef DEBUG
211         int j;
212 #endif
213
214         tid = (size_t)threadid;
215         printf("Thread #%zd starts\n", tid);
216
217         while (!random_alg_context.ra_seeded())
218         {
219                 random_alg_context.ra_pre_read();
220                 usleep(100);
221         }
222
223         for (i = 0; i < 100000; i++) {
224                 buffersize = i + RANDOM_BLOCKSIZE;
225                 buffersize -= buffersize%RANDOM_BLOCKSIZE;
226                 buf = malloc(buffersize);
227                 zbuf = malloc(2*i + 1024);
228                 if (i % 1000 == 0)
229                         printf("Thread read %zd - %d\n", tid, i);
230                 if (buf != NULL && zbuf != NULL) {
231                         random_alg_context.ra_pre_read();
232                         random_alg_context.ra_read(buf, buffersize);
233                         zsize = block_deflate(buf, zbuf, i);
234                         if (zsize < i)
235                                 printf("ERROR!! Compressible RNG output!\n");
236 #ifdef DEBUG
237                         printf("RNG output:\n");
238                         for (j = 0; j < i; j++) {
239                                 printf(" %02X", buf[j]);
240                                 if (j % 32 == 31 || j == i - 1)
241                                         printf("\n");
242                         }
243                         printf("Compressed output:\n");
244                         for (j = 0; j < zsize; j++) {
245                                 printf(" %02X", zbuf[j]);
246                                 if (j % 32 == 31 || j == zsize - 1)
247                                         printf("\n");
248                         }
249 #endif
250                         free(zbuf);
251                         free(buf);
252                 }
253                 usleep(100);
254         }
255
256         printf("Thread #%zd ends\n", tid);
257
258         thrd_exit(0);
259
260         return (0);
261 }
262
263 int
264 main(int argc, char *argv[])
265 {
266         thrd_t threads[NUM_THREADS];
267         int rc;
268         long t;
269
270         random_alg_context.ra_init_alg(NULL);
271
272         for (t = 0; t < NUM_THREADS; t++) {
273                 printf("In main: creating thread %ld\n", t);
274                 rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : (t == 1 ? WriteCSPRNG : ReadCSPRNG)), NULL);
275                 if (rc != thrd_success) {
276                         printf("ERROR; return code from thrd_create() is %d\n", rc);
277                         exit(-1);
278                 }
279         }
280
281         for (t = 2; t < NUM_THREADS; t++)
282                 thrd_join(threads[t], &rc);
283
284         stopseeding = 1;
285
286         thrd_join(threads[1], &rc);
287         thrd_join(threads[0], &rc);
288
289         random_alg_context.ra_deinit_alg(NULL);
290
291         /* Last thing that main() should do */
292         thrd_exit(0);
293
294         return (0);
295 }