Annotation of embedaddon/dhcp/dst/prandom.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>