[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Sorry to put this all in the subject line but my german account heregoes nuts if i type below it. So anyway, here's my most updated version ofa program I've been working on. i'm getting the bugs of really weak encryptionand incorrect decryption and it'd be great if I could have some people whowhat they're doing look at it. The padding routine should be sound and theonly place I can think of the problem being is the Feistel network, but Ican't pinpoint it. It's structure is similar to GOST with Sboxes along thelines of Blowfish. The coding may not be the best in the world so if youhave questions or comments about it, send it to: zinthefe@hrzpub.tu-darmstadt.de If you want to send working code, it'dbe a good idea to send it to my acount in America to avoid any legalunpleasantness at zinthefe@ews.uiuc.edu This isn't the finished product, I plan to do all sorts ofcosmetic changes when i get the algorithm working right like turning theecho off, putting it on the command line, etc. But for the moment, I'd loveif if y'all could figure out why it's encrypting crappy and decryptingincorrectly. Thanks in advance




/*
author - Mark Zinthefer, zinthefe@uiuc.edu
title - olaf.C
c++
Symetric block encryption algorithm
64 bit block size
128 bit key (entered as 4 32-bit unsigned integers)
Feistel network

compiles with CC at a unix prompt

*/

#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>

struct olaf{
  unsigned Sbox[4][765],
    keys[48],
    left,
    right;
};

///left bitwise rotation by c bits///

unsigned ROTL32(unsigned, short);
unsigned ROTL32(unsigned x, short c){
  return (((x)<<(c))|((x)>>(32-(c))));                                
}

void menu();                                         //outputs menu
void gs_keys(olaf *);                                //get, set, check keys
void sc_Sbox(olaf *);                                //set, check Sboxes
void pad_file(fstream &, fstream &);                 //pads the _from_ file 
void unpad_file(fstream &, fstream &);               //removes padding
void olaf_encr(olaf *, unsigned *, unsigned *);      //encrypt
void olaf_decr(olaf *, unsigned *, unsigned *);      //decrypt 
unsigned to_unsign(char *, char *, char *, char *);  //turns 4 chars into 32 bit unsigned
unsigned F(olaf *, unsigned *, unsigned *);          //the round function


void menu(){
  cout<<"############################################"<<endl;
  cout<<"Enter 1 to encrypt, 2 to decrypt, 3 to exit."<<endl;
  cout<<"############################################"<<endl;
}

void gs_keys(olaf *o){
  unsigned                   //the keys. 32 bit unsigned ints.  
    key1, 
    key2, 
    key3, 
    key4;
  short shifter = 0;
  
  cout<<"Enter first key:"<<endl;       //prompt
  cin>>key1;
  cout<<"Enter second key:"<<endl;
  cin>>key2;
  cout<<"Enter third key:"<<endl;
  cin>>key3;
  cout<<"Enter fourth key:"<<endl;
  cin>>key4;
  

  // setting key array based on input keys
  
  for (char i = 0; i < 48; i+=6){
    o->keys[i] = ROTL32( key1, shifter) ^ key2;
    o->keys[i+1] = ROTL32( key1, shifter) ^ key3;
    o->keys[i+2] = ROTL32( key1, shifter) ^ key4;
    o->keys[i+3] = ROTL32( key2, shifter) ^ key3;
    o->keys[i+4] = ROTL32( key2, shifter) ^ key4;
    o->keys[i+5] = ROTL32( key3, shifter) ^ key4;
    shifter++;
  }
  
  //checking and fixing redundant key array entries
  
  for (short j = 0; j < 48; j++){
    char flag = 1;
    while (flag > 0)
      for (char k = 0; k < 48; k++){
	if ((o->keys[j])==(o->keys[k]))
	  flag++;
	if (flag > 2){
	  (o->keys[j])=
	    ((key1^key2^key3^key4)+1+(o->keys[j]))%4294967291;
	  k=0;
	  flag=1;
	}
	else if(k==47 && flag==2)
	  flag = 0;
      }
  }
  
}

void sc_Sbox(olaf *o){
  unsigned 
    set1 = o->keys[0],   //the seeds of the sboxes are the first 4 entries of
    set2 = o->keys[1],   //the keys array. 
    set3 = o->keys[2], 
    set4 = o->keys[3];
  
  /*
    The S-boxes are completely key dependent. They are generated 
    in the followong loop. Like with the keys, i'm going to make 
    them more math sound later.
  */
  
  for (short y = 0; y < 256; y++)
    for (short x = 0; x < 4; x++){
      o->Sbox[x][y] = (set1 & set2) | (set3 & set4);
      set1 = set2;
      set2 = set3;
      set3 = set4;
      set4 = (o->Sbox[x][y] + set4) % 4294967296; 
    }
  
  cout<<"Fixing s-boxes..."<<endl;
  ///fixing Sboxes///
  /*
    Here I check to see if there are any duplicate entries in any of
    the S-boxes. After the loops are done, all entries should be unique
    You don't have to bother with a close look at this as
    long as you agree that the S-boxes will be the same for encr and decr
    so long as the key is the same. 
  */
  
  for (char i = 0; i < 4; i++)
    for (short j = 0; j < 256; j++){
      char flag = 1;
      while (flag > 0)
	for (char k = 0; k < 4; k++)
	  for (short l = 0; l < 256; l++){
	    if (o->Sbox[i][j]==o->Sbox[k][l])
	      flag++;
	    if (flag > 2){
	      o->Sbox[i][j]=
		((o->keys[0]^
		  o->keys[1]^
		  o->keys[2]^
		  o->keys[3])
		 +1
		 +o->Sbox[i][j])
		%4294967291;
	      k=l=0;
	      flag=1;
	    }
	    else if(k==3 && l==255 && flag==2)
	      flag = 0;
	  }
    }
  cout<<"s-boxes set."<<endl;
}

//Any suggestions???
void pad_file(fstream &to, fstream &from){
  
}
void unpad_file(fstream &to, fstream &from){
  
}


void olaf_encr(olaf *o, unsigned *XL, unsigned *XR){
  
  // similar to GOST's gostcrypt(...)
  // for 48 rounds, do the Feistel network swapping sides rather than names,
  // use keys[] 0 to 47

  for (char i = 0; i < 48; i+=2){
    *XL ^= F(o, XR, &(o->keys[i])); *XR ^= F(o, XL, &(o->keys[i+1]));
  }
  
  // set the olaf struct's values left and right to XL and XR

  o->left = *XL;
  o->right = *XR;
}

void olaf_decr(olaf *o, unsigned *XL, unsigned *XR){

  // basicaly the same as the encr function but with key order reversed
  // and left and right sides flipped

  for (char i = 47; i > 0; i-=2){
    *XR ^= F(o, XL, &(o->keys[i])); *XL ^= F(o, XR, &(o->keys[i-1]));
  }
  o->left = *XL;
  o->right = *XR;
}

unsigned to_unsign(char *a, char *b, char *c, char *d){
  unsigned num =  (*a + (*b)*256 + (*c)*65536 + (*d)*16777216);	
  return num;
}

unsigned F(olaf *o, unsigned *x, unsigned *k){
  
  //almost a clone of Schneier's Blowfish function
  
  short a, b, c, d;
  
  d = *x & 255;
  *x >>= 8;
  c = *x & 255;
  *x >>= 8;
  b = *x & 255;
  *x >>= 8;
  a = *x & 255;
  
  // x = ((Sbox[0][a+b+c]*Sbox[1][a+c+d]%4294967391) ^ Sbox[2][a+b+d]) + Sbox[3][b+c+d];
  *x = (o->Sbox[0][a+b+c] * o->Sbox[1][a+c+d]) % 4294967291;
  *x ^= o->Sbox[2][a+b+d];
  *x += o->Sbox[3][b+c+d];

  *x^=*k;

  *x = ROTL32(*x, 11);
  
  return *x;
}


main(){

  olaf o;
  short choice = 0;
  char 
    block[8],   //block 
    fn[20],     //file name
    ch,         //generic char value for use throughout program
    IV[8];      //IV
  fstream from;
  fstream to;
  
  do{
    menu();
   
    cin>>choice;
    
    if(choice == 1 || choice == 2){
      
      gs_keys(&o);
     
      cout<<"Enter 8 character pass:"<<endl;
      cin>>IV;
      cout<<"Enter file to be processed:"<<endl;
      cin>>fn;
      cout<<"Please wait..."<<endl;
      
      sc_Sbox(&o); 
    }

    
    switch(choice){
  
    case 1:{
      
      ///open files///
      
      to.open( "dead.letter", ios::out); from.open( fn, ios::in);
      
      if(!from)  {cout<<"file not there."<<endl;break;}
      
      ///get file length///
  
      from.seekg(0 , ios::end);
      long length = from.tellg();
      from.seekg(0);
           
      char padd = (8 - length%8);
      
      for (char pad = 0; pad < padd; pad++)
	to.put(padd);
      
      ///padding file///
            
      for (int put = 0; put < length; put++){
	ch = from.get();
	to.put(ch);
      }
      
      from.close();
      to.close();
      
      from.open("dead.letter", ios::in);
      to.open(fn, ios::out);
      
      for (int bloc = 0; bloc < length + padd ; bloc += 8){
	
	//reads 8 chars and fills the block register with them
	
	for(char i = 0; i < 8; i++)
	  block[i]=from.get();
	
	//commented out to make it ECB for the time being
	//   for(char q = 0; q < 8; q++)
	// 	block[q]^=IV[q];
	
	unsigned 
	  xl=to_unsign(&block[0], &block[1], &block[2], &block[3]),
	  xr=to_unsign(&block[4], &block[5], &block[6], &block[7]);
	
	olaf_encr(&o,
		  &xl,  //left side
		  &xr); //right side
	
	//makes the block come from olaf struct//
	block[0] = o.left % 256;
	block[1] = (o.left / 256) % 256;
	block[2] = (o.left / 65536) % 256;
	block[3] = o.left / 16777216;
	block[4] = o.right % 256;
	block[5] = (o.right/ 256) % 256;
	block[6] = (o.right/ 65536) % 256;
	block[7] = o.right / 16777216;
	
	//commented out CBC loop
	//    for (char n = 0; n < 8; n++)
	// 	IV[n]=block[n];
	
	//putting the block into target file
	for (char m = 0; m < 8; m++)
	  to.put(block[m]);
      }
      
      //after the file is encrypted close files
      from.close();
      to.close();
      
      // here i clear the contents of dead.letter
      
      // to.open( "dead.letter", ios::out);
      // to.close();
      break; 
      
    }
    
    case 2:{
      to.open( "dead.letter", ios::out);from.open( fn, ios::in);
      
      if(!from)
	{cout<<"file not there."<<endl; break;}
      
      ///get file length///
      from.seekg(0 , ios::end);
      long length = from.tellg();
      from.seekg(0);
      
      char nextIV[8];
      
      for (int bloc = 0; bloc < length ; bloc += 8){
	for(char i = 0; i < 8; i++)
	  block[i]=from.get();
	//commented out to make it ECB
	//  for (char n = 0; n < 8; n++)
	// 	nextIV[n]=block[n];
	
	unsigned 
	  xl=to_unsign(&block[0], &block[1], &block[2], &block[3]),
	  xr=to_unsign(&block[4], &block[5], &block[6], &block[7]);
	
	olaf_decr(&o,
		  &xl,  //left side
		  &xr); //right side
	
	//make this come from olaf struct//
	block[0] = o.left % 256;
	block[1] = (o.left / 256) % 256;
	block[2] = (o.left / 65536) % 256;
	block[3] = o.left / 16777216;
	block[4] = o.right % 256;
	block[5] = (o.right/ 256) % 256;
	block[6] = (o.right/ 65536) % 256;
	block[7] = o.right / 16777216;
	
	// old IV loops
	//   for(char q = 0; q < 8; q++)
	//    	block[q]^=IV[q];
	//    for (char r = 0; r < 8; r++)
	// 	IV[r]=nextIV[r];
	for (char m = 0; m < 8; m++)
	  to.put(block[m]);
	
      }
      from.close();
      to.close();
      
      //The decrypted file is unpadded here by reading the first char
      //and replacing the origional file with the decryption in dead.letter
      
      from.open("dead.letter", ios::in);
      to.open(fn, ios::out);
           
      char depadd = from.get();
      
      from.seekg(depadd);
      
      for (int putback = 0; putback < length-depadd; putback++){
	ch = from.get();
	to.put(ch);
      }
      from.close();
      to.close();
      // to.open( "dead.letter", ios::out);
      //  to.close();
      break;
    }
    
    case 3:{
      for (char i = 0; i < 35; i++)
	cout<<endl;
      cout<<"Program terminated"<<endl<<endl;
      return 0;
    }
    default:
      cout<<"Invalid option."<<endl;
      break;
    }
  }
  while(choice!=3); 
}