#include <stdio.h>
#include <stdlib.h>
unsigned long a,b[128],index;
unsigned int r,cle;

/* CARACACHS Cipher (c) Alexandre PUKALL 2000 */
/* a 20 characters key : 160 bits is enough for security */
/* can go up to 256 charcters key : 2048 bits key */

stream(unsigned int *r,unsigned long *index,unsigned long *a,unsigned long *b)
{
  b[*index] = ( b[*index] * (*a) ) + 1;
  *r = _rotl( (*r + (( b[*index] >> 16 ) & 0x7fff)), ((*r)%16) );
}

unsigned char pc3encode(unsigned char byte)
{
  unsigned short d;

     for (index=0;index<=(cle-1);index++)
     {
       stream(&r,&index,&a,b);
     }
   d=byte;
   byte=byte^(r&255);
   r=r+d;
   b[cle-1]=b[cle-1]+d;
   return(byte);
}

unsigned char pc3decode(unsigned char byte)
{
  unsigned short d;

     for (index=0;index<=(cle-1);index++)
     {
       stream(&r,&index,&a,b);
     }
   byte=byte^(r&255);
   d=byte;
   r=r+d;
   b[cle-1]=b[cle-1]+d;
   return(byte);
}


pc3init(unsigned int lngkey,unsigned char key[258])
{
   unsigned int z,y,x,i;
   unsigned char tab[258],plain;
   div_t reste;
   if (lngkey>256) lngkey=256;
   if (lngkey<1)
   {
     lngkey=1;
     strcpy(key,"a");
   }

   x=lngkey;

   for (i=0;i<x;i++)
   {
     tab[i]=key[i];
   }

   reste=div(lngkey,2);
   cle=reste.quot;
   if (reste.rem!=0) cle=cle+1;

   for (z=0;z<128;z++)
   {
    b[z]=0;
   }

   y=0;
   for (z=0;z<=(cle-1);z++)
   {
    if ( (z==(cle-1))&&(reste.rem!=0) )
     {
       b[z]=key[y]*256;
     }
    else
     {
       b[z]=(key[y]*256)+key[y+1];
       y=y+1;
     }
    y=y+1;
   }

   r=0;
   a=0x015a4e35;

     for (index=0;index<=(cle-1);index++)
     {
       for(z=0;z<=index;z++)
       {
       stream(&r,&index,&a,b);
       }
     }

   for (i=0;i<x;i++)
   {
       plain=pc3encode(tab[i]);
       tab[i]=tab[i]^plain;
   }
  i=i-1;
   for (z=1;z<=((x+1)*10);z++)
   {
       plain=pc3encode(tab[i]);
       tab[i]=tab[i]^plain;
       i=i+1;
       if (i>=x) i=0;
   }

   reste=div(lngkey,2);
   cle=reste.quot;
   if (reste.rem!=0) cle=cle+1;

   for (z=0;z<128;z++)
   {
    b[z]=0;
   }

   y=0;
   for (z=0;z<=(cle-1);z++)
   {
    if ( (z==(cle-1))&&(reste.rem!=0) )
     {
       b[z]=tab[y]*256;
     }
    else
     {
       b[z]=(tab[y]*256)+tab[y+1];
       y=y+1;
     }
    y=y+1;
   }

   for (z=0;z<x;z++)
   {
     key[z]=0;
     tab[z]=0;
   }

   r=0;
   a=0x015a4e35;

     for (index=0;index<=(cle-1);index++)
     {
       for(z=0;z<=index;z++)
       {
       stream(&r,&index,&a,b);
       }
     }
}

pc3saltinit(unsigned int lngkey,unsigned char key[258],unsigned int lngsalt,unsigned char salt[258])
{
   unsigned int z,y,x,i;
   unsigned char tab[516],plain;
   div_t reste;
   if (lngkey>256) lngkey=256;
   if (lngkey<1)
   {
     lngkey=1;
     strcpy(key,"a");
   }
   if (lngsalt>256) lngsalt=256;
   if (lngsalt<1)
   {
     lngsalt=1;
     strcpy(salt,"a");
   }

   x=lngkey;

   for (i=0;i<x;i++)
   {
     tab[i]=key[i];
   }

   for (i=x;i<(lngkey+lngsalt);i++)
   {
     tab[i]=salt[i-lngkey];
   }

   reste=div(lngkey,2);
   cle=reste.quot;
   if (reste.rem!=0) cle=cle+1;

   for (z=0;z<128;z++)
   {
    b[z]=0;
   }

   y=0;
   for (z=0;z<=(cle-1);z++)
   {
    if ( (z==(cle-1))&&(reste.rem!=0) )
     {
       b[z]=key[y]*256;
     }
    else
     {
       b[z]=(key[y]*256)+key[y+1];
       y=y+1;
     }
    y=y+1;
   }

   r=0;
   a=0x015a4e35;

     for (index=0;index<=(cle-1);index++)
     {
       for(z=0;z<=index;z++)
       {
       stream(&r,&index,&a,b);
       }
     }

   for (i=0;i<(lngkey+lngsalt);i++)
   {
       plain=pc3encode(tab[i]);
       tab[i]=tab[i]^plain;
   }
  i=i-1;
   for (z=1;z<=((lngkey+lngsalt+1)*10);z++)
   {
       plain=pc3encode(tab[i]);
       tab[i]=tab[i]^plain;
       i=i+1;
       if (i>=(lngkey+lngsalt)) i=0;
   }

   reste=div(lngkey,2);
   cle=reste.quot;
   if (reste.rem!=0) cle=cle+1;

   for (z=0;z<128;z++)
   {
    b[z]=0;
   }

   y=0;
   for (z=0;z<=(cle-1);z++)
   {
    if ( (z==(cle-1))&&(reste.rem!=0) )
     {
       b[z]=tab[y]*256;
     }
    else
     {
       b[z]=(tab[y]*256)+tab[y+1];
       y=y+1;
     }
    y=y+1;
   }

   for (z=0;z<x;z++)
   {
     key[z]=0;
   }
   for(z=0;z<(lngkey+lngsalt);z++)
   {
     tab[z]=0;
   }

   r=0;
   a=0x015a4e35;

     for (index=0;index<=(cle-1);index++)
     {
       for(z=0;z<=index;z++)
       {
       stream(&r,&index,&a,b);
       }
     }
}


main()
{
  unsigned int longueur,y;
  unsigned char code[21];
  FILE *in,*out;
  short c;

  strcpy(code,"abcdefghijklmnopqrst"); /* the password */
  longueur=20; /* length of the key up to 256 characters */

  /* init the key */

  pc3init(longueur,code);

  if ((in=fopen("input.bin","rb")) == NULL) {printf("\nError reading file INPUT.BIN !\n");exit(0);}
  if ((out=fopen("output.bin","wb")) == NULL) {printf("\nError writing file OUTPUT.BIN !\n");exit(0);}

  /* encrypt the file INPUT.BIN and write it to OUTPUT.BIN */
  while ( (c=fgetc(in)) !=EOF )
  {
   fputc(pc3encode(c),out);
  }

  fclose(in);
  fclose(out);

  if ((in=fopen("output.bin","rb")) == NULL) {printf("\nError reading file OUTPUT.BIN !\n");exit(0);}
  if ((out=fopen("plain.bin","wb")) == NULL) {printf("\nError writing file PLAIN.BIN !\n");exit(0);}

  /* init the key with the same parameters as the encryption key*/
  strcpy(code,"abcdefghijklmnopqrst");
  longueur=20; /* length of the key up to 256 characters */

  pc3init(longueur,code);

  /* decrypt the file OUTPUT.BIN and write it to PLAIN.BIN */

  while ( (c=fgetc(in)) !=EOF )
  {
   fputc(pc3decode(c),out);
  }

  fclose(in);
  fclose(out);

}


