/* PKEP ( Pukall Key Exchange Protocol (c) Alexander PUKALL 1997 */
/* end at July 7, 1997 */
/* can be freely use */
/* but the name of the author must be included in the final software */
/* this algorithm allows to exchange securly a random password */
/* use the PC3 cipher for random number generation based on a 160-bit seed */

/* run the Phase 1 */
/* send the SEND.BIN file to your correspondent over the internet */
/* keep the LOCAL.BIN file secret on your harddisk */

/* your correspondent run Phase 1 too, and send you his SEND.BIN file */

/* you erase your own SEND.BIN file and replace it with the SEND.BIN file*/
/* of your correspondent */

/* your correspondent erase his own SEND.BIN file and replace it with your*/
/* SEND.BIN file */

/* Both run Phase 2*/
/* You will obtain a common random password, impossible to intercept over the*/
/* internet */

/* you can use this password with an other soft to exchange messages */

/* NOT FOR EXPORT */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <process.h>

unsigned long a1,b1[128],index;
unsigned int r1,cle;
typedef unsigned char u;
unsigned char expo2[64];
u m[1024],g[1024],e[1024],b[1024];
int n,v,d,z,S=65;


stream(unsigned int *r1,unsigned long *index,unsigned long *a1,unsigned long *b1)
{
  b1[*index] = ( b1[*index] * (*a1) ) + 1;
  *r1 = _rotl( (*r1 + (( b1[*index] >> 16 ) & 0x7fff)), ((*r1)%16) );
}

unsigned char pc3stream(unsigned char byte)
{
  unsigned short d;

     for (index=0;index<=(cle-1);index++)
     {
       stream(&r1,&index,&a1,b1);
     }
   d=byte;
   byte=byte^(r1&255);
   r1=r1+d;
   b1[cle-1]=b1[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++)
   {
    b1[z]=0;
   }

   y=0;
   for (z=0;z<=(cle-1);z++)
   {
    if ( (z==(cle-1))&&(reste.rem!=0) )
     {
       b1[z]=key[y]*256;
     }
    else
     {
       b1[z]=(key[y]*256)+key[y+1];
       y=y+1;
     }
    y=y+1;
   }

   r1=0;
   a1=0x015a4e35;

     for (index=0;index<=(cle-1);index++)
     {
       for(z=0;z<=index;z++)
       {
       stream(&r1,&index,&a1,b1);
       }
     }

   for (i=0;i<x;i++)
   {
       plain=pc3stream(tab[i]);
       tab[i]=tab[i]^plain;
   }
  i=i-1;
   for (z=1;z<=((x+1)*10);z++)
   {
       plain=pc3stream(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++)
   {
    b1[z]=0;
   }

   y=0;
   for (z=0;z<=(cle-1);z++)
   {
    if ( (z==(cle-1))&&(reste.rem!=0) )
     {
       b1[z]=tab[y]*256;
     }
    else
     {
       b1[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;
   }

   r1=0;
   a1=0x015a4e35;

     for (index=0;index<=(cle-1);index++)
     {
       for(z=0;z<=index;z++)
       {
       stream(&r1,&index,&a1,b1);
       }
     }
}

createkey(unsigned char shahash[20])
{
  unsigned int leng;
  int i;

  unsigned char code[20];
  unsigned char inite[64]={0x94,0x05,0xF4,0x50,0x81,0x79,0x38,0xAB,
  0x39,0x81,0x05,0x8C,0xCD,0xE8,0x04,0xDF,0x6E,0x7C,0xAB,0x07,
  0x63,0xFE,0x4A,0xD7,0x47,0x05,0x9D,0x2D,0x73,0xA9,0x38,0xBA,
  0xB5,0x48,0x39,0x10,0x0A,0xD8,0xD1,0x5A,0x9D,0x64,0x74,0xF8,
  0x8B,0xC5,0x3E,0x9A,0xBF,0x27,0x55,0x9C,0x0C,0x6A,0x7E,0xD8,
  0xA4,0x78,0x96,0x4C,0x96,0xBB,0x3A,0xC3};


  leng=20;

  for (i=0;i<20;i++)
  {
   code[i]=shahash[i];
  }

  pc3init(leng,code);

  for (i=1;i<S;i++)
  {
   e[i]=pc3stream(inite[i-1]);
   expo2[i-1]=e[i];
  }
}

a(u *x,u *y,int o)
{
 d=0;
 for(v=S;v--;)
 {
  d+=x[v]+y[v]*o;
  x[v]=d;
  d=d>>8;
  }
 }
 s(u *x)
 {
  for(v=0;(v<S-1)&&(x[v]==m[v]);)
  v++;
  if(x[v]>=m[v])a(x,m,-1);
 }
 r(u *x)
 {
  d=0;
  for(v=0;v<S;)
  {
   d|=x[v];
   x[v++]=d/2;
   d=(d&1)<<8;
   }
  }
  M(u *x,u *y)
  {
   u X[1024],Y[1024];
   bcopy(x,X,S);
   bcopy(y,Y,S);
   bzero(x,S);
   for(z=S*8;z--;)
   {
    if(X[S-1]&1)
    {
     a(x,Y,1);
     s(x);
    }
    r(X);
    a(Y,Y,1);
    s(Y);
    }
   }
    bzero(u *b,int S)
    {
      int i;
      for (i=0;i<S;i++)
      {
	b[i]=0;
      }
    }
    bcopy(u *x, u *X,int S)
    {
      int i;
      for (i=0;i<S;i++)
      {
	X[i]=x[i];
      }
    }

initdipuk(unsigned char shahash[20])

    {
      unsigned int pr;

	unsigned char prime512[64] = {
        0xF5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40,
        0x18, 0x11, 0x8D, 0x7C, 0x84, 0xA7, 0x0A, 0x72,
        0xD6, 0x86, 0xC4, 0x03, 0x19, 0xC8, 0x07, 0x29,
        0x7A, 0xCA, 0x95, 0x0C, 0xD9, 0x96, 0x9F, 0xAB,
        0xD0, 0x0A, 0x50, 0x9B, 0x02, 0x46, 0xD3, 0x08,
        0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C,
        0xBD, 0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB,
        0xA2, 0x5E, 0xC3, 0x55, 0xE9, 0x2A, 0x05, 0x5F
};

      bzero(g,S);
      bzero(e,S);
      bzero(m,S);
      g[64]=3;
      for (pr=1;pr<S;pr++)
      {
       m[pr]=prime512[pr-1];
      }

      createkey(shahash);

      bzero(b,S);
      b[S-1]=1;
      for(n=S*8;n--;)
      {
       if(e[S-1]&1)M(b,g);
       M(g,g);
       r(e);
      }
    }


dipukexp(unsigned char expo1[64], unsigned char expo2[64])

    {
      unsigned int pr;

	unsigned char prime512[64] = {
        0xF5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40,
        0x18, 0x11, 0x8D, 0x7C, 0x84, 0xA7, 0x0A, 0x72,
        0xD6, 0x86, 0xC4, 0x03, 0x19, 0xC8, 0x07, 0x29,
        0x7A, 0xCA, 0x95, 0x0C, 0xD9, 0x96, 0x9F, 0xAB,
        0xD0, 0x0A, 0x50, 0x9B, 0x02, 0x46, 0xD3, 0x08,
        0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C,
        0xBD, 0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB,
        0xA2, 0x5E, 0xC3, 0x55, 0xE9, 0x2A, 0x05, 0x5F
};

      bzero(g,S);
      bzero(e,S);
      bzero(m,S);
      for (pr=1;pr<S;pr++)
      {
       g[pr]=expo1[pr-1];
       e[pr]=expo2[pr-1];
       m[pr]=prime512[pr-1];
      }

      bzero(b,S);
      b[S-1]=1;
      for(n=S*8;n--;)
      {
       if(e[S-1]&1)M(b,g);
       M(g,g);
       r(e);
      }
    }


main()
{
  int count,i,cchh,choix;
  unsigned char codez[30],shahash[20],expo1[64],final[10];

FILE *in,*out;

codez[0]=21;

 printf("\nPKEP Pukall Key Exchange Protocol (c) Alexander PUKALL 1997\n\n");
 printf("1-Phase 1\n");
 printf("2-Phase 2\n");
 printf("3-Quit\n");
 printf("\n");
 printf("Votre choix:");

 choix=getch();

 for (cchh=0;cchh<1;cchh++)
 {
   cchh=cchh-1;
   if (choix==49) {printf("1\n");cchh=1;}
   if (choix==50) {printf("2\n");cchh=1;}
   if (choix==51) {printf("3\n");exit(0);}
   if (cchh!=1) {choix=getch();}
 }

if (choix==49)

{

 printf("\nEnter the random password ( 20 chars ):");
 cgets(codez);
 printf("\n");

 if (codez[1]!=20) {printf("\nThe password must have 20 characters !\n");exit(0);}

 for(i=0;i<(strlen(codez)-2);i++)
 {
  shahash[i]=codez[i+2];
 }


  initdipuk(shahash);


  if ((out=fopen("send.bin","wb")) == NULL) {printf("\nError writing file SEND.BIN !\n");exit(0);}


  for (count=1;count<S;count++)
  {
    fputc(b[count],out);
  }

fclose(out);

  if ((out=fopen("local.bin","wb")) == NULL) {printf("\nError reading file LOCAL.BIN !\n");exit(0);}

  for (count=0;count<S-1;count++)
  {
    fputc(expo2[count],out);
  }

fclose(out);

exit(0);

}

else

if (choix==50)

{

  if ((in=fopen("send.bin","rb")) == NULL) {printf("\nError reading file SEND.BIN !\n");exit(0);}

  for (count=0;count<S-1;count++)
  {
    expo1[count]=fgetc(in);
  }

  fclose(in);

  if ((in=fopen("local.bin","rb")) == NULL) {printf("\nError reading file LOCAL.BIN !\n");exit(0);}

  for (count=0;count<S-1;count++)
  {
    expo2[count]=fgetc(in);
  }

  fclose(in);

  dipukexp(expo1,expo2);

 for (i=0;i<=9;i++)
 {
   final[i]=0;
 }

 for (count=1;count<S;count++)
  {
    final[count%10]=final[count%10] ^ b[count];
  }

  printf("\n");
  printf("FINAL KEY TO USE: ");
  for (i=0;i<=9;i++)
  {
   printf("%c",(final[i]%59)+65);
  }

}

}
