/ entropy-gathering / entropy-stats.c
entropy-stats.c
  1  /*
  2   * An experiment to show how much entropy one can gather from diverse
  3   * system and process counters.
  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  /* VMSy stuff */
 25  #ifdef __VMS
 26  # include <descrip.h>
 27  # include <stsdef.h>
 28  # include <ssdef.h>
 29  # include <starlet.h>
 30  # include <lib$routines.h>
 31  # ifdef __DECC
 32  #  pragma message disable DOLLARID
 33  # endif
 34  
 35  # include "dict.h"
 36  # include "entropy.h"
 37  
 38  size_t total_bits = 0;
 39  size_t total_entropy = 0;
 40  size_t total_rounds = 0;
 41  size_t data_sz = 0;
 42  
 43  void final_entropy()
 44  {
 45    if (total_bits)
 46      printf("Total bits / entropy: %d / %d (ratio = %f)\n",
 47  	   total_bits, total_entropy, (double)total_entropy / total_bits);
 48    else
 49      printf("No data gathered yet\n");
 50    printf("Data was gathered in %d byte chunks\n", data_sz * sizeof(uint32_t));
 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    size_t bytes = 0;
 61  
 62    {
 63      size_t i, j;
 64  
 65      /* Calculate total data size */
 66      for (i = 0; i < dicts(); i++) {
 67        ile3 *itms = items(i);
 68        size_t num_itms = num_items(i);
 69  
 70        for (j = 0; j < num_itms; j++)
 71  	data_sz += itms[j].ile3$w_length / sizeof(uint32_t);
 72      }
 73      init_entropy_state(data_sz);
 74    }
 75  
 76    atexit(final_entropy);
 77    signal(SIGINT, sigint);
 78    do {
 79      size_t round_entropy = 0;
 80      size_t round_bits = 0;
 81      size_t pos = 0;
 82      size_t i, j;
 83      uint32_t status = gather_system_data();
 84      if (!($VMS_STATUS_SUCCESS(status)))
 85        lib$signal(status);
 86  
 87      for (i = 0; i < dicts(); i++) {
 88        for (j = 0; j < num_items(i); j++) {
 89  	size_t sz = items(i)[j].ile3$w_length / sizeof(uint32_t);
 90  	size_t entropy = 0;
 91  	size_t k;
 92  	char buffer[1024];
 93  
 94  	for (k = 0; k < sz; k++) {
 95  	  entropy +=
 96  	    calculate_entropy(((uint32_t *)(items(i)[j].ile3$ps_bufaddr))[k],
 97  			      pos++);
 98  	}
 99  	bytes += fwrite(items(i)[j].ile3$ps_bufaddr,
100  			items(i)[j].ile3$w_length, 1,
101  			binout)
102  	  * items(i)[j].ile3$w_length;
103  
104  	/* We must count all bits for fair measurements */
105  	round_bits += items(i)[j].ile3$w_length * 8;
106  	round_entropy += entropy;
107  
108  	/*
109  	 * There's no point in using the entropy on the first run,
110  	 * as there isn't enough saved state.
111  	 */
112  	if (first)
113  	  continue;
114  
115  	/* We don't care to display zero entropy items */
116  	if (entropy == 0)
117  	  continue;
118  
119  	if (item_istime(i, items(i)[j].ile3$w_code)) {
120  	  size_t timlen = 0;
121  
122  	  $DESCRIPTOR(timbuf, buffer);
123  	  sys$asctim(&timlen, &timbuf, items(i)[j].ile3$ps_bufaddr, 0);
124  	  buffer[timlen] = '\0';
125  	} else {
126  	  size_t buflen = 0;
127  
128  	  if (sz > 2) {
129  	    strcpy(buffer, "\n  ");
130  	    buflen = strlen(buffer);
131  	  }
132  	  for (k = 0; k < sz; k++) {
133  	    size_t itemlen = 0;
134  
135  	    if (k > 0) {
136  	      if (k % 4 == 0) {
137  		strcpy(buffer + buflen, ",\n  ");
138  		buflen += strlen(buffer + buflen);
139  	      } else {
140  		strcpy(buffer + buflen, ", ");
141  		buflen += strlen(buffer + buflen);
142  	      }
143  	    }
144  	    itemlen = snprintf(buffer + buflen, sizeof(buffer) - buflen,
145  			       "0x%08X",
146  			       ((uint32_t *)(items(i)[j].ile3$ps_bufaddr))[k]);
147  	    buflen += itemlen;
148  	  }
149  	  buffer[buflen] = '\0';
150  	}
151  	printf("%s: (%d) ", item_name(i, items(i)[j].ile3$w_code), entropy);
152  	puts(buffer);
153        }
154      }
155      first = 0;
156      total_rounds++;
157      total_bits += round_bits;
158      total_entropy += round_entropy;
159      if (round_bits)
160        printf("Total bits / entropy this round: %d / %d (ratio = %f)\n",
161  	     round_bits, round_entropy, (double)round_entropy / round_bits);
162      else
163        printf("No data gathered this round\n");
164  
165      printf("%lu bytes written to file so far\n", bytes);
166      if (bytes >= maxbytes)
167        break;
168      printf("%lu bytes still needed\n", maxbytes - bytes);
169  
170      {
171        int sleeptime = rand() % 10 + 1;
172        printf("DEBUG: sleep %d seconds\n", sleeptime);
173        sleep(sleeptime);
174      }
175    } while (1);
176  }
177  #endif
178  
179  /********************************************************************/
180  int main()
181  {
182    FILE *binout = NULL;
183  
184    srand((unsigned int)time(NULL));
185    binout = fopen("entropy-stats.bin", "w", "ctx=bin");
186    test_entropy(binout, 1024 * 1024);
187    fclose(binout);
188  }
189