1#ifndef LINT 2static const char rcsid[] = "$Header: /usr/local/opengrok/home/cvs-mirror/mirrors/netbsd/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