Wednesday, August 10, 2016

Playfair Cipher with a Debugging challenge!


Note: This source code has an Error. If you want a completely correct code, you'll have to ask me in the comments. I was under the impression that repeated letters are replaced with padding character(say X), instead of being inserted, while coding this. Hence the code reflects this output. I never really got around to change the code and fix this so since you've got a starting hint to write code for this cipher, Take it as a fun exercise to correct that mistake. Your debugging skills are being tested! :D
I enlarged the page but the code was still spread out. You can click on any spot in the code and then use LEFT/RIGHT Arrow keys to see parts of the code that is not visible. Alternatively, you could also just tap once on the code and then scroll right with your finger if you are using a touchscreen device.
#include <iostream>
#include <string>
using namespace std;

class Playfair
{
 string keyword;
 string ukey; //unrepeated keyword
 string plain;
 string cipher;
 string generic="ABCDEFGHIKLMNOPQRSTUVWXYZ";
 char pftable[5][5]; // 5x5 matrix table
 public:
  void setKey(string keyword)
  {
   this->keyword = keyword;
   //Capitalize all characters and replace all j with i in keyword
   for(int i=0;i<(int)keyword.length();i++)
   {
       keyword[i]=toupper((char)keyword[i]);
       if(keyword[i]=='J'){keyword[i]='I';}
   }
   //find unrepeated characters in keyword
   int x=0,itrepeated=0;
   cout<<endl<<"Tracing the processes of playfair Cipher"<<endl;
   for(int i=0;i<(int)keyword.length();i++)
   {
    for(int j=0;j<i;j++)
    {
              if (keyword[i]==keyword[j])
              {
                  itrepeated++;
                  cout<<"Discard Repeated Character->";
              }
             }
             if (itrepeated==0)
             {
                 cout<<"Store Non-Repeated Character to ukey("<<x<<")-";
                 ukey+=keyword[i]; //Note to self: don't use ukey[x] index on this part since ukey is unallocated pointer
                 x++;
             }
             cout<<keyword[i]<<"--> obtained from keyword("<<i<<") "<<endl;
             itrepeated=0;
   }
   cout<<endl<<"Length of keyword("<<keyword<<") = "<<keyword.length()<<"; removing repetitions("<<ukey<<") = "<<ukey.length()<<endl;
   //Now its time to put this ukey in matrix form of 5x5
   //Inserting into matrix
            cout<<endl<<"Inserting unrepeated keyword into playfair table in matrix form 5x5::";
         //First inserting ukey[k]
         int a=-1,b=0;
         for(int i=0;i<(int)ukey.length();i++)
         {
             if(i%5==0){cout<<endl;b=0;a++;}
             pftable[a][b]=(char)ukey[i];
             cout<<pftable[a][b]<<"["<<a<<"]"<<"["<<b<<"]"<<" "; //JUST TRACING (Uncomment this line to see trace result)
             b++;
         }
         
         x=0;
         itrepeated=0;
   for(int i=0;i<(int)generic.length();i++)
   {
       for(int j=0;j<(int)ukey.length();j++)
       {
           if(generic[i]==(char)ukey[j])
           {
               itrepeated++;
               break;
           }
       }
       if(!itrepeated)
       {
           if(((int)ukey.length()+x)%5==0){cout<<endl;b=0;a++;}
           pftable[a][b]=(char)generic[i];
                 cout<<pftable[a][b]<<"["<<a<<"]"<<"["<<b<<"]"<<" ";// JUST TRACING (Uncomment this line to see trace result)
                 x++;
                 b++;
       }
             itrepeated=0;
   }
   
  
  //At this point, keyword is properly formatted into the 5x5 matrix
  }
  void setPlain(string plain)
  {
   this->plain = plain;
  }
  void setCipher(string cipher)
  {
   this->cipher = cipher;
  }
  int * MapThisLetter(char Char2m)
  {
   static int r[2];
   r[0]=0;
   r[1]=0;
   
      for(int i=0;i<5;i++){
          for(int j=0;j<5;j++){
            
              if(pftable[i][j]==Char2m){
                  cout<<pftable[i][j];
                  r[0]=i;
                  r[1]=j;
                  break;
                  }
          }
      }
  return r;
  }
  void encrypt()
  {
     int *position;
     bool flag=0;
     int indexx1;
     int indexy1;
     int indexx2;
     int indexy2;
     for(int i=0;i<(int)plain.length();i++)
   {
       plain[i]=toupper((char)plain[i]);
       if(plain[i]=='J'){plain[i]='I';}
   }
  cout<<endl<<endl<<"Now mapping each letter to its corresponding cipher character from the playfair table:"<<endl;
  for(int i=0;i<(int)plain.length();i++)
  {
      position=MapThisLetter(toupper((char)plain[i++]));
      indexx1=*(position);
      indexy1=*(position+1);
      cout<<"["<<indexx1<<","<<indexy1<<"] & ";
      if(((char)plain[i-1]==(char)plain[i]) || (i>=(int)plain.length() && (int)plain.length()%2!=0)){
              position=MapThisLetter('X');
               indexx2=*(position);
               indexy2=*(position+1);
               cout<<"["<<indexx2<<", "<<indexy2<<"]";
               flag=1;//Indicates (a letter has been replaced with X) OR (a position has been padded with X)
      }// breaks at last line if odd length plaintext is entered
      if(!flag){
          position=MapThisLetter(toupper((char)plain[i]));
          indexx2=*(position);
          indexy2=*(position+1);
          cout<<"["<<indexx2<<", "<<indexy2<<"]";
      }
      //at shis point we already have x1,y1 and x2,y2 available for two letters of plaintext at a time. 
      //now we apply certain conditional comparisions
      if(indexx1==indexx2){
      //if x1==x2 i.e. when horizontal match then right shift
      indexy1=(indexy1+1)%4;
      indexy2=(indexy2+1)%4;
      cout<<" maps to: "<< pftable[indexx1][indexy1]<<"["<<indexx1<<", "<<indexy1<<"] & "<< pftable[indexx2][indexy2]<<"["<<indexx2<<", "<<indexy2<<"] respectively"<<endl;
      }
      else if(indexy1==indexy2){
      //if y1==y2 i.e when vertical match then down shift
      indexx1=(indexx1+1)%4;
      indexx2=(indexx2+1)%4;
      cout<<" maps to: "<< pftable[indexx1][indexy1]<<"["<<indexx1<<", "<<indexy1<<"] & "<< pftable[indexx2][indexy2]<<"["<<indexx2<<", "<<indexy2<<"] respectively"<<endl;
      }
      else{
          //exchange x1 and x2 in boxes
          indexy1=indexy1+indexy2;
          indexy2=indexy1-indexy2;
          indexy1=indexy1-indexy2;
          cout<<" maps to: "<< pftable[indexx1][indexy1]<<"["<<indexx1<<", "<<indexy1<<"] & "<< pftable[indexx2][indexy2]<<"["<<indexx2<<", "<<indexy2<<"] respectively"<<endl;
          }
          cipher+=pftable[indexx1][indexy1];
          cipher+=pftable[indexx2][indexy2];
      if(flag){//this flag is TRUE IF (selected both string are same) or (odd End-of-line has been reached)
          if((char)plain[i-1]==(char)plain[i]){flag=0;}//reseting the flag to Not-END-of-Line IFF selected both letters are the same  
          if(flag){break;} //no resetting; break IF odd End-of-line is padded with character X at the last position
      }
  }
  
  }
  void decrypt()
  {
  int *position;
     bool flag=0;
     int indexx1;
     int indexy1;
     int indexx2;
     int indexy2;
  cout<<endl<<endl<<"Now mapping each letter to its corresponding cipher character from the playfair table:"<<endl;
  for(int i=0;i<(int)cipher.length();i++)
  {
      position=MapThisLetter(toupper((char)cipher[i++]));
      indexx1=*(position);
      indexy1=*(position+1);
      cout<<"["<<indexx1<<","<<indexy1<<"] & ";
      if(((char)cipher[i-1]==(char)cipher[i]) || (i>=(int)cipher.length() && (int)cipher.length()%2!=0)){
              position=MapThisLetter('X');
               indexx2=*(position);
               indexy2=*(position+1);
               cout<<"["<<indexx2<<", "<<indexy2<<"]";
               flag=1;//Indicates (a letter has been replaced with X) OR (a position has been padded with X)
      }// breaks at last line if odd length plaintext is entered
      if(!flag){
          position=MapThisLetter(toupper((char)cipher[i]));
          indexx2=*(position);
          indexy2=*(position+1);
          cout<<"["<<indexx2<<", "<<indexy2<<"]";
      }
      //at shis point we already have x1,y1 and x2,y2 available for two letters of plaintext at a time. 
      //now we apply certain conditional comparisions
      if(indexx1==indexx2){
      //if x1==x2 i.e. when horizontal match then LEFT shift
      indexy1=(indexy1-1)%4;
      indexy2=(indexy2-1)%4;
      cout<<" maps to: "<< pftable[indexx1][indexy1]<<"["<<indexx1<<", "<<indexy1<<"] & "<< pftable[indexx2][indexy2]<<"["<<indexx2<<", "<<indexy2<<"] respectively"<<endl;
      }
      else if(indexy1==indexy2){
      //if y1==y2 i.e when vertical match then UP shift
      indexx1=(indexx1-1)%4;
      indexx2=(indexx2-1)%4;
      cout<<" maps to: "<< pftable[indexx1][indexy1]<<"["<<indexx1<<", "<<indexy1<<"] & "<< pftable[indexx2][indexy2]<<"["<<indexx2<<", "<<indexy2<<"] respectively"<<endl;
      }
      else{
          //exchange x1 and x2 in boxes
          indexy1=indexy1+indexy2;
          indexy2=indexy1-indexy2;
          indexy1=indexy1-indexy2;
          cout<<" maps to: "<< pftable[indexx1][indexy1]<<"["<<indexx1<<", "<<indexy1<<"] & "<< pftable[indexx2][indexy2]<<"["<<indexx2<<", "<<indexy2<<"] respectively"<<endl;
          }
          plain+=pftable[indexx1][indexy1];
          plain+=pftable[indexx2][indexy2];
      if(flag){//this flag is TRUE IF (selected both string are same) or (odd End-of-line has been reached)
          if((char)cipher[i-1]==(char)cipher[i]){flag=0;}//reseting the flag to Not-END-of-Line IFF selected both letters are the same  
          if(flag){break;} //no resetting; break IF odd End-of-line is padded with character X at the last position
      }
  }
  
  }
 string getPlainText()
 {
  return plain;
 }
 string getCipherText()
 {
  return cipher;
 }
};

int main() 
{
 Playfair playfair;
 int choice=1;//just for testing first choice
 string plain,cipher,keyword,ukey;
 cout<<"Playfair:: Enter 1 for Encryption or, 2 for Decryption-";
 cin>>choice;
if(choice == 1)
 {
  /* encryption */
  cout<<"Enter keyword-";
  cin>>keyword;
  cout<<"Enter plain text-";
  cin>>plain;
  playfair.setKey(keyword);
  playfair.setPlain(plain);
  playfair.encrypt();
  cout<<endl<<"Finally, we have the Cipher text = "<<playfair.getCipherText()<<endl;
 }
 else if(choice == 2)
 {
  /* decryption */
  cout<<"Enter key-";
  cin>>keyword;
  cout<<"Enter cipher text-";
  cin>>cipher;
  playfair.setKey(keyword);
  playfair.setCipher(cipher);
     playfair.decrypt();
  cout<<endl<<"Finally, we have the Plain text = "<<playfair.getPlainText()<<endl;
 }
 return 0;
}

Try it yourself!
Note: I was under the impression that repeated letters are replaced with padding character(say X) while coding this. Hence the code reflects this output. I never really got around to change the code and fix this so please Take it as a fun exercise to correct that mistake. Your debugging skills are being tested! :D


Blogger Comments:


Emoticon Emoticon

Most read this week!