Annotation of embedaddon/dhcp/dst/prandom.c, revision 1.1.1.1
1.1 misho 1: #ifndef LINT
1.1.1.1 ! misho 2: static const char rcsid[] = "$Header: /tmp/cvstest/DHCP/dst/prandom.c,v 1.6.328.1 2012/03/09 16:00:13 tomasz Exp $";
1.1 misho 3: #endif
4: /*
1.1.1.1 ! misho 5: * Portions Copyright (c) 2007,2012 by Internet Systems Consortium, Inc. ("ISC")
1.1 misho 6: * Portions Copyright (c) 1995-1998 by Trusted Information Systems, 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 structures like
51: * stat and time wrap over blocks. This adds certain randomness 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 dictates 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 initializer 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 contains 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 controls 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 values
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 frequently 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 successful 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: ; /* 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 add 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 variable in the work structure 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: /* calculate 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 initialized
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 especially 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 directories 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: /*
696: * now get the initial seed to put into the quick random function from
697: * the address of the work structure
698: */
699: bytes = (int) getpid();
700: /*
701: * proceed while needed
702: */
703: while (work->filled < work->needed) {
704: EREPORT(("own_random r %08x b %6d t %6d f %6d\n",
705: ran_val, bytes, work->in_temp, work->filled));
706: /* pick a random number in the range of 0..7 based on that random number
707: * perform some operations that yield random data
708: */
709: n = (dst_s_quick_random(bytes) >> DST_SHIFT) & 0x07;
710: switch (n) {
711: case 0:
712: case 3:
713: if (sizeof(cmds) > 2 *sizeof(*cmds)) {
714: b = unix_cmd(work);
715: cmd += b;
716: }
717: break;
718:
719: case 1:
720: case 7:
721: if (sizeof(dirs) > 2 *sizeof(*dirs)) {
722: b = do_ls(work);
723: dir += b;
724: }
725: break;
726:
727: case 4:
728: case 5:
729: /* retry getting data from /dev/random */
730: b = get_dev_random(&work->output[work->filled],
731: work->needed - work->filled);
732: if (b > 0)
733: work->filled += b;
734: break;
735:
736: case 6:
737: if (sizeof(files) > 2 * sizeof(*files)) {
738: b = digest_file(work);
739: dig += b;
740: }
741: break;
742:
743: case 2:
744: default: /* to make sure we make some progress */
745: work->output[work->filled++] = 0xff &
746: dst_s_quick_random(bytes);
747: b = 1;
748: break;
749: }
750: if (b > 0)
751: bytes += b;
752: }
753: return (work->filled);
754: }
755:
756:
757: /*
758: * dst_s_random() This function will return the requested number of bytes
759: * of randomness to the caller it will use the best available sources of
760: * randomness.
761: * The current order is to use /dev/random, precalculated randomness, and
762: * finally use some system calls and programs to generate semi random data
763: * that is then digested to generate randomness.
764: * This function is thread safe as each thread uses its own context, but
765: * concurrent treads will affect each other as they update shared state
766: * information.
767: * It is strongly recommended that this function be called requesting a size
768: * that is not a multiple of the output of the hash function used.
769: *
770: * If /dev/random is not available this function is not suitable to generate
771: * large amounts of data, rather it is suitable to seed a pseudo-random
772: * generator
773: * Returns the number of bytes put in the output buffer
774: */
775: int
776: dst_s_random(u_char *output, unsigned size)
777: {
778: int n = 0, i;
779: unsigned s;
780: static u_char old_unused[DST_HASH_SIZE * DST_NUM_HASHES];
781: static unsigned unused = 0;
782:
783: if (size <= 0 || output == NULL)
784: return (0);
785:
786: if (size >= 2048)
787: return (-1);
788: /*
789: * Read from /dev/random
790: */
791: n = get_dev_random(output, size);
792: /*
793: * If old data is available and needed use it
794: */
795: if (n < size && unused > 0) {
796: unsigned need = size - n;
797: if (unused <= need) {
798: memcpy(output, old_unused, unused);
799: n += unused;
800: unused = 0;
801: } else {
802: memcpy(output, old_unused, need);
803: n += need;
804: unused -= need;
805: memcpy(old_unused, &old_unused[need], unused);
806: }
807: }
808: /*
809: * If we need more use the simulated randomness here.
810: */
811: if (n < size) {
812: dst_work *my_work = (dst_work *) malloc(sizeof(dst_work));
813: if (my_work == NULL)
814: return (n);
815: my_work->needed = size - n;
816: my_work->filled = 0;
817: my_work->output = (u_char *) malloc(my_work->needed +
818: DST_HASH_SIZE *
819: DST_NUM_HASHES);
820: my_work->file_digest = NULL;
821: if (my_work->output == NULL)
822: return (n);
823: memset(my_work->output, 0x0, my_work->needed);
824: /* allocate upto 4 different HMAC hash functions out of order */
825: #if DST_NUM_HASHES >= 3
826: my_work->hash[2] = get_hmac_key(3, DST_RANDOM_BLOCK_SIZE / 2);
827: #endif
828: #if DST_NUM_HASHES >= 2
829: my_work->hash[1] = get_hmac_key(7, DST_RANDOM_BLOCK_SIZE / 6);
830: #endif
831: #if DST_NUM_HASHES >= 4
832: my_work->hash[3] = get_hmac_key(5, DST_RANDOM_BLOCK_SIZE / 4);
833: #endif
834: my_work->hash[0] = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE);
835: if (my_work->hash[0] == NULL) /* if failure bail out */
836: return (n);
837: s = own_random(my_work);
838: /* if more generated than needed store it for future use */
839: if (s >= my_work->needed) {
840: EREPORT(("dst_s_random(): More than needed %d >= %d\n",
841: s, my_work->needed));
842: memcpy(&output[n], my_work->output, my_work->needed);
843: n += my_work->needed;
844: /* saving unused data for next time */
845: unused = s - my_work->needed;
846: memcpy(old_unused, &my_work->output[my_work->needed],
847: unused);
848: } else {
849: /* XXXX This should not happen */
850: EREPORT(("Not enough %d >= %d\n", s, my_work->needed));
851: memcpy(&output[n], my_work->output, s);
852: n += my_work->needed;
853: }
854:
855: /* delete the allocated work area */
856: for (i = 0; i < DST_NUM_HASHES; i++) {
857: dst_free_key(my_work->hash[i]->key);
858: SAFE_FREE(my_work->hash[i]);
859: }
860: SAFE_FREE(my_work->output);
861: SAFE_FREE(my_work);
862: }
863: return (n);
864: }
865:
866: /*
867: * A random number generator that is fast and strong
868: * this random number generator is based on HASHing data,
869: * the input to the digest function is a collection of <NUMBER_OF_COUNTERS>
870: * counters that is incremented between digest operations
871: * each increment operation amortizes to 2 bits changed in that value
872: * for 5 counters thus the input will amortize to have 10 bits changed
873: * The counters are initially set using the strong random function above
874: * the HMAC key is selected by the same method as the HMAC keys for the
875: * strong random function.
876: * Each set of counters is used for 2^25 operations
877: *
878: * returns the number of bytes written to the output buffer
879: * or negative number in case of error
880: */
881: int
882: dst_s_semi_random(u_char *output, unsigned size)
883: {
884: static u_int32_t counter[DST_NUMBER_OF_COUNTERS];
885: static u_char semi_old[DST_HASH_SIZE];
886: static int semi_loc = 0, cnt = 0;
887: static unsigned hb_size = 0;
888: static DST_KEY *my_key = NULL;
889: prand_hash *hash;
890: unsigned out = 0;
891: unsigned i;
892: int n;
893:
894: if (output == NULL || size <= 0)
895: return (-2);
896:
897: /* check if we need a new key */
898: if (my_key == NULL || cnt > (1 << 25)) { /* get HMAC KEY */
899: if (my_key)
900: my_key->dk_func->destroy(my_key);
901: if ((hash = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE)) == NULL)
902: return (0);
903: my_key = hash->key;
904: /* check if the key works stir the new key using some old random data */
905: hb_size = dst_sign_data(SIG_MODE_ALL, my_key, NULL,
906: (u_char *) counter, sizeof(counter),
907: semi_old, sizeof(semi_old));
908: if (hb_size <= 0) {
909: EREPORT(("dst_s_semi_random() Sign of alg %d failed %d\n",
910: my_key->dk_alg, hb_size));
911: return (-1);
912: }
913: /* new set the counters to random values */
914: dst_s_random((u_char *) counter, sizeof(counter));
915: cnt = 0;
916: }
917: /* if old data around use it first */
918: if (semi_loc < hb_size) {
919: if (size <= hb_size - semi_loc) { /* need less */
920: memcpy(output, &semi_old[semi_loc], size);
921: semi_loc += size;
922: return (size); /* DONE */
923: } else {
924: out = hb_size - semi_loc;
925: memcpy(output, &semi_old[semi_loc], out);
926: semi_loc += out;
927: }
928: }
929: /* generate more random stuff */
930: while (out < size) {
931: /*
932: * modify at least one bit by incrementing at least one counter
933: * based on the last bit of the last counter updated update
934: * the next one.
935: * minimally this operation will modify at least 1 bit,
936: * amortized 2 bits
937: */
938: for (n = 0; n < DST_NUMBER_OF_COUNTERS; n++)
939: i = (int) counter[n]++;
940:
941: i = dst_sign_data(SIG_MODE_ALL, my_key, NULL,
942: (u_char *) counter, hb_size,
943: semi_old, sizeof(semi_old));
944: if (i != hb_size)
945: EREPORT(("HMAC SIGNATURE FAILURE %d\n", i));
946: cnt++;
947: if (size - out < i) /* Not all data is needed */
948: semi_loc = i = size - out;
949: memcpy(&output[out], semi_old, i);
950: out += i;
951: }
952: return (out);
953: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>