1 /* $NetBSD: prandom.c,v 1.1.1.4 2014/07/12 11:57:50 spz Exp $ */
3 static const char rcsid
[] = "Header: /tmp/cvstest/DHCP/dst/prandom.c,v 1.10 2012/03/09 11:18:13 tomasz Exp ";
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 $");
28 #include <sys/types.h>
35 #include <sys/param.h>
39 #include <netinet/in.h>
40 #include <sys/socket.h>
41 #define NEED_PRAND_CONF
45 #include "dst_internal.h"
46 #include "arpa/nameser.h"
49 #ifndef DST_NUM_HASHES
50 #define DST_NUM_HASHES 4
52 #ifndef DST_NUMBER_OF_COUNTERS
53 #define DST_NUMBER_OF_COUNTERS 5 /* 32 * 5 == 160 == SHA(1) > MD5 */
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
69 * This constant dictates how many bits we shift to the right before using a
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
82 * things must have changed in the last 3600 seconds to be used
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",
101 "/usr/bin/uptime 2>&1",
102 "/usr/bin/printenv 2>&1",
103 "/usr/bin/netstat -s 2>&1",
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",
111 "/bin/ps -axlw 2>&1",
112 "/usr/sbin/iostat 2>&1",
113 "/usr/sbin/vmstat 2>&1",
115 "/usr/bin/vmstat 2>&1",
118 "/usr/bin/ps -ef 2>&1",
120 "/usr/etc/arp -a 2>&1",
121 "/usr/bsd/uptime 2>&1",
122 "/usr/bin/printenv 2>&1",
125 "/sbin/arp -an 2>&1",
126 "/usr/bin/vmstat 2>&1",
133 "/bin/sin memory 2>&1",
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",
146 static const char *dirs
[] = {
161 static const char *files
[] = {
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
{
192 int digested
, block
, step
, curr
;
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
;
207 prand_hash
*hash
[DST_NUM_HASHES
];
208 DST_KEY
*file_digest
;
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
,
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
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
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 */
259 ran_val
+= ran_cnt
++;
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
269 get_dev_random(u_char
*output
, unsigned size
)
271 #ifdef HAVE_DEV_RANDOM
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)
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
;
298 do_time(dst_work
*work
)
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
);
308 my_digest(work
, tmp
, sizeof(tmp
));
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
329 do_ls(dst_work
*work
)
335 time_t atime
, mtime
, ctime
;
337 static struct dir_info dir_info
;
339 struct dirent
*entry
;
341 static unsigned long d_round
= 0;
346 char file_name
[1024];
347 u_char tmp_buff
[1024];
350 if (dirs
[i
] == NULL
) /* if at the end of the list start over */
352 if (stat(dirs
[i
++], &buf
)) /* directory does not exist */
355 gettimeofday(&tv
,NULL
);
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
)
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 */
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
);
377 if (my_digest(work
, (u_char
*)entry
->d_name
, len
))
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
,
398 closedir(dir
); /* done */
399 out
+= do_time(work
); /* add a time stamp */
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
416 unix_cmd(dst_work
*work
)
418 static int cmd_index
= 0;
423 if (cmds
[cmd_index
] == NULL
)
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
))
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 */
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
447 digest_file(dst_work
*work
)
449 static int f_cnt
= 0;
450 static unsigned long f_round
= 0;
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 */
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 */
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
)
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
,
484 work
->file_digest
= dst_free_key(work
->file_digest
);
487 if ((fp
= fopen(name
, "r")) == NULL
)
489 for (no
= 0; (i
= fread(buf
, sizeof(*buf
), sizeof(buf
), fp
)) > 0;
491 dst_sign_data(SIG_MODE_UPDATE
, work
->file_digest
, &ctx
,
492 buf
, (unsigned)i
, NULL
, 0);
496 i
= dst_sign_data(SIG_MODE_FINAL
, work
->file_digest
, &ctx
,
497 NULL
, 0, &work
->output
[work
->filled
],
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
512 force_hash(dst_work
*work
, prand_hash
*hash
)
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
],
526 dst_sign_data(SIG_MODE_INIT
, hash
->key
, &hash
->ctx
,
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
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;
547 unsigned needed
, avail
, dig
, cnt
= size
;
548 unsigned tmp_size
= 0;
550 if (cnt
<= 0 || input
== NULL
)
553 if (hash
->step
> 1) { /* if using subset of input data */
554 tmp_size
= size
/ hash
->step
+ 2;
555 abuf
= tp
= malloc(tmp_size
);
557 for (cnt
= 0, i
= hash
->curr
; i
< size
; i
+= hash
->step
, cnt
++)
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
) {
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
) {
574 SAFE_FREE2(abuf
, tmp_size
);
579 SAFE_FREE2(abuf
, tmp_size
);
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.
589 my_digest(dst_work
*work
, const u_char
*input
, unsigned size
)
593 static unsigned counter
;
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
,
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
]);
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;
617 get_hmac_key(int step
, int block
)
623 DST_KEY
*new_key
= NULL
;
624 prand_hash
*new = NULL
;
626 /* use key that is larger than digest algorithms (64) for key size */
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 */
637 temp
= dst_s_quick_random((int) buff
[n
- 1]);
638 memcpy(&buff
[n
], &temp
, sizeof(temp
));
641 /* get the pid of this process and its parent */
643 temp
= (int) getpid();
644 memcpy(&buff
[n
], &temp
, sizeof(temp
));
648 temp
= (int) getppid();
649 memcpy(&buff
[n
], &temp
, sizeof(temp
));
652 /* get the user ID */
654 temp
= (int) getuid();
655 memcpy(&buff
[n
], &temp
, sizeof(temp
));
658 #ifndef GET_HOST_ID_MISSING
660 temp
= (int) gethostid();
661 memcpy(&buff
[n
], &temp
, sizeof(temp
));
665 /* get some more random data */
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
);
674 /* get the control structure */
675 if ((new = malloc(sizeof(prand_hash
))) == NULL
)
677 new->digested
= new->curr
= 0;
681 if (dst_sign_data(SIG_MODE_INIT
, new_key
, &new->ctx
, NULL
, 0, NULL
, 0)) {
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.
698 own_random(dst_work
*work
)
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;
720 if (sizeof(cmds
) > 2 *sizeof(*cmds
)) {
728 if (sizeof(dirs
) > 2 *sizeof(*dirs
)) {
736 /* retry getting data from /dev/random */
737 b
= get_dev_random(&work
->output
[work
->filled
],
738 work
->needed
- work
->filled
);
744 if (sizeof(files
) > 2 * sizeof(*files
)) {
745 b
= digest_file(work
);
751 default: /* to make sure we make some progress */
752 work
->output
[work
->filled
++] = 0xff &
753 dst_s_quick_random(bytes
);
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
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
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
780 * Returns the number of bytes put in the output buffer
783 dst_s_random(u_char
*output
, unsigned size
)
787 static u_char old_unused
[DST_HASH_SIZE
* DST_NUM_HASHES
];
788 static unsigned unused
= 0;
790 if (size
<= 0 || output
== NULL
)
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
);
809 memcpy(output
, old_unused
, need
);
812 memcpy(old_unused
, &old_unused
[need
], unused
);
816 * If we need more use the simulated randomness here.
819 dst_work
*my_work
= (dst_work
*) malloc(sizeof(dst_work
));
822 my_work
->needed
= size
- n
;
824 my_work
->output
= (u_char
*) malloc(my_work
->needed
+
827 my_work
->file_digest
= NULL
;
828 if (my_work
->output
== NULL
) {
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);
837 #if DST_NUM_HASHES >= 2
838 my_work
->hash
[1] = get_hmac_key(7, DST_RANDOM_BLOCK_SIZE
/ 6);
840 #if DST_NUM_HASHES >= 4
841 my_work
->hash
[3] = get_hmac_key(5, DST_RANDOM_BLOCK_SIZE
/ 4);
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
);
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
],
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
);
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
;
917 if (output
== NULL
|| size
<= 0)
920 /* check if we need a new key */
921 if (my_key
== NULL
|| cnt
> (1 << 25)) { /* get HMAC KEY */
923 my_key
->dk_func
->destroy(my_key
);
924 if ((hash
= get_hmac_key(1, DST_RANDOM_BLOCK_SIZE
)) == NULL
)
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
));
932 EREPORT(("dst_s_semi_random() Sign of alg %d failed %d\n",
933 my_key
->dk_alg
, hb_size
));
936 /* new set the counters to random values */
937 dst_s_random((u_char
*) counter
, sizeof(counter
));
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
);
945 return (size
); /* DONE */
947 out
= hb_size
- semi_loc
;
948 memcpy(output
, &semi_old
[semi_loc
], out
);
952 /* generate more random stuff */
955 * modify at least one bit by incrementing at least one counter
956 * based on the last bit of the last counter updated update
958 * minimally this operation will modify at least 1 bit,
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
));
972 EREPORT(("HMAC SIGNATURE FAILURE %d\n", i
));
974 if (size
- out
< i
) /* Not all data is needed */
975 semi_loc
= i
= size
- out
;
976 memcpy(&output
[out
], semi_old
, i
);