/* exor.c: (ANSI-)C-Program for exclusive oring of files = One Time Pad (OTP) = Vernam encryption. Ein einmaliges Anwenden verschluesselt eine Datei mit einer anderen mittels byteweisem exor, ein zweites entschluesselt. Dieses Verfahren (one time pad) ist primitiv und erfordert moeglichst lange Schluessel, aber es ist sehr schnell, weil es wenig Rechenaufwand erfordert und zudem bewiesen unknackbar (wenn die zu verschluesselnde Datei nicht laenger als der Schluessel ist), denn das bitweise EXOR einer beliebigen zu verschluesselnden Bitfolge mit einer echt zufaelligen Folge von unabhaengigen Bits ist wieder eine echt zufaellige Folge von unabhngigen Bits (s. z. B. http://stat.fsu.edu/~geo/diehard.html). In dieser Version muss sich die Ausgabe-Datei von den 2 Eingabedateien unterscheiden und diese Version ist mit rd. 1MB/s (mit Pentium 233) bei grossen Dateien nicht besonders schnell, aber die Ausgabedateigroesse ist nur durch den freien Plattenplatz und nicht durch den Haupspeicher begrenzt. von Rolf Freitag 1998, rolf.freitag at email.de 11/2004: Optimized for 64 bit integer hardware (i586 and higher): 2 times faster than the old fgets/fputs version. For files bigger than 2 GiB, > 2^31 Byte, you should use the compiler option "-D_FILE_OFFSET_BITS=64". 2/2008: Eleminated wrong wrap around bug. 2010: Benchmarking with an Intel Core i7 940 on an SuperMicro X8SAX under 2.6.32-5-amd64 shows a speed of 77 MB/s, which is limitated by the HDD speed. A faster but less portable version would be possible with faster SSDs or RAIDs and using SIMD, http://en.wikipedia.org/wiki/SIMD. Example usage: exor infile.txt keyfile.bin enc.out 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 hop 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. */ #include #include #include #include #include #include #include #include #include // simple version number #define SOFTWARE_VERSION_NUMBER 1.1 # define mc_MIN(a, b) ((a) < (b) ? (a) : (b)) void sig_handler (int sig) { if ((SIGINT == sig) or (SIGILL == sig) or (SIGKILL == sig) or (SIGSEGV == sig) or (SIGTERM == sig)) { (void) printf ("\a\a\a\a\a\a\a Received signal %d, program exiting... \r\n\a\a\a", sig); exit (-sig); } printf ("Received signal %d.\r\n", sig); return; } int main (const int argc, const char * const argv[]) { FILE *ifp1; // input-file-pointer1 FILE *ifp2; // input-file-pointer2 FILE *ofp; // output file pointer char inname1[0x3ff] = // input file name1 { '\0' }; char inname2[0x3ff] = // input file name2 { '\0' }; char outname[0x3ff] = // output file name { '\0' }; int i1 = 0, i2 = 0, i3 = 0, i_retval=0, i=0; // for the chars of ifp1, ifp2, ofp, exit value, counter(s) int i_f1, i_f2, i_f3; union tag { int64_t i64; char c[8]; } // buffer unions u_buffer1 = { 0 } , u_buffer2 = { 0 }; void *buffer1 = (void *) &u_buffer1; void *buffer2 = (void *) &u_buffer2; 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 (argc not_eq 4) { fprintf (stderr, "\aUsage: %s \n", argv[0]); fprintf (stderr, "\aor: %s -V \n", argv[0]); fprintf (stderr, "[] = Optional <> = Parameter Requirement. 1 or 3 parameters required.\n"); exit (-1); } snprintf (inname1, sizeof(inname1)-1, "%s", argv[1]); snprintf (inname2, sizeof(inname2)-1, "%s", argv[2]); snprintf (outname, sizeof(outname)-1, "%s", argv[3]); ifp1 = fopen (inname1, "r"); ifp2 = fopen (inname2, "r"); if ((ifp1 == NULL) or (ifp2 == NULL)) { fprintf (stderr, "\a input-file-error "); perror("\n error \n"); exit (errno); } ofp = fopen (outname, "w+"); // overwrite existing output file if (ofp == NULL) { fprintf (stderr, "\a\ncan't open %s ", outname); perror("\n error \n"); exit (errno); // missing output file } // loop for exoring with 64 bit blocks while (not feof(ifp1) and ((i1 = fread (buffer1, 1, 8, ifp1)) != 0) ) // while the first input file is not completely read { i2 = fread (buffer2, 1, 8, ifp2); if (0 == i2) // restart if second file is smaller { rewind (ifp2); // key file: go to the file begin i2 = fread (buffer2, 1, 8, ifp2); // take the first 8 bytes } if (i2 < 8) // at the unaligned end of the key file, in first input file: go to first byte after last processed { fseek(ifp2, 0, SEEK_SET); // go to the start of the second file (wrap around) because only i2 of 8 bytes could be processed, so i1-i2 do remain. for (i=i2; i