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