/* * rp1p.c * This Program won't work on the sparc, where there's no concept of I/O space. * Tested with 2.2, 2.4, 2.6 and Cygwin (MS-Windows) on the x86, should run on the alpha. * * Important: this program won't work without the compiler-option -O or -O2 ... * and this program can only be run by a superuser (or another user after * "chown root.root rp1p; chmod 4755 rp1p"). * * This user-space-program reads the bytes from the true random number generator rp1. * The speed is approx. 600 Kilobyte/s. * * rp1p and rb1m (the module which also uses the rp1) * can be used at the same time, but one random byte from the parallel port can be read only from * one of this programs. * The parallel port base (first command line argument) should be set correct. * Otherwise the program reads other Bytes (usually only 0xff). 2000 Rolf Freitag, rolf.freitag at email.de This Program is free software; you can redistribute it and/od modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at yout option) any later version. This Program is distributed in the hope that it will be useful, but WITHOUT ANY WARRENTY; without even the implied warrenty of MERCHANTABILITY of FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this Program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/ #define RANDOMBITCOUNT(x) (((BX_(x)+(BX_(x)>>4)) & 0x0F0F0F0F) % 255) #define BX_(x) ((x) - (((x)>>1)&0x77777777) \ - (((x)>>2)&0x33333333) \ - (((x)>>3)&0x11111111)) // simple version number #define SOFTWARE_VERSION_NUMBER 1.1 // defines for default parallel port #ifdef __sparc__ # error "This Program can't run on the Sparc platform" #endif #ifdef __alpha__ # define PPB 0x3bc #else # define PPB 0x378 #endif #include /* error codes */ #include // or asm/io.h #include #include #include #include //#include #include // system() #include // getuid() #include #include // or, and, ... // pseudorandom number parameters #define IA 16807 #define IM 2147483647 #define IQ 127773 #define IR 2836 static unsigned char f[5]; // buffer static FILE *ofp1 = NULL; // Output-File-Pointer to the random byte file static FILE *ofp2 = NULL; // Output-File-Pointer to the version number of ofp1 // 5 1/4 " - Disc-Size : 1457152 static unsigned int byteanz = ((unsigned int) 1457152); static unsigned int ll = 0; // version number of ofp1 static int ssm = 0; // flag for single-shot or contiguous mode */ static unsigned int b = PPB; // parallel port base void sig_handler (int sig) { printf ("\aSignal %d - program exiting... \r\n", sig); if (ofp1 != NULL) fclose (ofp1); if (ofp2 != NULL) fclose (ofp2); iopl (0); exit (0); } /* sig_handler */ void direct () /* direct output */ { unsigned long int li = 0; register unsigned char c = 0; for (;;) { rewind (ofp2); fprintf (ofp2, "%u\n", ll); fflush (ofp2); rewind (ofp1); for (li = 0; li < byteanz; li += 5) { c = inb (b + 1); /* direct reading */ c >>= 3; /* shift the 5 Bits from the status register to the right end */ f[0] = c & 0x1f; // store the 5 bits c = inb (b + 1); f[0] |= ((c << 2) & 0x70); f[1] = (c >> 6) & 0x03; c = inb (b + 1); f[1] |= (c >> 1) & 0x7c; c = inb (b + 1); f[1] |= (c << 4) & 0x80; f[2] = (c >> 4) & 0x0f; c = inb (b + 1); f[2] |= (c << 1) & 0xf0; f[3] = (c >> 7) & 0x01; c = inb (b + 1); f[3] |= (c >> 2) & 0x3c; c = inb (b + 1); f[3] |= (c << 3) & 0xc0; f[4] = (c >> 5) & 0x7; c = inb (b + 1); f[4] |= c & 0xf8; fwrite (f, 5 * (sizeof (unsigned char)), 1, ofp1); // direct writing fflush (ofp1); } ll++; if (ssm) break; } } /* direct */ void slow () /* slow speed version of direct (), rel. high quality by slow speed */ { unsigned char stmp = 0; unsigned long int li = 0; register unsigned char c = 0; for (;;) { rewind (ofp2); fprintf (ofp2, "%u\n", ll); fflush (ofp2); rewind (ofp1); for (li = 0; li < byteanz; li += 5) { c = 0; for (stmp = 0x08; stmp <= 0x80; stmp <<= 1) /* read 5 times one bit direct */ { c += inb (b + 1) & stmp; // store the bit if (stmp == 0x80) break; } c >>= 3; /* shift the 5 Bits from the status register to the right end */ f[0] = c & 0x1f; c = 0; for (stmp = 0x08; stmp <= 0x80; stmp <<= 1) { c += inb (b + 1) & stmp; if (stmp == 0x80) break; } f[0] |= ((c << 2) & 0x70); f[1] = (c >> 6) & 0x03; c = 0; for (stmp = 0x08; stmp <= 0x80; stmp <<= 1) { c += inb (b + 1) & stmp; if (stmp == 0x80) break; } f[1] |= (c >> 1) & 0x7c; c = 0; for (stmp = 0x08; stmp <= 0x80; stmp <<= 1) { c += inb (b + 1) & stmp; if (stmp == 0x80) break; } f[1] |= (c << 4) & 0x80; f[2] = (c >> 4) & 0x0f; c = 0; for (stmp = 0x08; stmp <= 0x80; stmp <<= 1) { c += inb (b + 1) & stmp; if (stmp == 0x80) break; } f[2] |= (c << 1) & 0xf0; f[3] = (c >> 7) & 0x01; c = 0; for (stmp = 0x08; stmp <= 0x80; stmp <<= 1) { c += inb (b + 1) & stmp; if (stmp == 0x80) break; } f[3] |= (c >> 2) & 0x3c; c = 0; for (stmp = 0x08; stmp <= 0x80; stmp <<= 1) { c += inb (b + 1) & stmp; if (stmp == 0x80) break; } f[3] |= (c << 3) & 0xc0; f[4] = (c >> 5) & 0x7; c = 0; for (stmp = 0x08; stmp <= 0x80; stmp <<= 1) { c += inb (b + 1) & stmp; if (stmp == 0x80) break; } f[4] |= c & 0xf8; fwrite (f, 5 * (sizeof (unsigned char)), 1, ofp1); // direct writing fflush (ofp1); } ll++; if (ssm) break; } } /* slow */ void good_quality () /* producec good random numbers even without a rp1 */ { FILE *ifp = NULL; /* for /dev/urandom */ int i1 = 0, k = 0; /* for minimal Standard Generator (Lewis, Goodman, Miller, 1969) */ register unsigned char c = 0; unsigned char uc = 0; /* for random bytes from /dev/urandom */ unsigned int li = 0; ifp = fopen ("/dev/urandom", "r"); if (ferror (ifp)) { perror ("\a can't open /dev/urandom "); exit (errno); } fscanf (ifp, "%c", &uc); i1 = ((unsigned int) uc); /* init */ fscanf (ifp, "%c", &uc); i1 |= ((unsigned int) uc) << 8; fscanf (ifp, "%c", &uc); i1 |= ((unsigned int) uc) << 16; fscanf (ifp, "%c", &uc); i1 |= ((unsigned int) uc) << 24; fclose (ifp); i1 -= RANDOMBITCOUNT (getpid ()) - RANDOMBITCOUNT (inb (b + 1)); if (i1) { /* reverse */ i1 = ((i1 >> 1) & 0x55555555) | ((i1 << 1) & 0xaaaaaaaa); i1 = ((i1 >> 2) & 0x33333333) | ((i1 << 2) & 0xcccccccc); i1 = ((i1 >> 4) & 0x0f0f0f0f) | ((i1 << 4) & 0xf0f0f0f0); i1 = ((i1 >> 8) & 0x00ff00ff) | ((i1 << 8) & 0xff00ff00); i1 = ((i1 >> 16) & 0x0000ffff) | ((i1 << 16) & 0xffff0000); } else i1 = time (NULL); for (;;) { rewind (ofp2); fprintf (ofp2, "%ud\n", ll); fflush (ofp2); rewind (ofp1); for (li = 0; li < byteanz; li += 5) { f[2] = ~inb (b + 1); /* diret reading and cyclic inversion, store */ f[4] = ~inb (b + 1); f[0] = ~inb (b + 1); f[3] = inb (b + 1); f[1] = inb (b + 1); c = ~inb (b + 1); c >>= 3; /* shift the 5 Bits from the status register to the right end */ f[3] ^= c; /* complete the first byte */ f[1] ^= c >> 2; c = inb (b + 1); f[1] ^= (c >>= 3); f[4] ^= (c >>= 1); f[0] ^= c >> 3; c = inb (b + 1); f[0] ^= (c >>= 2); f[2] ^= c >> 1; k = i1 / IQ; i1 = IA * (i1 - k * IQ) - IR * k; if (i1 < 0) i1 += IM; f[1] ^= (unsigned char) i1; /* EXOR of pseudo random byte and true random byte makes the */ f[0] ^= (unsigned char) (i1 >> 8); /* true random byte better (more entropy, more entropy cover) */ f[2] ^= (unsigned char) (i1 >> 16); k = i1 / IQ; i1 = IA * (i1 - k * IQ) - IR * k; if (i1 < 0) i1 += IM; f[4] ^= (unsigned char) i1; f[3] ^= (unsigned char) (i1 >> 8); /* output */ fwrite (f, 5 * (sizeof (unsigned char)), 1, ofp1); fflush (ofp1); } ll++; if (ssm) break; } } /* good_quality */ int main (const int argc, const char *const argv[]) { char c1 = '0'; int i = 0; // char line1[255] = { '\0' }; // char line2[255] = { '\0' }; // char line3[255] = { '\0' }; char outname1[255] = "/dev/null"; char outname2[255] = "/dev/null"; signal (SIGHUP, sig_handler); signal (SIGINT, sig_handler); signal (SIGQUIT, sig_handler); //signal (SIGILL, sig_handler); signal (SIGTRAP, sig_handler); //signal (SIGIOT, sig_handler); /* signal(SIGEMT, sig_handler); */ signal (SIGFPE, sig_handler); signal (SIGKILL, sig_handler); signal (SIGBUS, sig_handler); signal (SIGSEGV, sig_handler); /* signal(SIGSYS, sig_handler); */ signal (SIGPIPE, sig_handler); signal (SIGALRM, sig_handler); signal (SIGTERM, sig_handler); signal (SIGABRT, sig_handler); if ((argc > 1) and not strncmp (argv[1], "-V", 123)) { fprintf (stdout, "%s version %.1f\n", argv[0], SOFTWARE_VERSION_NUMBER); exit ((2 == argc) ? 0 : -1); } if ((5 >= argc) and (4 <= argc)) { // ok } else { printf ("Usage: %s \n", argv[0]); fprintf (stderr, "\a\r\nUsage: %s [output-file-size in 5*(n/5) Byte]\r\n", argv[0]); printf ("or: %s -V\n", argv[0]); fprintf (stderr, "[] = Optional <> = Parameter Requirement. 1 or 4..5 parameters required.\n"); exit (-1); } b = strtol (argv[1], (char **) NULL, 0); // base i = strtol (argv[4], (char **) NULL, 0); // number of bytes if (geteuid () != 0) { printf ("\a\n\nWarning: $EUID==%d=0 (it seems you are not a superuser and therefore can not access the I/O ports).\n\n", getuid ()); // exit (-EPERM); } sscanf (argv[2], "%c", &c1); sscanf (argv[3], "%s", outname1); if (i) { byteanz = ((unsigned int) i); ssm = 1; } ofp1 = fopen (outname1, "w"); if (ferror (ofp1)) { perror ("\a output-random-number-file-error \n"); fclose (ofp1); exit (errno); } chmod (outname1, 01644); /* read for all, write only for superusers */ ofp2 = fopen (outname2, "w"); if (ferror (ofp2)) { perror ("\a output-log-file-error \n"); fclose (ofp1); fclose (ofp2); exit (errno); } chmod (outname2, 01644); iopl (3); // allows access to all I/O-Ports, ioperm doesen't work above the 0x3ff-Limit e. g. at PCI-Cards outb (0x04, b + 2); // write; /STROBE + /AUTOFD + INIT + /SELECT for power supply of the generator outb (0xff, b); switch (c1) { case ('d'): direct (); break; case ('s'): slow (); break; default: good_quality (); break; } if (ofp1 != NULL) fclose (ofp1); if (ofp2 != NULL) fclose (ofp2); iopl (0); // no I/O permission exit (0); } /* main */ #undef RANDOMBITCOUNT #undef BX_ #undef PPB