/ entropy-gathering / entropy-hash.c
entropy-hash.c
  1  /*
  2   * An experiment to show how much entropy one can gather from diverse
  3   * system and process counters by hashing them all together with SHA256.
  4   *
  5   * (with gratefulness to the folks on comp.os.vms, who kindly fed me ideas)
  6   */
  7  
  8  /*
  9   * The idea is to pick all the data into an internal state and measure how
 10   * how much they change over small periods of time.  A third order delta is
 11   * calculated for every iteration, and the position of the highest set bit
 12   * from that delta will be used as entropy estimate.  Items with no entropy
 13   * (i.e. third order delta == 0) will not be displayed.
 14   */
 15  
 16  #include <stdio.h>
 17  #include <stdlib.h>
 18  #include <string.h>
 19  #include <unistd.h>
 20  #include <time.h>
 21  #include <signal.h>
 22  #include <assert.h>
 23  
 24  #include <openssl/evp.h>
 25  
 26  /* VMSy stuff */
 27  #ifdef __VMS
 28  # include <descrip.h>
 29  # include <stsdef.h>
 30  # include <ssdef.h>
 31  # include <starlet.h>
 32  # include <lib$routines.h>
 33  # ifdef __DECC
 34  #  pragma message disable DOLLARID
 35  # endif
 36  
 37  # include "dict.h"
 38  # include "entropy.h"
 39  
 40  size_t total_bits = 0;
 41  size_t total_entropy = 0;
 42  size_t total_rounds = 0;
 43  
 44  void final_entropy()
 45  {
 46    if (total_bits)
 47      printf("Total bits / entropy: %d / %d (ratio = %f)\n",
 48  	   total_bits, total_entropy, (double)total_entropy / total_bits);
 49    else
 50      printf("No data gathered yet\n");
 51  }
 52  void sigint(int x)
 53  {
 54    exit(0);
 55  }
 56  void test_entropy(FILE *binout, size_t maxbytes)
 57  {
 58    /* Flag for the first run... */
 59    int first = 1;
 60    const EVP_MD *md = EVP_sha512();
 61    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
 62    uint32_t hash[16];	/* 512 bits */
 63    size_t bytes = 0;
 64  
 65    init_entropy_state(sizeof(hash) / sizeof(hash[0]));
 66  
 67    atexit(final_entropy);
 68    signal(SIGINT, sigint);
 69  
 70    do {
 71      size_t i, j;
 72      size_t round_entropy = 0;
 73      size_t round_bits = 0;
 74      uint32_t status = gather_system_data();
 75      if (!($VMS_STATUS_SUCCESS(status)))
 76        lib$signal(status);
 77  
 78      EVP_MD_CTX_reset(ctx);
 79      EVP_DigestInit(ctx, md);
 80  
 81      for (i = 0; i < dicts(); i++) {
 82        for (j = 0; j < num_items(i); j++) {
 83  	void *b = items(i)[j].ile3$ps_bufaddr;
 84  	int l = items(i)[j].ile3$w_length;
 85  	EVP_DigestUpdate(ctx, b, l);
 86        }
 87      }
 88  
 89      EVP_DigestFinal(ctx, (unsigned char *)hash, NULL);
 90  
 91      do {
 92        size_t entropy = 0;
 93        size_t k, pos;
 94        char *hexbuf;
 95  
 96        for (k = 0, pos = 0; k < sizeof(hash) / sizeof(hash[0]); k++) {
 97  	entropy += calculate_entropy(hash[k], pos++);
 98        }
 99        bytes += fwrite(hash, sizeof(hash), 1, binout) * sizeof(hash);
100  
101        /*
102         * There's no point in using the entropy on the first run,
103         * as there isn't enough saved state.
104         */
105        if (first)
106  	continue;
107  
108        /* We don't care about zero entropy items */
109        if (entropy == 0)
110  	continue;
111  
112        round_entropy += entropy;
113        round_bits += sizeof(hash) * 8;
114  
115        hexbuf = OPENSSL_buf2hexstr((unsigned char *)hash, sizeof(hash));
116        printf("%s: (%d)\n", hexbuf, entropy);
117      } while(0);
118  
119      first = 0;
120      total_rounds++;
121      total_bits += round_bits;
122      total_entropy += round_entropy;
123      if (round_bits)
124        printf("Total bits / entropy this round: %d / %d (ratio = %f)\n",
125  	     round_bits, round_entropy, (double)round_entropy / round_bits);
126      else
127        printf("No data gathered this round\n");
128  
129      printf("%lu bytes written to file so far\n", bytes);
130      if (bytes >= maxbytes)
131        break;
132      printf("%lu bytes still needed\n", maxbytes - bytes);
133  
134      {
135        int sleeptime = rand() % 10 + 1;
136  #ifdef DEBUG
137        fprintf(stderr, "DEBUG: sleep %d seconds\n", sleeptime);
138  #endif
139        sleep(sleeptime);
140      }
141    } while (1);
142  }
143  #endif
144  
145  /********************************************************************/
146  int main()
147  {
148    FILE *binout = NULL;
149  
150    srand((unsigned int)time(NULL));
151    binout = fopen("entropy-hash.bin", "w", "ctx=bin");
152    test_entropy(binout, 1024 * 1024);
153    fclose(binout);
154  }
155