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