*   USAGE:     pass a key made up of 8 16-bit numbers (word16) in an array
("word16 key[8];"), an input FILE * and an output temporary
FILE * to either encode_file() or decode_file().
where the key comes from is up to you.
then call swap_files_and_clean_up() with the original file's
name as the argument, to replace the original file
with the encoded data (stored in the temporary file).
 */
#include "idea.h"
static uint16 inv(uint16 x)
{
   uint16 t0,t1;
   uint16 q,y;
   if (x<=1)
      return x;
   t1=(uint16)(0x10001l/x);
   y=(uint16)(0x10001l%x);
   if (y==1)
return low16(1-t1);
   t0=1;
   do
   {
      q=x/y;
      x=x%y;
      t0+=q*t1;
      if (x==1)
return t0;
      q=y/x;
      y=y%x;
      t1+=q*t0;
   } while (y!=1);
   return low16(1-t1);
}
static void en_key_idea(word16 *userkey, word16 *Z)
{
   int i,j;
   /* shifts */
   for (j=0;j<8;j++)
      Z[j]=*userkey++;
   for (i=0;j<KEYLEN;j++)
   {
      i++;
      Z[i+7]=((Z[i&7] << 9) | (Z[i+1 & 7] >> 7));
      Z+=i&8;
      i&=7;
   }
}
static void de_key_idea(IDEAkey Z,IDEAkey DK)
{
   int j;
   uint16 t1,t2,t3;
   IDEAkey T;
   word16 *p=T+KEYLEN;
   t1=inv(*Z++);
   t2=-*Z++;
   t3=-*Z++;
   *--p=inv(*Z++);
   *--p=t3;
   *--p=t2;
   *--p=t1;
   for (j=1;j<ROUNDS;j++)
   {
      t1=*Z++;
      *--p=*Z++;
      *--p=t1;
      t1=inv(*Z++);
      t2=-*Z++;
      t3=-*Z++;
      *--p=inv(*Z++);
      *--p=t2;
      *--p=t3;
      *--p=t1;
   }
   t1=*Z++;
   *--p=*Z++;
   *--p=t1;
   t1=inv(*Z++);
   t2=-*Z++;
   t3=-*Z++;
   *--p=inv(*Z++);
   *--p=t3;
   *--p=t2;
   *--p=t1;
   /*copy and destroy temp copy*/
   for(j=0,p=T;j<KEYLEN;j++)
   {
      *DK++=*p;
      *p++=0;
   }
}
uint16 mul(uint16 a, uint16 b)
{
   word32 p;
   if (a)
   {
      if (b)
      {
 p=(word32)a*b;
 b=(uint16)(low16(p));
 a=(uint16)(p>>16);
 return b-a+(b<a);
      }
      else
      {
 return 1-a;
      }
   }
   else
      return 1-b;
}
#define MUL(x,y) (x=mul(low16(x),y))
#define CONST
static void cipher_idea(word16 in[4],word16 out[4],register CONST IDEAkey Z)
{
   register uint16 x1,x2,x3,x4,t1,t2;
   int r=ROUNDS;
   x1=*in++; x2=*in++;
   x3=*in++; x4=*in;
   do
   {
      MUL(x1,*Z++);
      x2+=*Z++;
      x3+=*Z++;
      MUL(x4,*Z++);
      t2=x1^x3;
      MUL(t2,*Z++);
      t1=t2+(x2^x4);
      MUL(t1,*Z++);
      t2=t1+t2;
      x1^=t1;
      x4^=t2;
      t2^=x2;
      x2=x3^t1;
      x3=t2;
   } while (--r);
   MUL(x1,*Z++);
   *out++=x1;
   *out++=(x3+*Z++);
   *out++=(x2+*Z++);
   MUL(x4,*Z);
   *out=x4;
}
char read_char_from_file(FILE *fp)
{
   char temp=0;
   if ((fread(&temp,sizeof(char),1,fp))!=1)
      end_of_file=1;
   return (temp);
}
word16 read_word16_from_file(FILE *fp)
{
   word16 temp=0;
   if ((fread(&temp,sizeof(word16),1,fp))!=1)
      end_of_file=1;
   return temp;
}
void write_char_to_file(char data,FILE *fp)
{
   if ((fwrite(&data,sizeof(char),1,fp))!=1)
   {
      printf("Fatal Error writing output file!!!\n");
      exit(-1);
   }
}
void write_word16_to_file(word16 data,FILE *fp)
{
   if ((fwrite(&data,sizeof(word16),1,fp))!=1)
   {
      printf("Fatal Error writing output file!!!\n");
      exit(-1);
   }
}
void cipher_file(FILE *in,FILE *out,word16 *key)
{
   word16 input[4],output[4];
   IDEAkey Z;
   int x,y;
   int count=0;
   long length;
   int temp;
   en_key_idea(key,Z);
   end_of_file=0;
   length=filelength(fileno(in));
   fwrite(&length,sizeof(long),1,out);
   while (!end_of_file)
   {
      x=0;
      while (x<4)
      {
 input[x]=((word16)(read_char_from_file(in)<<8));
 if (!end_of_file)
 {
    temp=read_char_from_file(in);
    if (temp<0) temp+=256;
    input[x]=input[x]|temp;
    x++;
 }
 if (end_of_file)
 {
    while (x<4) input[x++]=0;
    break;
 }
      }
cipher_idea(input,output,Z);
      for (y=0;y<x;y++)
      {
 if (noisy) if (count++%256==0) printf(".");
 write_word16_to_file(output[y],out);
      }
   }
}
void decipher_file(FILE *in,FILE *out,word16 *key)
{
   word16 input[4],output[4];
   int x,y;
   IDEAkey Z,DK;
   int count=0;
   long length=0;
   en_key_idea(key,Z);
   de_key_idea(Z,DK);
end_of_file=0;
fread(&length,sizeof(long),1,in);
   while (!end_of_file)
   {
      x=0;
      while (x<4)
      {
 input[x]=read_word16_from_file(in);
 if (end_of_file)
    break;
 x++;
      }
      cipher_idea(input,output,DK);
      for (y=0;y<x;y++)
      {
 if (noisy) if (count++%256==0) printf(".");
 if (length-->0)
    write_char_to_file(((char)(output[y]>>8)),out);
 if (length-->0)
    write_char_to_file(((char)(output[y]&255)),out);
      }
   }
}
void swap_files_and_clean_up(char *file)
{
   long fsize,count;
   FILE *fp;
   char temp[100];
   if (overwrite)
   {
      if ((fp=fopen(file,"r+b"))==NULL)
      {
 printf("\nError overwriting old file, security compromised.\n");
      }
      else
      {
 fseek(fp,0l,SEEK_END);
 fsize=ftell(fp);
 fseek(fp,0l,SEEK_SET);
 for (count=0;count<fsize;count++)
    fputc('0',fp);
 fclose(fp);
      }
      if ((remove(file))!=0)
      {
 printf("\nERROR removing old file <%s>\n",file);
 printf("encoded data remains in temporary file <%s>\n",tempfilename);
 exit(-1);
      }
   }
   else
   {
      strcpy(temp,file);
      file=strtok(temp,".");
      strcat(file,".enc");
   }
   if ((rename(tempfilename,file))!=0)
   {
      printf("\nERROR renaming temporary file <%s>!!\n",tempfilename);
      printf("Data is safely processed and stored in that file.\n");
      exit(-1);
   }
}
/*-----------------------------------------------*/
#define KBYTES 1024
void getuserkeyfromargv(word16 *key,char *arg)
{
   int x;
   for (x=0;x<strlen(arg) && x<8;x++)
   {
       if (x==0) key[x]=arg[x]<<8;
       else key[x]=((arg[x]<<8)|(key[x-1]>>8));
   }
if (strlen(arg)>8) printf ("\nONLY first *8* characters of key used!!!\n");
   if (x<8) while (x<8) key[x++]=0;
}
main(int argc, char **argv)
{
   word16 userkey[8];
   char filename[100];
   FILE *fp,*temp;
   int to_or_from;
   noisy=1;
   overwrite=0;
   if (argc!=4)
   {
      printf("\nUsage: idea filename.ext [e|d[w]] key\n");
      printf("          e=encode   d=decode   w=overwrite file\n");
      printf("       NOTE: Key must be no longer than 8 characters long!!!\n");
      exit(-1);
   }
   else
   {
      strncpy(filename,argv[1],99);
      filename[99]='\0';
      if (argv[2][0]=='e') to_or_from=1;
      else if (argv[2][0]=='d') to_or_from=0;
      else
      {
 printf("\nUsage: idea filename.ext [e|d[w]] key\n");
 printf("e=encrypt d=decrypt w=overwrite file\n");
 printf("       NOTE: Key must be no longer than 8 characters long!!!\n");
 exit(-1);
      }
      if (argv[2][1]=='w') overwrite=1;
      getuserkeyfromargv(userkey,argv[3]);
   }
   if ((fp=fopen(filename,"r+b"))==NULL)
   {
      printf("\nError opening File %s\n",filename);
      exit (-1);
   }
   if ((temp=fopen(tempfilename,"w+b"))==NULL)
   {
      printf("\nError opening temporary file\n");
      exit(-1);
   }
   if (to_or_from==1)
   {
      printf("\nEncoding file %s   ",filename);
      cipher_file(fp,temp,userkey);
   }
   else
   {
      printf("\nDecoding file %s   ",filename);
      decipher_file(fp,temp,userkey);
   }
   fclose (fp);
   fclose(temp);
swap_files_and_clean_up(filename);
   return 0;
}

 
											





 
	    

