/* * TEA Total Copyright (c) Alex Holden 2000, 2001. * * This code is public domain; you can do whatever you want with it, though I * would prefer you to contribute any bug fixes back to me if possible. * This software comes with NO WARRANTY WHATSOEVER, not even the implied * warranties of merchantability and fitness for a particular purpose. * * randint.c: Generates a random key using a hash of key press timings. */ #include #include #include #include #include #include "teatotal.h" #include "tea-kgen.h" #include "md5.h" #define TEA_KGEN_MSG "Please mash the keyboard to generate randomness.\n" /* * For systems which don't have a /dev/random or equivalent, we generate the * key data by timing the gap between key presses for 128 presses (I'm assuming * that we can safely get one bit of randomness from each key stroke), and then * distilling the data by performing an MD5 hash on the resulting array of * times. The MD5 hash is performed by the functions in the file md5.c, which * is a public domain implementation of MD5 by Colin Plumb. If you find the * number of key presses you need to do annoying, it is probably safe to * reduce the loop count somewhat (keep it a multiple of 16 though). */ void generate_key(teastate *state) { char c; int bits; long udiff, sdiff; u32 diffs[16]; struct termios ti; struct timeval tv, otv; struct MD5Context md5state; /* Check that this is being run from a terminal */ if(!isatty(STDIN_FILENO)) die("Must be run from a terminal\n"); /* Save the current terminal attributes */ tcgetattr(STDIN_FILENO, &origtermattr); /* Register a cleanup function to restore the attributes on exit */ atexit(restore_termattr); /* Clear ICANON and ECHO on STDIN so we get characters one at a time * and they aren't echoed to the console, and flush the input buffer */ tcgetattr(STDIN_FILENO, &ti); ti.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSAFLUSH, &ti); /* Print a message about needing to generate randomness */ safe_write(STDERR_FILENO, TEA_KGEN_MSG, sizeof(TEA_KGEN_MSG)); /* Initialise the MD5 state structure */ MD5Init(&md5state); /* Get the initial time */ gettimeofday(&otv, NULL); /* Loop around once per key press for a total of 128 times */ for(bits = 0; bits < 128; bits++) { /* Read the next keypress- the value of the key is ignored */ if(read(STDIN_FILENO, &c, 1) != 1) die("Error reading from keyboard\n"); /* Get the new time */ gettimeofday(&tv, NULL); /* Calculate the difference between the new and old times */ udiff = tv.tv_usec - otv.tv_usec; sdiff = tv.tv_sec - otv.tv_sec; diffs[bits % 16] = (1000000 * sdiff) + udiff; /* When the array is full, add the latest delays to the hash */ if(!((bits + 1) % 16)) MD5Update(&md5state, (char *)diffs, 64); /* Rotate the new time to the old time */ otv.tv_usec = tv.tv_usec; otv.tv_sec = tv.tv_sec; /* Give the user an indication that something is happening */ if(!(bits % 2)) write(STDERR_FILENO, ".", 1); } /* End the line of dots */ #ifdef DOS_FILE_ENDINGS write(STDERR_FILENO, "\r\n", 2); #else write(STDERR_FILENO, "\n", 1); #endif /* Read the random data from the hash structure into the key array */ MD5Final((unsigned char *)state->k, &md5state); }