/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
NAME
  xor - simple "one-time pad" encryption program

SYNOPSIS
  xor infile1 [infile2 [outfile]]

DESCRIPTION
  The xor program reads two input files, exclusive-ors their contents,
  and writes the result to an output file.  If either of the two input
  files is available to both ends of a transaction, then this  program
  implements an unbreakable one-time pad encryption of the other input
  file.

  If the outfile is missing, stdout will be used.  If the second input
  file is missing, stdin is used.  Thus  this  program  behaves  as  a
  normal  Unix  "filter", though it does require one file name (either
  the key or the data file) on the command line.

  Here's  how  to  use  this  program  is  useful  as  a  simple  (but
  unbreakable)  encryption  scheme.   To  encrypt  a text file T using
  another file K as the key, use the command:
    xor K T X
  and then send the files K and X via separate channels.   Don't  send
  your text file T.  The recipient then runs the command
    xor K X T
  and  your text file T will be reconstructed.  K may be any available
  file, but for encryption purposes, the best value for K  is  a  file
  that  you  know  the  recipient  already  has,  and thus need not be
  transmitted.  Files from a  vendor's  distribution  disks  are  good
  choices  for K, as long as you have the same disks on both ends, and
  a good way of telling the recipient which file to use for K.

  While arbitrary files K and T may be used, it is best  if  they  are
  roughly the same size.  This program produces an output file as long
  as the second of its two input files. If the input files are not the
  same  size,  then  the  first  will  be  adjusted  (by truncation or
  rereading) to make up the difference.

  A useful mathematical property of the xor operation is  that,  given
  any  two  of the files K, T and X, this program will reconstruct the
  third file.  Care must be taken, of course,  to  name  them  on  the
  command line in an order to give the correct size.

  An amusing use of this property is to "prove" that the file T is  an
  encrypted  form  of the file K.  Suppose that K is an innocuous text
  (the U.S.  Constitution, some document that you don't agree with, or
  the binary image of a competitor's application) and T is a bitmapped
  image of a pornographic picture.  Construct the file X as above.  It
  is  the "key" to the "decoding" of K.  Send the file K and the key X
  to some recipient, with instructions to run the command
    xor K X T
  and then display the output file T  with  the  appropriate  graphics
  package. The picture T will appear on their screen, "proving" that K
  was really an encrypted pornographic picture. If K is a message that
  you  have  received,  you  can  use  this method to "prove" that the
  sender has used email to send you an encrypted pornographic picture.

  Enjoy!

AUTHOR
  Copyright 1995, 1996 by John Chambers  <jc%trillian.mit.edu>.   All
  rights reserved.  Permission is granted to copy this program by any
  method, provided that you don't sell it, don't claim that you wrote
  it, and don't use it to prove that it is an encryption of any other
  text.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <stdio.h>
main(ac,av) char**av;
{	int a;
	FILE *filin;		/* Input file */
	int   c1,  c2;		/* Input chars */
	extern int errno;	/* Error code */

	if (ac < 2) {
		fprintf(stderr,"Usage: %s infile1 infile2 [outfile]\n",av[0]);
		exit(1);
	}
	if (!(filin = fopen(av[1],"r"))) {
		fprintf(stderr,"%s\t### Can't read \"%s\"\n",av[0],av[1]);
		exit(errno);
	}
	if (ac > 2 && !freopen(av[2],"r",stdin)) {
		fprintf(stderr,"%s\t### Can't read \"%s\"\n",av[0],av[2]);
		exit(errno);
	}
	if (ac > 3 && !freopen(av[3],"w",stdout)) {
		fprintf(stderr,"%s\t### Can't write \"%s\"\n",av[0],av[3]);
		exit(errno);
	}
	for (;;) {
		c1 = getc(filin);
		c2 = getc(stdin);
		if (c1 == EOF) {
			fclose(filin);
			if (!freopen(av[1],"r",filin)) {
				fprintf(stderr,"%s\t### Can't re-read \"%s\"\n",av[0],av[1]);
				exit(errno);
			}
			c1 = getc(filin);
		}
		if (c2 == EOF) {
			exit(0);	/* We've hit EOF on file 2 */
		}
		putc((c1 ^ c2), stdout);
	}
}
