/*

    XOR-Crypter
    (c) 2000-2001 Udo Wolter, uwp@dicke-aersche.de

    Reads a file and a key file and xors them. The result goes to
    the standard output. The key file must be equal or longer than
    the file which should be crypted. Optional an offset can be
    given on which the crypting begins.

    Usage: XOR-crypt file key-file [offset] > crypted-file

    Should compile with:

    gcc -O2 XOR-crypt.c -o XOR-crypt

    on any Linux-System. Send me patches if it needs to be changed
    on other systems.

    BTW, this is truely the safest way of encryption, although
    it's symmetric encryption...

    V1.6 (2001-02-01): Corrected version-dates & added version in help line
    V1.5 (2001-01-25): Even big files are supported (byte-for-byte)
    V1.4 (2000-11-21): Inserted GNU GPL hints
    V1.3 (2000-11-21): Add some documentation in the code
    V1.2 (2000-11-20): Initial Version

    REMINDER:

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License (GPL) as published
    by the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version. The GPL can be found here:
    http://www.gnu.org/copyleft/gpl.html
   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
    USA or take it from the web site as described earlier in this document
 
*/

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <malloc.h>
#include <stdlib.h>

char vers[] = "1.6";

int main(int ac, char **av){

  FILE *text;
  FILE *key;
  struct stat statbuf;
  long btsize, bksize;
  char buftext;
  char bufkey;
  char bufresult;
  long total;
  long i, offset;

  if ((ac < 3) || (ac > 4)){
    fprintf(stderr,"%s: Version %s\n\n",av[0],vers);
    fprintf(stderr,"Usage: %s file keyfile [offset]\n",av[0]);
    return(-1);
  }

/*
   open data & key file
*/
  text = fopen(av[1], "r");
  key = fopen(av[2], "r");

/*
   offset is used ? if there's no offset in the options, it gets
   an offset of 0
*/
  if (ac == 4){
    offset = atoi(av[3]);
  } else {
    offset = 0;
  }

/*
   test if data file exists. ok, maybe it should have been tested at the
   fopen, but this is also ok
*/
  if (stat(av[1], &statbuf) == -1){
    perror(av[1]);
    return(-2);
  }

/*
   size of the data file
*/
  btsize = (long)statbuf.st_size;

/*
   test like in the data file part
*/
  if (stat(av[2], &statbuf) == -1){
    perror(av[2]);
    return(-3);
  }

/*
   size of the key file
*/
  bksize = (long)statbuf.st_size;

/*
   the safe encryption shouldn't have a smaller key
*/
  if (bksize < btsize){
    fprintf(stderr,"Key file must have equal or bigger size !\n");
    return(-4);
  }

/*
   if the offset is bigger than the keyfile the offset will be
   displaced
*/
  offset = offset % bksize;

/*
   total counter is needed for offset wraparound
*/
  total=0;

/*
   setting the file position in the key file
*/
  fseek(key, offset, SEEK_SET);

/*
   starting at the offset, ending at the keyfile's last byte
*/
  for (i=offset; i<bksize; i++){

/*
   Byte-for-byte method, so you can also use bigger files & key-files
*/
    fread(&buftext, 1, 1, text);
    fread(&bufkey, 1, 1, key);

/*
   this is the encryption, it's a simple xor :-)
*/

    bufresult = (unsigned char) ((int)buftext ^ (int)bufkey);
    printf("%c", bufresult);
    total++;

/*
   if the keyfile is bigger than the data file it should end coding
   when the end of the data file has been reached
*/
    if (total >= btsize){
      break;
    }
  }

/*
   if the offset reaches the end of the keyfile, it should start
   again at the beginning of the keyfile, simple wraparound
*/
  if ((offset) && (total < btsize)){

/*
   This time the offset starts at the beginning of the key-file,
   because of the wraparound
*/
    fseek(key, 0, SEEK_SET);
    for (i=0; i<offset; i++){

/*
   Again: byte-for-byte
*/
      fread(&buftext, 1, 1, text);
      fread(&bufkey, 1, 1, key);

      bufresult = (unsigned char) ((int)buftext ^ (int)bufkey);
      printf("%c", bufresult);
      total++;

/*
   this time for real. here it should end the loop when everything
   of the data is coded
*/
      if (total >= btsize){
        break;
      }
    }
  }

/*
   Closing the files
*/
  fclose(text);
  fclose(key);
  return(0);
}


