]> git.ipfire.org Git - thirdparty/dhcp.git/blob - dst/prandom.c
b45c5332ddf6e48f43739479af68d7c0fb7dc6f4
[thirdparty/dhcp.git] / dst / prandom.c
1 #ifndef LINT
2 static const char rcsid[] = "$Header: /tmp/cvstest/DHCP/dst/prandom.c,v 1.3 2007/05/19 19:16:25 dhankins Exp $";
3 #endif
4 /*
5 * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
6 * Portions Copyright (c) 2007 by Internet Systems Consortium, Inc.
7 *
8 * Permission to use, copy modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
13 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
15 * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
16 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
17 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
18 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19 * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
20 */
21
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <time.h>
29 #include <dirent.h>
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33
34 #include <netinet/in.h>
35 #include <sys/socket.h>
36 #define NEED_PRAND_CONF
37 #include "minires/minires.h"
38 #include "dst_internal.h"
39 #include "arpa/nameser.h"
40
41
42 #ifndef DST_NUM_HASHES
43 #define DST_NUM_HASHES 4
44 #endif
45 #ifndef DST_NUMBER_OF_COUNTERS
46 #define DST_NUMBER_OF_COUNTERS 5 /* 32 * 5 == 160 == SHA(1) > MD5 */
47 #endif
48
49 /*
50 * the constant below is a prime number to make fixed data structues like
51 * stat and time wrap over blocks. This adds certain uncertanty to what is
52 * in each digested block.
53 * The prime number 2879 has the special property that when
54 * divided by 2,4 and 6 the result is also a prime numbers
55 */
56
57 #ifndef DST_RANDOM_BLOCK_SIZE
58 #define DST_RANDOM_BLOCK_SIZE 2879
59 #endif
60
61 /*
62 * This constant dictatates how many bits we shift to the right before using a
63 */
64 #ifndef DST_SHIFT
65 #define DST_SHIFT 9
66 #endif
67
68 /*
69 * An initalizer that is as bad as any other with half the bits set
70 */
71 #ifndef DST_RANDOM_PATTERN
72 #define DST_RANDOM_PATTERN 0x8765CA93
73 #endif
74 /*
75 * things must have changed in the last 3600 seconds to be used
76 */
77 #define MAX_OLD 3600
78
79 /*
80 * Define a single set of configuration for prand stuff. A superset
81 * works okay (failed commands return no data, missing directories
82 * are skipped, and so on.
83 */
84 static const char *cmds[] = {
85 "/usr/bin/netstat -an 2>&1",
86 "/usr/sbin/netstat -an 2>&1",
87 "/usr/etc/netstat -an 2>&1",
88 "/bin/netstat -an 2>&1",
89 "/usr/ucb/netstat -an 2>&1",
90
91 /* AIX */
92 "/bin/ps -ef 2>&1",
93 "/bin/df 2>&1",
94 "/usr/bin/uptime 2>&1",
95 "/usr/bin/printenv 2>&1",
96 "/usr/bin/netstat -s 2>&1",
97 "/usr/bin/w 2>&1",
98 /* Tru64 */
99 "/usr/bin/dig com. soa +ti=1 +retry=0 2>&1",
100 "/usr/sbin/arp -an 2>&1",
101 "/usr/ucb/uptime 2>&1",
102 "/bin/iostat 2>&1",
103 /* BSD */
104 "/bin/ps -axlw 2>&1",
105 "/usr/sbin/iostat 2>&1",
106 "/usr/sbin/vmstat 2>&1",
107 /* FreeBSD */
108 "/usr/bin/vmstat 2>&1",
109 "/usr/bin/w 2>&1",
110 /* HP/UX */
111 "/usr/bin/ps -ef 2>&1",
112 /* IRIX */
113 "/usr/etc/arp -a 2>&1",
114 "/usr/bsd/uptime 2>&1",
115 "/usr/bin/printenv 2>&1",
116 "/usr/bsd/w 2>&1",
117 /* Linux */
118 "/sbin/arp -an 2>&1",
119 "/usr/bin/vmstat 2>&1",
120 /* NetBSD */
121 /* OpenBSD */
122 /* QNX */
123 "/bin/ps -a 2>&1",
124 "/bin/sin 2>&1",
125 "/bin/sin fds 2>&1",
126 "/bin/sin memory 2>&1",
127 /* Solaris */
128 "/usr/ucb/uptime 2>&1",
129 "/usr/ucb/netstat -an 2>&1",
130
131 "/usr/bin/netstat -an 2>&1",
132 "/usr/sbin/netstat -an 2>&1",
133 "/usr/etc/netstat -an 2>&1",
134 "/bin/netstat -an 2>&1",
135 "/usr/ucb/netstat -an 2>&1",
136 NULL
137 };
138
139 static const char *dirs[] = {
140 "/tmp",
141 "/var/tmp",
142 ".",
143 "/",
144 "/var/spool",
145 "/var/adm",
146 "/dev",
147 "/var/spool/mail",
148 "/var/mail",
149 "/home",
150 "/usr/home",
151 NULL
152 };
153
154 static const char *files[] = {
155 "/var/adm/messages",
156 "/var/adm/wtmp",
157 "/var/adm/lastlog",
158 "/var/log/messages",
159 "/var/log/wtmp",
160 "/var/log/lastlog",
161 "/proc/stat",
162 "/proc/rtc",
163 "/proc/meminfo",
164 "/proc/interrupts",
165 "/proc/self/status",
166 "/proc/ipstats",
167 "/proc/dumper",
168 "/proc/self/as",
169 NULL
170 };
171
172 /*
173 * these two data structure are used to process input data into digests,
174 *
175 * The first structure is containts a pointer to a DST HMAC key
176 * the variables accompanying are used for
177 * step : select every step byte from input data for the hash
178 * block: number of data elements going into each hash
179 * digested: number of data elements digested so far
180 * curr: offset into the next input data for the first byte.
181 */
182 typedef struct hash {
183 DST_KEY *key;
184 void *ctx;
185 int digested, block, step, curr;
186 } prand_hash;
187
188 /*
189 * This data structure controlls number of hashes and keeps track of
190 * overall progress in generating correct number of bytes of output.
191 * output : array to store the output data in
192 * needed : how many bytes of output are needed
193 * filled : number of bytes in output so far.
194 * bytes : total number of bytes processed by this structure
195 * file_digest : the HMAC key used to digest files.
196 */
197 typedef struct work {
198 unsigned needed, filled, bytes;
199 u_char *output;
200 prand_hash *hash[DST_NUM_HASHES];
201 DST_KEY *file_digest;
202 } dst_work;
203
204
205 /*
206 * forward function declarations
207 */
208 static int get_dev_random(u_char *output, unsigned size);
209 static int do_time(dst_work *work);
210 static int do_ls(dst_work *work);
211 static int unix_cmd(dst_work *work);
212 static int digest_file(dst_work *work);
213
214 static void force_hash(dst_work *work, prand_hash *hash);
215 static int do_hash(dst_work *work, prand_hash *hash, const u_char *input,
216 unsigned size);
217 static int my_digest(dst_work *tmp, const u_char *input, unsigned size);
218 static prand_hash *get_hmac_key(int step, int block);
219
220 static unsigned own_random(dst_work *work);
221
222
223 /*
224 * variables used in the quick random number generator
225 */
226 static u_int32_t ran_val = DST_RANDOM_PATTERN;
227 static u_int32_t ran_cnt = (DST_RANDOM_PATTERN >> 10);
228
229 /*
230 * setting the quick_random generator to particular values or if both
231 * input parameters are 0 then set it to initial vlaues
232 */
233
234 void
235 dst_s_quick_random_set(u_int32_t val, u_int32_t cnt)
236 {
237 ran_val = (val == 0) ? DST_RANDOM_PATTERN : val;
238 ran_cnt = (cnt == 0) ? (DST_RANDOM_PATTERN >> 10) : cnt;
239 }
240
241 /*
242 * this is a quick and random number generator that seems to generate quite
243 * good distribution of data
244 */
245 u_int32_t
246 dst_s_quick_random(int inc)
247 {
248 ran_val = ((ran_val >> 13) ^ (ran_val << 19)) ^
249 ((ran_val >> 7) ^ (ran_val << 25));
250 if (inc > 0) /* only increasing values accepted */
251 ran_cnt += inc;
252 ran_val += ran_cnt++;
253 return (ran_val);
254 }
255
256 /*
257 * get_dev_random: Function to read /dev/random reliably
258 * this function returns how many bytes where read from the device.
259 * port_after.h should set the control variable HAVE_DEV_RANDOM
260 */
261 static int
262 get_dev_random(u_char *output, unsigned size)
263 {
264 #ifdef HAVE_DEV_RANDOM
265 struct stat st;
266 int n = 0, fd = -1, s;
267
268 s = stat("/dev/random", &st);
269 if (s == 0 && S_ISCHR(st.st_mode)) {
270 if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) != -1) {
271 if ((n = read(fd, output, size)) < 0)
272 n = 0;
273 close(fd);
274 }
275 return (n);
276 }
277 #endif
278 return (0);
279 }
280
281 /*
282 * Portable way of getting the time values if gettimeofday is missing
283 * then compile with -DMISSING_GETTIMEOFDAY time() is POSIX compliant but
284 * gettimeofday() is not.
285 * Time of day is predictable, we are looking for the randomness that comes
286 * the last few bits in the microseconds in the timer are hard to predict when
287 * this is invoked at the end of other operations
288 */
289 struct timeval *mtime;
290 static int
291 do_time(dst_work *work)
292 {
293 int cnt = 0;
294 static u_char tmp[sizeof(struct timeval) + sizeof(struct timezone)];
295 struct timezone *zone;
296
297 zone = (struct timezone *) tmp;
298 mtime = (struct timeval *)(tmp + sizeof(struct timezone));
299 gettimeofday(mtime, zone);
300 cnt = sizeof(tmp);
301 my_digest(work, tmp, sizeof(tmp));
302
303 return (cnt);
304 }
305
306 /*
307 * this function simulates the ls command, but it uses stat which gives more
308 * information and is harder to guess
309 * Each call to this function will visit the next directory on the list of
310 * directories, in a circular manner.
311 * return value is the number of bytes added to the temp buffer
312 *
313 * do_ls() does not visit subdirectories
314 * if attacker has access to machine it can guess most of the values seen
315 * thus it is important to only visit directories that are freqently updated
316 * Attacker that has access to the network can see network traffic
317 * when NFS mounted directories are accessed and know exactly the data used
318 * but may not know exactly in what order data is used.
319 * Returns the number of bytes that where returned in stat structures
320 */
321 static int
322 do_ls(dst_work *work)
323 {
324 struct dir_info {
325 uid_t uid;
326 gid_t gid;
327 off_t size;
328 time_t atime, mtime, ctime;
329 };
330 static struct dir_info dir_info;
331 struct stat buf;
332 struct dirent *entry;
333 static int i = 0;
334 static unsigned long d_round = 0;
335 struct timeval tv;
336 int n = 0, tb_i = 0, out = 0;
337 unsigned dir_len;
338
339 char file_name[1024];
340 u_char tmp_buff[1024];
341 DIR *dir = NULL;
342
343 if (dirs[i] == NULL) /* if at the end of the list start over */
344 i = 0;
345 if (stat(dirs[i++], &buf)) /* directory does not exist */
346 return (0);
347
348 gettimeofday(&tv,NULL);
349 if (d_round == 0)
350 d_round = tv.tv_sec - MAX_OLD;
351 else if (i==1) /* if starting a new round cut what we accept */
352 d_round += (tv.tv_sec - d_round)/2;
353
354 if (buf.st_atime < d_round)
355 return (0);
356
357 EREPORT(("do_ls i %d filled %4d in_temp %4d\n",
358 i-1, work->filled, work->in_temp));
359 memcpy(tmp_buff, &buf, sizeof(buf));
360 tb_i += sizeof(buf);
361
362
363 if ((dir = opendir(dirs[i-1])) == NULL)/* open it for read */
364 return (0);
365 strcpy(file_name, dirs[i-1]);
366 dir_len = strlen(file_name);
367 file_name[dir_len++] = '/';
368 while ((entry = readdir(dir))) {
369 unsigned len = strlen(entry->d_name);
370 out += len;
371 if (my_digest(work, (u_char *)entry->d_name, len))
372 break;
373
374 memcpy(&file_name[dir_len], entry->d_name, len);
375 file_name[dir_len + len] = 0x0;
376 /* for all entries in dir get the stats */
377 if (stat(file_name, &buf) == 0) {
378 n++; /* count successfull stat calls */
379 /* copy non static fields */
380 dir_info.uid += buf.st_uid;
381 dir_info.gid += buf.st_gid;
382 dir_info.size += buf.st_size;
383 dir_info.atime += buf.st_atime;
384 dir_info.mtime += buf.st_mtime;
385 dir_info.ctime += buf.st_ctime;
386 out += sizeof(dir_info);
387 if(my_digest(work, (u_char *)&dir_info,
388 sizeof(dir_info)))
389 break;
390 }
391 }
392 closedir(dir); /* done */
393 out += do_time(work); /* add a time stamp */
394 return (out);
395 }
396
397
398 /*
399 * unix_cmd()
400 * this function executes the a command from the cmds[] list of unix commands
401 * configured in the prand_conf.h file
402 * return value is the number of bytes added to the randomness temp buffer
403 *
404 * it returns the number of bytes that where read in
405 * if more data is needed at the end time is added to the data.
406 * This function maintains a state to selects the next command to run
407 * returns the number of bytes read in from the command
408 */
409 static int
410 unix_cmd(dst_work *work)
411 {
412 static int cmd_index = 0;
413 int cnt = 0, n;
414 FILE *pipe;
415 u_char buffer[4096];
416
417 if (cmds[cmd_index] == NULL)
418 cmd_index = 0;
419 EREPORT(("unix_cmd() i %d filled %4d in_temp %4d\n",
420 cmd_index, work->filled, work->in_temp));
421 pipe = popen(cmds[cmd_index++], "r"); /* execute the command */
422
423 while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0) {
424 cnt += n; /* process the output */
425 if (my_digest(work, buffer, (unsigned)n))
426 break;
427 /* this adds some randomness to the output */
428 cnt += do_time(work);
429 }
430 while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0)
431 NULL; /* drain the pipe */
432 pclose(pipe);
433 return (cnt); /* read how many bytes where read in */
434 }
435
436 /*
437 * digest_file() This function will read a file and run hash over it
438 * input is a file name
439 */
440 static int
441 digest_file(dst_work *work)
442 {
443 static int f_cnt = 0;
444 static unsigned long f_round = 0;
445 FILE *fp;
446 void *ctx;
447 const char *name;
448 int no, i;
449 struct stat st;
450 struct timeval tv;
451 u_char buf[1024];
452
453 if (f_round == 0 || files[f_cnt] == NULL || work->file_digest == NULL)
454 if (gettimeofday(&tv, NULL)) /* only do this if needed */
455 return (0);
456 if (f_round == 0) /* first time called set to one hour ago */
457 f_round = (tv.tv_sec - MAX_OLD);
458 name = files[f_cnt++];
459 if (files[f_cnt] == NULL) { /* end of list of files */
460 if(f_cnt <= 1) /* list is too short */
461 return (0);
462 f_cnt = 0; /* start again on list */
463 f_round += (tv.tv_sec - f_round)/2; /* set new cutoff */
464 work->file_digest = dst_free_key(work->file_digest);
465 }
466 if (work->file_digest == NULL) {
467 work->file_digest = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0,
468 (u_char *)&tv, sizeof(tv));
469 if (work->file_digest == NULL)
470 return (0);
471 }
472 if (access(name, R_OK) || stat(name, &st))
473 return (0); /* no such file or not allowed to read it */
474 if (strncmp(name, "/proc/", 6) && st.st_mtime < f_round)
475 return(0); /* file has not changed recently enough */
476 if (dst_sign_data(SIG_MODE_INIT, work->file_digest, &ctx,
477 NULL, 0, NULL, 0)) {
478 work->file_digest = dst_free_key(work->file_digest);
479 return (0);
480 }
481 if ((fp = fopen(name, "r")) == NULL)
482 return (0);
483 for (no = 0; (i = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0;
484 no += i)
485 dst_sign_data(SIG_MODE_UPDATE, work->file_digest, &ctx,
486 buf, (unsigned)i, NULL, 0);
487
488 fclose(fp);
489 if (no >= 64) {
490 i = dst_sign_data(SIG_MODE_FINAL, work->file_digest, &ctx,
491 NULL, 0, &work->output[work->filled],
492 DST_HASH_SIZE);
493 if (i > 0)
494 work->filled += i;
495 }
496 else if (i > 0)
497 my_digest(work, buf, (unsigned)i);
498 my_digest(work, (const u_char *)name, strlen(name));
499 return (no + strlen(name));
500 }
501
502 /*
503 * function to perform the FINAL and INIT operation on a hash if allowed
504 */
505 static void
506 force_hash(dst_work *work, prand_hash *hash)
507 {
508 int i = 0;
509
510 /*
511 * if more than half a block then add data to output
512 * otherwise adde the digest to the next hash
513 */
514 if ((hash->digested * 2) > hash->block) {
515 i = dst_sign_data(SIG_MODE_FINAL, hash->key, &hash->ctx,
516 NULL, 0, &work->output[work->filled],
517 DST_HASH_SIZE);
518
519 hash->digested = 0;
520 dst_sign_data(SIG_MODE_INIT, hash->key, &hash->ctx,
521 NULL, 0, NULL, 0);
522 if (i > 0)
523 work->filled += i;
524 }
525 return;
526 }
527
528 /*
529 * This function takes the input data does the selection of data specified
530 * by the hash control block.
531 * The step varialbe in the work sturcture determines which 1/step bytes
532 * are used,
533 *
534 */
535 static int
536 do_hash(dst_work *work, prand_hash *hash, const u_char *input, unsigned size)
537 {
538 const u_char *tmp = input;
539 u_char *tp, *abuf = (u_char *)0;
540 int i, n;
541 unsigned needed, avail, dig, cnt = size;
542 unsigned tmp_size = 0;
543
544 if (cnt <= 0 || input == NULL)
545 return (0);
546
547 if (hash->step > 1) { /* if using subset of input data */
548 tmp_size = size / hash->step + 2;
549 abuf = tp = malloc(tmp_size);
550 tmp = tp;
551 for (cnt = 0, i = hash->curr; i < size; i += hash->step, cnt++)
552 *(tp++) = input[i];
553 /* calcutate the starting point in the next input set */
554 hash->curr = (hash->step - (i - size)) % hash->step;
555 }
556 /* digest the data in block sizes */
557 for (n = 0; n < cnt; n += needed) {
558 avail = (cnt - n);
559 needed = hash->block - hash->digested;
560 dig = (avail < needed) ? avail : needed;
561 dst_sign_data(SIG_MODE_UPDATE, hash->key, &hash->ctx,
562 &tmp[n], dig, NULL, 0);
563 hash->digested += dig;
564 if (hash->digested >= hash->block)
565 force_hash(work, hash);
566 if (work->needed < work->filled) {
567 if (abuf)
568 SAFE_FREE2(abuf, tmp_size);
569 return (1);
570 }
571 }
572 if (tmp_size > 0)
573 SAFE_FREE2(abuf, tmp_size);
574 return (0);
575 }
576
577 /*
578 * Copy data from INPUT for length SIZE into the work-block TMP.
579 * If we fill the work-block, digest it; then,
580 * if work-block needs more data, keep filling with the rest of the input.
581 */
582 static int
583 my_digest(dst_work *work, const u_char *input, unsigned size)
584 {
585
586 int i, full = 0;
587 static unsigned counter;
588
589 counter += size;
590 /* first do each one of the hashes */
591 for (i = 0; i < DST_NUM_HASHES && full == 0; i++)
592 full = do_hash(work, work->hash[i], input, size) +
593 do_hash(work, work->hash[i], (u_char *) &counter,
594 sizeof(counter));
595 /*
596 * if enough data has be generated do final operation on all hashes
597 * that have enough date for that
598 */
599 for (i = 0; full && (i < DST_NUM_HASHES); i++)
600 force_hash(work, work->hash[i]);
601
602 return (full);
603 }
604
605 /*
606 * this function gets some semi random data and sets that as an HMAC key
607 * If we get a valid key this function returns that key initalized
608 * otherwise it returns NULL;
609 */
610 static prand_hash *
611 get_hmac_key(int step, int block)
612 {
613
614 u_char *buff;
615 int temp = 0, n = 0;
616 unsigned size = 70;
617 DST_KEY *new_key = NULL;
618 prand_hash *new = NULL;
619
620 /* use key that is larger than digest algorithms (64) for key size */
621 buff = malloc(size);
622 if (buff == NULL)
623 return (NULL);
624 /* do not memset the allocated memory to get random bytes there */
625 /* time of day is somewhat random expecialy in the last bytes */
626 gettimeofday((struct timeval *) &buff[n], NULL);
627 n += sizeof(struct timeval);
628
629 /* get some semi random stuff in here stir it with micro seconds */
630 if (n < size) {
631 temp = dst_s_quick_random((int) buff[n - 1]);
632 memcpy(&buff[n], &temp, sizeof(temp));
633 n += sizeof(temp);
634 }
635 /* get the pid of this process and its parent */
636 if (n < size) {
637 temp = (int) getpid();
638 memcpy(&buff[n], &temp, sizeof(temp));
639 n += sizeof(temp);
640 }
641 if (n < size) {
642 temp = (int) getppid();
643 memcpy(&buff[n], &temp, sizeof(temp));
644 n += sizeof(temp);
645 }
646 /* get the user ID */
647 if (n < size) {
648 temp = (int) getuid();
649 memcpy(&buff[n], &temp, sizeof(temp));
650 n += sizeof(temp);
651 }
652 #ifndef GET_HOST_ID_MISSING
653 if (n < size) {
654 temp = (int) gethostid();
655 memcpy(&buff[n], &temp, sizeof(temp));
656 n += sizeof(temp);
657 }
658 #endif
659 /* get some more random data */
660 if (n < size) {
661 temp = dst_s_quick_random((int) buff[n - 1]);
662 memcpy(&buff[n], &temp, sizeof(temp));
663 n += sizeof(temp);
664 }
665 /* covert this into a HMAC key */
666 new_key = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0, buff, size);
667 SAFE_FREE(buff);
668
669 /* get the control structure */
670 if ((new = malloc(sizeof(prand_hash))) == NULL)
671 return (NULL);
672 new->digested = new->curr = 0;
673 new->step = step;
674 new->block = block;
675 new->key = new_key;
676 if (dst_sign_data(SIG_MODE_INIT, new_key, &new->ctx, NULL, 0, NULL, 0))
677 return (NULL);
678
679 return (new);
680 }
681
682 /*
683 * own_random()
684 * This function goes out and from various sources tries to generate enough
685 * semi random data that a hash function can generate a random data.
686 * This function will iterate between the two main random source sources,
687 * information from programs and directores in random order.
688 * This function return the number of bytes added to the random output buffer.
689 */
690 static unsigned
691 own_random(dst_work *work)
692 {
693 int dir = 0, b;
694 int bytes, n, cmd = 0, dig = 0;
695 int start =0;
696 /*
697 * now get the initial seed to put into the quick random function from
698 * the address of the work structure
699 */
700 bytes = (int) getpid();
701 /*
702 * proceed while needed
703 */
704 while (work->filled < work->needed) {
705 EREPORT(("own_random r %08x b %6d t %6d f %6d\n",
706 ran_val, bytes, work->in_temp, work->filled));
707 /* pick a random number in the range of 0..7 based on that random number
708 * perform some operations that yield random data
709 */
710 start = work->filled;
711 n = (dst_s_quick_random(bytes) >> DST_SHIFT) & 0x07;
712 switch (n) {
713 case 0:
714 case 3:
715 if (sizeof(cmds) > 2 *sizeof(*cmds)) {
716 b = unix_cmd(work);
717 cmd += b;
718 }
719 break;
720
721 case 1:
722 case 7:
723 if (sizeof(dirs) > 2 *sizeof(*dirs)) {
724 b = do_ls(work);
725 dir += b;
726 }
727 break;
728
729 case 4:
730 case 5:
731 /* retry getting data from /dev/random */
732 b = get_dev_random(&work->output[work->filled],
733 work->needed - work->filled);
734 if (b > 0)
735 work->filled += b;
736 break;
737
738 case 6:
739 if (sizeof(files) > 2 * sizeof(*files)) {
740 b = digest_file(work);
741 dig += b;
742 }
743 break;
744
745 case 2:
746 default: /* to make sure we make some progress */
747 work->output[work->filled++] = 0xff &
748 dst_s_quick_random(bytes);
749 b = 1;
750 break;
751 }
752 if (b > 0)
753 bytes += b;
754 }
755 return (work->filled);
756 }
757
758
759 /*
760 * dst_s_random() This function will return the requested number of bytes
761 * of randomness to the caller it will use the best available sources of
762 * randomness.
763 * The current order is to use /dev/random, precalculated randomness, and
764 * finaly use some system calls and programs to generate semi random data that
765 * is then digested to generate randomness.
766 * This function is thread safe as each thread uses its own context, but
767 * concurrent treads will affect each other as they update shared state
768 * information.
769 * It is strongly recommended that this function be called requesting a size
770 * that is not a multiple of the output of the hash function used.
771 *
772 * If /dev/random is not available this function is not suitable to generate
773 * large ammounts of data, rather it is suitable to seed a pseudo-random
774 * generator
775 * Returns the number of bytes put in the output buffer
776 */
777 int
778 dst_s_random(u_char *output, unsigned size)
779 {
780 int n = 0, i;
781 unsigned s;
782 static u_char old_unused[DST_HASH_SIZE * DST_NUM_HASHES];
783 static unsigned unused = 0;
784
785 if (size <= 0 || output == NULL)
786 return (0);
787
788 if (size >= 2048)
789 return (-1);
790 /*
791 * Read from /dev/random
792 */
793 n = get_dev_random(output, size);
794 /*
795 * If old data is available and needed use it
796 */
797 if (n < size && unused > 0) {
798 unsigned need = size - n;
799 if (unused <= need) {
800 memcpy(output, old_unused, unused);
801 n += unused;
802 unused = 0;
803 } else {
804 memcpy(output, old_unused, need);
805 n += need;
806 unused -= need;
807 memcpy(old_unused, &old_unused[need], unused);
808 }
809 }
810 /*
811 * If we need more use the simulated randomness here.
812 */
813 if (n < size) {
814 dst_work *my_work = (dst_work *) malloc(sizeof(dst_work));
815 if (my_work == NULL)
816 return (n);
817 my_work->needed = size - n;
818 my_work->filled = 0;
819 my_work->output = (u_char *) malloc(my_work->needed +
820 DST_HASH_SIZE *
821 DST_NUM_HASHES);
822 my_work->file_digest = NULL;
823 if (my_work->output == NULL)
824 return (n);
825 memset(my_work->output, 0x0, my_work->needed);
826 /* allocate upto 4 different HMAC hash functions out of order */
827 #if DST_NUM_HASHES >= 3
828 my_work->hash[2] = get_hmac_key(3, DST_RANDOM_BLOCK_SIZE / 2);
829 #endif
830 #if DST_NUM_HASHES >= 2
831 my_work->hash[1] = get_hmac_key(7, DST_RANDOM_BLOCK_SIZE / 6);
832 #endif
833 #if DST_NUM_HASHES >= 4
834 my_work->hash[3] = get_hmac_key(5, DST_RANDOM_BLOCK_SIZE / 4);
835 #endif
836 my_work->hash[0] = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE);
837 if (my_work->hash[0] == NULL) /* if failure bail out */
838 return (n);
839 s = own_random(my_work);
840 /* if more generated than needed store it for future use */
841 if (s >= my_work->needed) {
842 EREPORT(("dst_s_random(): More than needed %d >= %d\n",
843 s, my_work->needed));
844 memcpy(&output[n], my_work->output, my_work->needed);
845 n += my_work->needed;
846 /* saving unused data for next time */
847 unused = s - my_work->needed;
848 memcpy(old_unused, &my_work->output[my_work->needed],
849 unused);
850 } else {
851 /* XXXX This should not happen */
852 EREPORT(("Not enough %d >= %d\n", s, my_work->needed));
853 memcpy(&output[n], my_work->output, s);
854 n += my_work->needed;
855 }
856
857 /* delete the allocated work area */
858 for (i = 0; i < DST_NUM_HASHES; i++) {
859 dst_free_key(my_work->hash[i]->key);
860 SAFE_FREE(my_work->hash[i]);
861 }
862 SAFE_FREE(my_work->output);
863 SAFE_FREE(my_work);
864 }
865 return (n);
866 }
867
868 /*
869 * A random number generator that is fast and strong
870 * this random number generator is based on HASHing data,
871 * the input to the digest function is a collection of <NUMBER_OF_COUNTERS>
872 * counters that is incremented between digest operations
873 * each increment operation amortizes to 2 bits changed in that value
874 * for 5 counters thus the input will amortize to have 10 bits changed
875 * The counters are initaly set using the strong random function above
876 * the HMAC key is selected by the same methold as the HMAC keys for the
877 * strong random function.
878 * Each set of counters is used for 2^25 operations
879 *
880 * returns the number of bytes written to the output buffer
881 * or negative number in case of error
882 */
883 int
884 dst_s_semi_random(u_char *output, unsigned size)
885 {
886 static u_int32_t counter[DST_NUMBER_OF_COUNTERS];
887 static u_char semi_old[DST_HASH_SIZE];
888 static int semi_loc = 0, cnt = 0;
889 static unsigned hb_size = 0;
890 static DST_KEY *my_key = NULL;
891 prand_hash *hash;
892 unsigned out = 0;
893 unsigned i;
894 int n;
895
896 if (output == NULL || size <= 0)
897 return (-2);
898
899 /* check if we need a new key */
900 if (my_key == NULL || cnt > (1 << 25)) { /* get HMAC KEY */
901 if (my_key)
902 my_key->dk_func->destroy(my_key);
903 if ((hash = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE)) == NULL)
904 return (0);
905 my_key = hash->key;
906 /* check if the key works stir the new key using some old random data */
907 hb_size = dst_sign_data(SIG_MODE_ALL, my_key, NULL,
908 (u_char *) counter, sizeof(counter),
909 semi_old, sizeof(semi_old));
910 if (hb_size <= 0) {
911 EREPORT(("dst_s_semi_random() Sign of alg %d failed %d\n",
912 my_key->dk_alg, hb_size));
913 return (-1);
914 }
915 /* new set the counters to random values */
916 dst_s_random((u_char *) counter, sizeof(counter));
917 cnt = 0;
918 }
919 /* if old data around use it first */
920 if (semi_loc < hb_size) {
921 if (size <= hb_size - semi_loc) { /* need less */
922 memcpy(output, &semi_old[semi_loc], size);
923 semi_loc += size;
924 return (size); /* DONE */
925 } else {
926 out = hb_size - semi_loc;
927 memcpy(output, &semi_old[semi_loc], out);
928 semi_loc += out;
929 }
930 }
931 /* generate more randome stuff */
932 while (out < size) {
933 /*
934 * modify at least one bit by incrementing at least one counter
935 * based on the last bit of the last counter updated update
936 * the next one.
937 * minimaly this operation will modify at least 1 bit,
938 * amortized 2 bits
939 */
940 for (n = 0; n < DST_NUMBER_OF_COUNTERS; n++)
941 i = (int) counter[n]++;
942
943 i = dst_sign_data(SIG_MODE_ALL, my_key, NULL,
944 (u_char *) counter, hb_size,
945 semi_old, sizeof(semi_old));
946 if (i != hb_size)
947 EREPORT(("HMAC SIGNATURE FAILURE %d\n", i));
948 cnt++;
949 if (size - out < i) /* Not all data is needed */
950 semi_loc = i = size - out;
951 memcpy(&output[out], semi_old, i);
952 out += i;
953 }
954 return (out);
955 }