/ 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