/* DESCRYPT by Greg Toth  7/27/90
** This program encrypts a text file using the Data Encryption Standard as
** described in Federal Information Processing Standards (FIPS) 46-1 and
** 81 and the book Digital Communications Fundamentals and Applications
** by Bernard Sklar, Prentice Hall, New Jersey, 1988. Four implementations
** of DES are in this program, Electronic Code Book (ECB), Cipher Block
** Chaining (CBC), Cipher Feedback (CFB), and Output Feedback (OFB).
**
** The program is run from the command line like this:
** descrypt inputfile outputfile mode implementation
** inputfile is the file you want to encrypt or decrypt
** outputfile is the file you want contain the encrtypted or decrypted file
** mode is either E for encrypt or D for decrypt
** implementation is ECB, CBC, CFB, or OFB
**
** The source code is not well commented because if you really want to
** understand it you need the FIPS publications or the Sklar book.
** To obtain the FIPS stuff call 800-336-4700 and order them for $15 each
** FIPS 46-1 is the basic description and FIPS 81 is a description of the
** implementations. The Sklar book just covers the stuff in FIPS 46-1 and
** has several errors in it so watch out if you use it, the errors are:
** line 9 of table 12.3 should be 0 10 0 9 14 6 3 15 5 1 13 12 7 11 4 2 8
** line 24 should be 3 4 3 2 12 9 5 15 10 11 14 1 7 6 0 8 12
** Of the 4 implementations CFB and OFB are probably the most secure but
** all 4 should be fairly secure (unless your enimies have access to a Cray)
*/

#include <stdio.h>
#include <ctype.h>
#define HiBit 0x80

typedef char BYTE;

main(argc,argv)
int argc;
char *argv[];
{
FILE *fin;
FILE *fout;

int inkey[8];
BYTE chKey;
BYTE Key[8];
BYTE P1Key[7];
BYTE K[16][7];

char mode[3];
char Funct=*argv[3];

int i,x,j,k,y;
for(i=0;i<3;i++)
 {
 mode[i]=*argv[4];
 argv[4]++;
 }

if(Funct=='d')
 Funct='D';
if(Funct=='e')
 Funct='E';

if((Funct!='E')&(Funct!='D'))
 {
 printf("Function error: should be either E or D");
 exit(1);
 }

printf("\nEnter 8 numbers between 0 and 128 for the key\n");
 for (i=0;i<8;i++)
  {
  printf("Enter the %dth number in the key:",i);
  scanf("%d",&inkey[i]);
  if(inkey[i]>128)
   {
   printf("Error: Key numbers should be between 0 and 128");
   exit(1);
   }
  Key[i]=0;
  chKey=0;
  for(j=0;j<128;j++)
   {
   if(inkey[i]==j)
     Key[i]=chKey;
   chKey++;
   }
  }
 printf("The key is %d %d %d %d %d %d %d %d.\n",Key[0],Key[1],Key[2],Key[3],
 Key[4],Key[5],Key[6],Key[7]);

MakeKey(Key,K);

if((fin=fopen(argv[1],"rb"))==NULL)
{
fprintf(stderr,"Error opening source file\n");
exit(1);
}
if((fout=fopen(argv[2],"wb"))==NULL)
{
fprintf(stderr,"Error opening destination file\n");
exit(1);
}

for(i=0;i<3;i++)
 {
 if(islower(mode[i]))
  {
  fprintf(stderr,"Error: Mode must be uppercase\n");
  exit(1);
  }
 }

if((mode[0]=='E')&(mode[1]=='C')&(mode[2]=='B'))
 ECB(fin,fout,K,Funct);
if((mode[0]=='C')&(mode[1]=='B')&(mode[2]=='C'))
 CBC(fin,fout,K,Funct);
if((mode[0]=='C')&(mode[1]=='F')&(mode[2]=='B'))
 CFB(fin,fout,K,Funct);
if((mode[0]=='O')&(mode[1]=='F')&(mode[2]=='B'))
 OFB(fin,fout,K,Funct);

fclose(fout);
fclose(fin);
printf("\n");

/* End of Main
*/
}

OFB(fin,fout,K,Funct)
FILE *fin;
FILE *fout;
BYTE K[16][7];
char Funct;
{
char Funct1;
BYTE PlnTxt;
BYTE NewTxt[8];
BYTE OldTxt[8];
int invec[8];
BYTE chvec,test;
int i,x,j,k,y,BlkCnt,done,isdone;

printf("\nEnter 8 numbers between 0 and 128 for the initialization vector\n");
 for (i=0;i<8;i++)
  {
  printf("Enter the %dth number in the initialization vector:",i);
  scanf("%d",&invec[i]);
  if(invec[i]>128)
   {
   printf("Error: Vector numbers should be between 0 and 128");
   exit(1);
   }
  NewTxt[i]=0;
  chvec=0;
  for(j=0;j<128;j++)
   {
   if(invec[i]==j)
     NewTxt[i]=chvec;
   chvec++;
   }
  }
 printf("The initialization vector is %d %d %d %d %d %d %d %d.\n",
       NewTxt[0],NewTxt[1],NewTxt[2],NewTxt[3],
       NewTxt[4],NewTxt[5],NewTxt[6],NewTxt[7]);

BlkCnt=0;
while(done!=1)
 {
 PlnTxt=0;
 if(Funct=='E')
  {
  if((PlnTxt=getc(fin))==EOF)
    isdone=1;
   else
    isdone=0;
  printf("\nEncrypting Byte %d",BlkCnt);
  BlkCnt++;
  for(i=0;i<8;i++)
   {
   OldTxt[i]=NewTxt[i];
   }
  crypt(NewTxt,K,Funct);
  PlnTxt=PlnTxt^NewTxt[0];
  putc(PlnTxt,fout);
  NewTxt[7]=NewTxt[0];
  for(i=0;i<7;i++)
   NewTxt[i]=OldTxt[i+1];
  done=isdone;
  }
 if(Funct=='D')
  {
  Funct1='E';
  PlnTxt=getc(fin);
  printf("\nDecrypting Byte %d",BlkCnt);
  BlkCnt++;
  for(i=0;i<8;i++)
   {
   OldTxt[i]=NewTxt[i]; 
   }
  crypt(NewTxt,K,Funct1);
  NewTxt[7]=NewTxt[0];
  PlnTxt=PlnTxt^NewTxt[0];
  if(PlnTxt==EOF)
    isdone=1;
  else
   {
   isdone=0;
   putc(PlnTxt,fout);
   for(i=0;i<7;i++)
    NewTxt[i]=OldTxt[i+1];
   }
  done=isdone;
  }
 }
fclose(fout);

/* End of OFB */
}

CFB(fin,fout,K,Funct)
FILE *fin;
FILE *fout;
BYTE K[16][7];
char Funct;
{
char Funct1;
BYTE PlnTxt;
BYTE NewTxt[8];
BYTE OldTxt[8];
int invec[8];
BYTE chvec,test;
int i,x,j,k,y,BlkCnt,done,isdone;

printf("\nEnter 8 numbers between 0 and 128 for the initialization vector\n");
 for (i=0;i<8;i++)
  {
  printf("Enter the %dth number in the initialization vector:",i);
  scanf("%d",&invec[i]);
  if(invec[i]>128)
   {
   printf("Error: Vector numbers should be between 0 and 128");
   exit(1);
   }
  NewTxt[i]=0;
  chvec=0;
  for(j=0;j<128;j++)
   {
   if(invec[i]==j)
     NewTxt[i]=chvec;
   chvec++;
   }
  }
 printf("The initialization vector is %d %d %d %d %d %d %d %d.\n",
       NewTxt[0],NewTxt[1],NewTxt[2],NewTxt[3],
       NewTxt[4],NewTxt[5],NewTxt[6],NewTxt[7]);

BlkCnt=0;
while(done!=1)
 {
 PlnTxt=0;
 if(Funct=='E')
  {
  if((PlnTxt=getc(fin))==EOF)
    isdone=1;
   else
    isdone=0;
  printf("\nEncrypting Byte %d",BlkCnt);
  BlkCnt++;
  for(i=0;i<8;i++)
   {
   OldTxt[i]=NewTxt[i];
   }
  crypt(NewTxt,K,Funct);
  PlnTxt=PlnTxt^NewTxt[0];
  putc(PlnTxt,fout);
  for(i=0;i<7;i++)
   NewTxt[i]=OldTxt[i+1];
  NewTxt[7]=PlnTxt;
  done=isdone;
  }
 if(Funct=='D')
  {
  Funct1='E';
  PlnTxt=getc(fin);
  printf("\nDecrypting Byte %d",BlkCnt);
  BlkCnt++;
  for(i=0;i<8;i++)
   {
   OldTxt[i]=NewTxt[i]; 
   }
  crypt(NewTxt,K,Funct1);
  NewTxt[7]=PlnTxt;
  PlnTxt=PlnTxt^NewTxt[0];
  if(PlnTxt==EOF)
    isdone=1;
  else
   {
   isdone=0;
   putc(PlnTxt,fout);
   for(i=0;i<7;i++)
    NewTxt[i]=OldTxt[i+1];
   }
  done=isdone;
  }
 }
fclose(fout);

/* End of CFB */
}

ECB(fin,fout,K,Funct)
FILE *fin;
FILE *fout;
BYTE K[16][7];
char Funct;
{
BYTE PlnTxt[8];
int i,x,j,k,y,BlkCnt;
int done,isdone;

BlkCnt=0;
while(done!=1)
 {
 i=0;
 for(i=0;i<8;i++)
  PlnTxt[i]=0;
 if(Funct=='E')
  {
  for(i=0;i<8;i++)
   {
   if((PlnTxt[i]=getc(fin))==EOF)
    isdone=1;
   else
    isdone=0;
   }
  printf("\nEncrypting Block %d",BlkCnt);
  BlkCnt++;
  crypt(PlnTxt,K,Funct);
  for(i=0;i<8;i++)
   {
   putc(PlnTxt[i],fout);
   }
  done=isdone;
  }
 if(Funct=='D')
  {
  for(i=0;i<8;i++)
   {
   PlnTxt[i]=getc(fin);
   }
  printf("\nDecrypting Block %d",BlkCnt);
  BlkCnt++; 
  crypt(PlnTxt,K,Funct);
  for(i=0;i<8;i++)
   {
   if(PlnTxt[i]==EOF)
    isdone=1;
   else
    {
    isdone=0;
    putc(PlnTxt[i],fout);
    }
   }
  done=isdone;
  }
 }

/* End of ECB */
}

CBC(fin,fout,K,Funct)
FILE *fin;
FILE *fout;
BYTE K[16][7];
char Funct;
{
BYTE PlnTxt[8];
BYTE NewTxt[8];
BYTE OldTxt[8];
int invec[8];
BYTE chvec;
int i,x,j,k,y,BlkCnt,done,isdone;

printf("\nEnter 8 numbers between 0 and 128 for the initialization vector\n");
 for (i=0;i<8;i++)
  {
  printf("Enter the %dth number in the initialization vector:",i);
  scanf("%d",&invec[i]);
  if(invec[i]>128)
   {
   printf("Error: Vector numbers should be between 0 and 128");
   exit(1);
   }
  NewTxt[i]=0;
  chvec=0;
  for(j=0;j<128;j++)
   {
   if(invec[i]==j)
     NewTxt[i]=chvec;
   chvec++;
   }
  }
 printf("The initialization vector is %d %d %d %d %d %d %d %d.\n",
       NewTxt[0],NewTxt[1],NewTxt[2],NewTxt[3],
       NewTxt[4],NewTxt[5],NewTxt[6],NewTxt[7]);

BlkCnt=0;
while(done!=1)
 {
 i=0;
 for(i=0;i<8;i++)
  PlnTxt[i]=0;
 if(Funct=='E')
  {
  for(i=0;i<8;i++)
   {
   if((PlnTxt[i]=getc(fin))==EOF)
    isdone=1;
   else
    isdone=0;
   PlnTxt[i]=PlnTxt[i]^NewTxt[i];
   }
  printf("\nEncrypting Block %d",BlkCnt);
  BlkCnt++;
  crypt(PlnTxt,K,Funct);
  for(i=0;i<8;i++)
   {
   putc(PlnTxt[i],fout);
   NewTxt[i]=PlnTxt[i];
   }
  done=isdone;
  }
 if(Funct=='D')
  {
  for(i=0;i<8;i++)
   {
   PlnTxt[i]=getc(fin);
   OldTxt[i]=PlnTxt[i];
   }
  printf("\nDecrypting Block %d",BlkCnt);
  BlkCnt++; 
  crypt(PlnTxt,K,Funct);
  for(i=0;i<8;i++)
   {
   PlnTxt[i]=PlnTxt[i]^NewTxt[i];
   if(PlnTxt[i]==EOF)
    isdone=1;
   else
    {
    isdone=0;
    putc(PlnTxt[i],fout);
    NewTxt[i]=OldTxt[i];
    }
   }
  done=isdone;
  }
 }
fclose(fout);


/* End of CBC */
}



MakeKey(Key,K)
BYTE Key[8];
BYTE K[16][7];
{
BYTE P1Key[7];
int i,x,y,k,j;

static int PC1W[56] =
{1,2,3,7,7,6,5,1,2,3,7,7,6,5,1,2,3,7,7,6,5,1,2,3,7,7,6,5,
1,2,3,4,6,5,4,1,2,3,4,6,5,4,1,2,3,4,6,5,4,1,2,3,4,6,5,4};

static BYTE PC1B[64] = { 0x01,0x01,0x01,0x01,0x10,0x10,0x10,0x02,
                         0x02,0x02,0x02,0x20,0x20,0x20,0x04,0x04,
                         0x04,0x04,0x40,0x40,0x40,0x08,0x08,0x08,
                         0x08,0x80,0x80,0x80,0x10,0x10,0x10,0x10,
                         0x01,0x01,0x01,0x20,0x20,0x20,0x20,0x02,
                         0x02,0x02,0x40,0x40,0x40,0x40,0x04,0x04,
                         0x04,0x80,0x80,0x80,0x80,0x08,0x08,0x08,
                         0x80,0x80,0x80,0x80,0x08,0x08,0x08,0x08};

for (i=0;i<16;i++)
 {
 for (j=0;j<7;j++)
  K[i][j]=0;
 }
/* Remove Bits 8,16,32,40,48,56,64 from the key then permute per
** table 12.6 i.e. bit 57 is now bit 1, bit 49 now bit 2 ....
*/

for (i=0;i<8;i++)
 Key[i]=Key[i]<<=1;
for (i=0;i<7;i++)
 P1Key[i]=0x00;
x=0;
for(i=0;i<8;i++)
 {
 for(j=0;j<7;j++)
  {
  if((Key[i]&HiBit)!=0)
   P1Key[(PC1W[x]-1)]=P1Key[(PC1W[x]-1)] + PC1B[x];
  Key[i]<<=1;
  x++;
  }
 }

/*To create the 16 subkeys leftshift P1Key the number of times specified
**in table 12.7 the permute the results
*/

for(k=0;k<16;k++)
{
 if((k!=0)&(k!=1)&(k!=8)&(k!=15))
 {
  lshift28(P1Key);
  lshift28(P1Key);
 }
 else
  {
  lshift28(P1Key);
  }
 for(i=0;i<7;i++)
  K[k][i]=P1Key[i];
 permute(K,k);
}
}

crypt(PlnTxt,K,Funct)
BYTE PlnTxt[8];
BYTE K[16][7];
char Funct;
{
int i,x,j,k,y;
BYTE RLO[8];
BYTE RLO2[8];


static int IPW[64]={4,0,5,1,6,2,7,3,4,0,5,1,6,2,7,3,4,0,5,1,6,2,7,3,
4,0,5,1,6,2,7,3,4,0,5,1,6,2,7,3,4,0,5,1,6,2,7,3,4,0,5,1,6,2,7,3,
4,0,5,1,6,2,7,3};

static BYTE IPB[64] = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
                      0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,
                      0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
                      0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
                      0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
                      0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
                      0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
                      0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80};


static int FPW[64] = {7,6,5,4,3,2,1,0,7,6,5,4,3,2,1,0,7,6,5,4,3,2,1,0,
                      7,6,5,4,3,2,1,0,7,6,5,4,3,2,1,0,7,6,5,4,3,2,1,0,
                      7,6,5,4,3,2,1,0,7,6,5,4,3,2,1,0};

static BYTE FPB[64]= {0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
                      0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
                      0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,
                      0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
                      0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
                      0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
                      0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
                      0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02};

/* Permute the 8 byte block of plain text (64 bits) per table
** 12.1 i.e. bit 58 now bit 1, bit 50 now 2 etc.
*/

for(i=0;i<8;i++)
 RLO[i]=0;
x=0;
for(i=0;i<8;i++)
 {
 for(j=0;j<8;j++)
  {
  if((PlnTxt[i]&HiBit)!=0)
   RLO[IPW[x]]=RLO[IPW[x]]+IPB[x];
  PlnTxt[i]<<=1;
  x++;
  }
 }

/* Feed RLO and the appropriate subkey into the Standard Block
*/
if(Funct=='E')
{
 for(y=0;y<16;y++)
  SBB(RLO,K,y);
 }
if(Funct=='D')
 {
 for(y=16;y>0;y--)
  SBB1(RLO,K,(y-1));
 }

x=0;
for(i=0;i<8;i++)
 RLO2[i]=0;
for(i=0;i<8;i++)
 {
 for(j=0;j<8;j++)
  {
  if((RLO[i]&HiBit)!=0)
   RLO2[FPW[x]]=RLO2[FPW[x]]+FPB[x];
  RLO[i]<<=1;
  x++;
  }
 }
for(i=0;i<8;i++)
 PlnTxt[i]=RLO2[i];
/*End of Crypt */
}

showbyte(a)
BYTE a;
{
int j;
printf(" ");
for(j=1;j<9;j++,a<<=1)
 {
 if((a&HiBit)!=0)
  putchar('1');
 else
  putchar('0');
 }
}

lshift28(a)
BYTE a[7];
{
int i,j;
BYTE x[9];
for(i=0;i<9;i++)
 x[i]=0;
for(i=0;i<3;i++)
 {
 if((a[i]&HiBit)!=0)
  x[i]=0x01;
 a[i]<<=1;
 }
a[0]=a[0]+x[1];
a[1]=a[1]+x[2];
x[8]=a[3];
x[8]=x[8]&0xF0;
x[7]=a[3]&0x0F;
x[8]<<=1;
if((a[3]&HiBit)!=0)
 a[2]=a[2]+0x01;
if(x[0]!=0)
 x[8]=x[8]+0x10;
for(i=4;i<7;i++)
 {
 if((a[i]&HiBit)!=0)
  x[i]=0x01;
 a[i]<<=1;
 }
a[4]=a[4]+x[5];
a[5]=a[5]+x[6];
if((a[3]&0x08)!=0)
 a[6]=a[6]+0x01;
x[7]<<=1;
x[7]=x[7]+x[4];
x[7]=x[7]&0x0F;
a[3]=x[7]+x[8];
}

permute(a,k)
BYTE a[16][7];
int k;
{
BYTE K[7];
static int  PC2W[56] = {0,2,0,1,0,1,2,2,6,1,0,1,2,0,1,2,0,6,
                        1,2,1,6,1,0,6,2,2,0,5,3,3,5,4,5,6,5,
                        3,6,4,3,3,5,6,4,4,5,3,4,4,5,4,3,5,6,3,4};

static BYTE PC2B[56] = {8,1,2,1,4,64,16,64,
                        0,16,32,2,2,128,128,32,
                        64,0,4,4,32,0,8,16,
                        0,128,8,1,2,2,32,1,
                        32,128,0,4,16,0,2,1,
                        128,16,0,8,64,32,8,16,
                        4,8,128,64,64,0,4,1};
int i,j,x;
for(i=0;i<7;i++)
 K[i]=0;
x=0;
for(i=0;i<7;i++)
 {
 for(j=0;j<8;j++)
  {
  if((a[k][i]&HiBit)!=0)
   K[PC2W[x]]=K[PC2W[x]]+PC2B[x];
  a[k][i]<<=1;
  x++;
  }
 }
for(i=0;i<7;i++)
 a[k][i]=K[i];

}

SBB(RL,a,k)
BYTE RL[8];
BYTE a[16][7];
int k;
{
BYTE LN[4];
BYTE RN[4];
BYTE LN1[4];
BYTE EXP[8];
BYTE EXP1[8];
BYTE EXP2[4];
BYTE Row;
int i,j,x;

static int EW[64] = {0,5,0,6,0,6,0,0,0,0,1,6,1,6,1,1,
                     1,1,1,6,1,6,2,2,2,2,2,6,2,6,2,3,
                     2,3,3,7,3,7,3,3,3,3,4,7,4,7,4,4,
                     4,4,4,7,4,7,5,5,5,5,5,7,5,7,5,0};

static BYTE EB[64] = {
 0x40,0x01,0x20,0x80,0x10,0x40,0x08,0x02,0x04,0x01,0x80,0x20,0x40,0x10,0x20,
 0x08,
 0x10,0x04,0x02,0x08,0x01,0x04,0x80,0x20,0x40,0x10,0x08,0x02,0x04,0x01,0x02,
 0x80,
 0x01,0x40,0x20,0x80,0x10,0x40,0x08,0x02,0x04,0x01,0x80,0x20,0x40,0x10,0x20,
 0x08,
 0x10,0x04,0x02,0x80,0x01,0x04,0x80,0x20,0x40,0x10,0x08,0x02,0x04,0x01,0x02,
 0x80};

static BYTE SBW0[128] = {
14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,
15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,
10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,
7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,
2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,
12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,
4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,
13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7};

static BYTE SBW1[128] = {
0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,
3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,
13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,
13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,
14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,
10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,
1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2};

static BYTE SBW2[128] = {
4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,
0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,
13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,
10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,
4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,
9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,
1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,
7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8};

static BYTE SBW3[128] = {
15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13,
13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9,
1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12,
3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14,
11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3,
4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13,
6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12,
2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11};

static int PW[32] = {1,2,2,3,1,3,0,2,2,1,3,0,3,2,1,0,
                     0,1,3,0,0,3,1,2,3,1,2,0,0,3,1,2};

static BYTE PB[32] = {0x80,0x80,0x02,0x02,0x08,0x10,0x40,0x40,
                      0x01,0x01,0x04,0x04,0x40,0x10,0x40,0x80,
                      0x01,0x04,0x80,0x20,0x10,0x08,0x20,0x20,
                      0x01,0x10,0x04,0x02,0x08,0x20,0x02,0x08};

for(i=0;i<4;i++)
 LN[i]=RL[i];
for(i=4;i<8;i++)
 RN[i-4]=RL[i];
for(i=0;i<4;i++)
 LN1[i]=RN[i];
for(i=0;i<8;i++)
 EXP[i]=0;
x=0;
for(i=0;i<4;i++)
 {
 for(j=0;j<8;j++)
  {
  if((RN[i]&HiBit)!=0)
   EXP[EW[x]]=EXP[EW[x]]+EB[x];
  x++;
  if((RN[i]&HiBit)!=0)
   EXP[EW[x]]=EXP[EW[x]]+EB[x];
  x++;
  RN[i]<<=1;
  }
 }
for(i=0;i<6;i++)
 EXP[i]=EXP[i]^a[k][i];
EXP[6]=0;
EXP[7]=0;
SixToEight(EXP);

for(i=0;i<8;i++)
 EXP1[i]=0;

for(i=0;i<8;i++)
 {
 Row=EXP[i];
 Row=Row&0x21;
 EXP[i]=EXP[i]&0x1F;
 EXP[i]=EXP[i]>>=1;
 if(Row==0x00)
  EXP1[i]=SBW0[EXP[i]+(i*16)];
 if(Row==0x01)
  EXP1[i]=SBW1[EXP[i]+(i*16)];
 if(Row==0x20)
  EXP1[i]=SBW2[EXP[i]+(i*16)];
 if(Row==0x21)
  EXP1[i]=SBW3[EXP[i]+(i*16)];
 }

EXP1[0]<<=4;
EXP1[2]<<=4;
EXP1[4]<<=4;
EXP1[6]<<=4;

EXP[0]=EXP1[0]+EXP1[1];
EXP[1]=EXP1[2]+EXP1[3];
EXP[2]=EXP1[4]+EXP1[5];
EXP[3]=EXP1[6]+EXP1[7];

x=0;
for(i=0;i<4;i++)
 EXP2[i]=0;
for(i=0;i<4;i++)
 {
 for(j=0;j<8;j++)
  {
  if((EXP[i]&HiBit)!=0)
   EXP2[PW[x]]=EXP2[PW[x]]+PB[x];
  EXP[i]<<=1;
  x++;
  }
 }
for(i=0;i<4;i++)
 EXP2[i]=EXP2[i]^LN[i];
for(i=0;i<4;i++)
 RL[i]=LN1[i];
for(i=4;i<8;i++)
 RL[i]=EXP2[(i-4)];

}

SixToEight(EXP1)
BYTE EXP1[8];
{
BYTE EXP2[8];
int i;
EXP2[0]=EXP1[0];

EXP2[0]=EXP2[0]>>=2;
EXP2[1]=EXP1[0]<<=4;
EXP2[1]=EXP2[1]&0x30;
EXP2[3]=EXP1[1];
EXP2[2]=EXP2[3]&0xF0;
EXP2[2]=EXP2[2]>>=4;
EXP2[1]=EXP2[1]+EXP2[2];

EXP2[2]=EXP1[1]<<=2;
EXP2[2]=EXP2[2]&0x3C;
EXP2[3]=EXP1[2];
EXP2[3]=EXP2[3]>>=6;
EXP2[3]=EXP2[3]&0x03;
EXP2[2]=EXP2[2]+EXP2[3];
EXP2[2]=EXP2[2]&0x3F;

EXP2[3]=EXP1[2]&0x3F;
EXP2[4]=EXP1[3];
EXP2[4]=EXP2[4]>>=2;

EXP2[5]=EXP1[3];
EXP2[5]=EXP2[5]<<=4;
EXP2[5]=EXP2[5]&0x30;
EXP2[6]=EXP1[4];
EXP2[6]=EXP2[6]&0xF0;
EXP2[6]=EXP2[6]>>=4;
EXP2[5]=EXP2[5]+EXP2[6];

EXP2[6]=EXP1[4]<<=2;
EXP2[6]=EXP2[6]&0x3C;
EXP2[7]=EXP1[5];
EXP2[7]=EXP2[7]>>=6;
EXP2[7]=EXP2[7]&0x03;
EXP2[6]=EXP2[6]+EXP2[7];

EXP2[7]=EXP1[5]&0x3F;

for(i=0;i<8;i++)
 EXP2[i]=EXP2[i]&0x3F;
for(i=0;i<8;i++)
 EXP1[i]=EXP2[i];
}


SBB1(RL,a,k)
BYTE RL[8];
BYTE a[16][7];
int k;
{
BYTE LN[4];
BYTE RN[4];
BYTE RN1[4];
BYTE EXP[8];
BYTE EXP1[8];
BYTE EXP2[4];
BYTE Row;
int i,j,x;

static int EW[64] = {0,5,0,6,0,6,0,0,0,0,1,6,1,6,1,1,
                     1,1,1,6,1,6,2,2,2,2,2,6,2,6,2,3,
                     2,3,3,7,3,7,3,3,3,3,4,7,4,7,4,4,
                     4,4,4,7,4,7,5,5,5,5,5,7,5,7,5,0};

static BYTE EB[64] = {
 0x40,0x01,0x20,0x80,0x10,0x40,0x08,0x02,0x04,0x01,0x80,0x20,0x40,0x10,0x20,
 0x08,
 0x10,0x04,0x02,0x08,0x01,0x04,0x80,0x20,0x40,0x10,0x08,0x02,0x04,0x01,0x02,
 0x80,
 0x01,0x40,0x20,0x80,0x10,0x40,0x08,0x02,0x04,0x01,0x80,0x20,0x40,0x10,0x20,
 0x08,
 0x10,0x04,0x02,0x80,0x01,0x04,0x80,0x20,0x40,0x10,0x08,0x02,0x04,0x01,0x02,
 0x80};

static BYTE SBW0[128] = {
14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,
15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,
10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,
7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,
2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,
12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,
4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,
13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7};

static BYTE SBW1[128] = {
0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,
3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,
13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,
13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,
14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,
10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,
13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,
1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2};

static BYTE SBW2[128] = {
4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,
0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,
13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,
10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,
4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,
9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,
1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,
7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8};

static BYTE SBW3[128] = {
15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13,
13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9,
1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12,
3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14,
11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3,
4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13,
6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12,
2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11};

static int PW[32] = {1,2,2,3,1,3,0,2,2,1,3,0,3,2,1,0,
                     0,1,3,0,0,3,1,2,3,1,2,0,0,3,1,2};

static BYTE PB[32] = {0x80,0x80,0x02,0x02,0x08,0x10,0x40,0x40,
                      0x01,0x01,0x04,0x04,0x40,0x10,0x40,0x80,
                      0x01,0x04,0x80,0x20,0x10,0x08,0x20,0x20,
                      0x01,0x10,0x04,0x02,0x08,0x20,0x02,0x08};

for(i=0;i<4;i++)
 LN[i]=RL[i];
for(i=4;i<8;i++)
 RN[i-4]=RL[i];
for(i=0;i<4;i++)
 RN1[i]=LN[i];
for(i=0;i<8;i++)
 EXP[i]=0;
x=0;
for(i=0;i<4;i++)
 {
 for(j=0;j<8;j++)
  {
  if((LN[i]&HiBit)!=0)
   EXP[EW[x]]=EXP[EW[x]]+EB[x];
  x++;
  if((LN[i]&HiBit)!=0)
   EXP[EW[x]]=EXP[EW[x]]+EB[x];
  x++;
  LN[i]<<=1;
  }
 }
for(i=0;i<6;i++)
 EXP[i]=EXP[i]^a[k][i];

SixToEight(EXP);

for(i=0;i<8;i++)
 EXP1[i]=0;

for(i=0;i<8;i++)
 {
 Row=EXP[i];
 Row=Row&0x21;
 EXP[i]=EXP[i]&0x1F;
 EXP[i]=EXP[i]>>=1;
 if(Row==0x00)
  EXP1[i]=SBW0[EXP[i]+(i*16)];
 if(Row==0x01)
  EXP1[i]=SBW1[EXP[i]+(i*16)];
 if(Row==0x20)
  EXP1[i]=SBW2[EXP[i]+(i*16)];
 if(Row==0x21)
  EXP1[i]=SBW3[EXP[i]+(i*16)];
 }

EXP1[0]<<=4;
EXP1[2]<<=4;
EXP1[4]<<=4;
EXP1[6]<<=4;

EXP[0]=EXP1[0]+EXP1[1];
EXP[1]=EXP1[2]+EXP1[3];
EXP[2]=EXP1[4]+EXP1[5];
EXP[3]=EXP1[6]+EXP1[7];

x=0;
for(i=0;i<4;i++)
 EXP2[i]=0;
for(i=0;i<4;i++)
 {
 for(j=0;j<8;j++)
  {
  if((EXP[i]&HiBit)!=0)
   EXP2[PW[x]]=EXP2[PW[x]]+PB[x];
  EXP[i]<<=1;
  x++;
  }
 }
for(i=0;i<4;i++)
 EXP2[i]=EXP2[i]^RN[i];
for(i=4;i<8;i++)
 RL[i]=RN1[i-4];
for(i=0;i<4;i++)
 RL[i]=EXP2[i];

}

