#include #include #include #include #include #include #include #include #include #include "bitbuffer.h" #include "debias.h" #include "asoundrunner.h" static char *version_number = "0.2"; int daemonise = 0; int verbose = 0; int minwatermark = 256; int maxwatermark = 4096-256; int depositsize = 64; int buffersize = 64 * 16; BitBuffer incoming_bits; BitBuffer buffered_bits; int randomfd; struct injector { int ent_count; int size; union { int ints[128]; BitField bitfield[512]; } value; } random_injector; int bits_in_pool(void) { int ret; ioctl(randomfd, RNDGETENTCNT, &ret); return ret; } void do_mixin_bits(void) { int i; int bits_before = bits_in_pool(); if (verbose > 3) printf("Injecting %d bits of entropy into the kernel\n", depositsize * 8); random_injector.ent_count = depositsize * 8; random_injector.size = depositsize; for (i = 0; i < depositsize; ++i) { bitbuffer_extract_bits(buffered_bits, random_injector.value.bitfield + i, 8); } if (ioctl(randomfd, RNDADDENTROPY, &random_injector) == -1) { perror("ioctl"); } if (verbose > 3) printf("Kernel now at %d bits of entropy\n", bits_in_pool()); if (bits_before == bits_in_pool()) printf("Did it fail?!?!\n"); } void main_loop() { fd_set readfds; fd_set writefds; fd_set errfds; int ret; int adding = 0; FD_ZERO(&writefds); while (1) { if (restart_arecord == 1) { int pid; if (verbose > 1) printf("Need to restart arecord.\n"); pid = start_arecord(incoming_bits); if (pid == -1) return; if (verbose > 1) printf("Started arecord with pid %d\n", pid); FD_ZERO(&readfds); FD_ZERO(&errfds); if (restart_arecord) { printf("Arecord already died.\n"); return; } } FD_SET(arecord_read_fd, &readfds); FD_SET(arecord_read_fd, &errfds); ret = select(arecord_read_fd + 1, &readfds, &writefds, &errfds, NULL); if (ret == -1) { perror("select"); return; } if (FD_ISSET(arecord_read_fd, &readfds)) asound_do_read(); if (FD_ISSET(arecord_read_fd, &errfds)) { printf("Error on arecord fd, gotta restart.\n"); restart_arecord = 1; } ret = transfer_bits_and_debias(incoming_bits, buffered_bits); if (verbose > 3 && ret > 0) printf("Added %d bits to cache. Now at %d/%d bits in it\n", ret, bitbuffer_available_bits(buffered_bits), buffersize * 8); if (bits_in_pool() <= minwatermark && adding == 0) { if (verbose > 2) printf("Transition to inserting entropy. Kernel pool at %d\n", bits_in_pool()); adding = 1; } if (bits_in_pool() >= maxwatermark && adding == 1) { if (verbose > 2) printf("Transition to waiting. Kernel pool at %d\n", bits_in_pool()); adding = 0; } if (adding == 1) { if (bitbuffer_available_bits(buffered_bits) >= (depositsize * 8)) { do_mixin_bits(); if (verbose > 3) printf("Kernel entropy pool now sits at %d bits\n", bits_in_pool()); } } } } void usage(const char* prog, FILE *output) { fprintf(output, "%s: Usage:\n"\ "\n"\ "Argument: h - display this help message\n"\ " V - display version information.\n", " D - Daemonize\n"\ " v - Increase verbosity. Can be used more than once.\n"\ " m - specify minimum number of bits of entropy in the pool.\n"\ " M - specify max number of bits in the pool.\n"\ " b - specify number of bytes of randomness to buffer for use.\n"\ " d - specify number of bytes to deposit into the pool each time.\n", prog); } void version(const char* prog, FILE *output) { fprintf(output, "%s: %s\n"\ "Copyright 2007 Daniel Silverstone\n", prog, version_number); } int main(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, ":hDvVm:M:b:d:")) != -1) { switch (opt) { case 'h': usage(argv[0], stdout); return 0; case 'V': version(argv[0], stdout); return 0; case 'D': daemonise = 1; break; case 'v': verbose += 1; break; case 'm': minwatermark = atoi(optarg); break; case 'M': maxwatermark = atoi(optarg); break; case 'b': buffersize = atoi(optarg); break; case 'd': depositsize = atoi(optarg); break; default: usage(argv[0], stderr); return 1; } } /* Validate options now */ if (minwatermark < 64) { fprintf(stderr, "Minimum watermark is below 64 bits. This is silly.\n"); return 2; } if (maxwatermark > 4096) { fprintf(stderr, "Maxmimum watermark is above 4096. This is not possible.\n"); return 2; } if (buffersize < depositsize || buffersize > (1024*1024)) { fprintf(stderr, "Buffer size smaller than deposit size or greater than one megabyte.\n"); return 2; } if (depositsize < 4 || depositsize > 512 || (depositsize & 3) != 0) { fprintf(stderr, "Deposit size must be a multiple of four, between 4 and 512 inclusive.\n"); return 2; } if (verbose > 0) { printf("Random sound daemon. Copyright 2007 Daniel Silverstone.\n\n"); printf("Will keep random pool between %d and %d bits of entropy.\n", minwatermark, maxwatermark); printf("Will retain a buffer of %d bytes, making entropy deposits of %d bytes at a time.\n", buffersize, depositsize); if (daemonise == 1) { printf("Will daemonise.\n"); } } if (verbose > 1) { printf("Allocating a %d bit buffer for the incoming bits.\n", buffersize * 8 * 4); } incoming_bits = bitbuffer_new(buffersize * 8 * 4); buffered_bits = bitbuffer_new(buffersize * 8); if (incoming_bits == NULL || buffered_bits == NULL) { fprintf(stderr, "Unable to allocate buffers.\n"); return 3; } randomfd = open("/dev/random", O_RDWR); if (randomfd == -1) { perror("Opening /dev/random\n"); return 3; } if (daemonise == 1) { printf("Daemonising\n"); fflush(stdout); int fd = fork(); if (fd == -1 ) { perror("forking daemon.\n"); return 4; } if (fd != 0) return 0; setpgrp(); setsid(); } main_loop(); return -1; }