Playfair Cipher
In cryptography, a Playfair cipher, also known as Playfair square, Wheatstone-Playfair cipher or Wheatstone cipher is a manual symmetric encryption technique and was the first literal digram substitution cipher. The scheme was invented in 1854 by Charles Wheatstone, but was named after Lord Playfair who promoted the use of the cipher.
In this scheme, pairs of letters are encrypted, instead of single letters as in the case of simple substitution cipher.
In playfair cipher, initially a key table is created. The key table is a 5×5 grid of alphabets that acts as the key for encrypting the plaintext. Each of the 25 alphabets must be unique and one letter of the alphabet (usually J) is omitted from the table as we need only 25 alphabets instead of 26. If the plaintext contains J, then it is replaced by I.
The sender and the receiver decide on a particular key, say 'Algorithm'. In a key table, the first characters (going left to right) in the table is the phrase, excluding the duplicate letters. The rest of the table will be filled with the remaining letters of the alphabet, in natural order. The key table works out to be -
A | L | G | O | R |
I | T | H | M | B |
C | D | E | F | K |
N | P | Q | S | U |
V | W | X | Y | Z |
Algorithm:
- First, a plaintext message is split into pairs of two letters (digraphs). If there is an odd number of letters, a Z is added to the last letter. Let us say we want to encrypt the message "Programming". It will be written as - Pr og ra mm in gZ
- The rules of encryption are -
- If both the letters are in the same column, take the letter below each one (going back to the top if at the bottom)
- If both letters are in the same row, take the letter to the right of each one (going back to the left if at the farthest right)
- If neither of the preceding two rules are true, form a rectangle with the two letters and take the letters on the horizontal opposite corner of the rectangle.
Using these rules, the result of the encryption of 'Programming' with the key of 'Algorithm' would be − UlroalkkcvhG
Decrypting the Playfair cipher is as simple as doing the same process in reverse. Receiver has the same key and can create the same key table, and then decrypt any messages made using that key.
Security:
It is also a substitution cipher and is difficult to break compared to the simple substitution cipher. As in case of substitution cipher, cryptanalysis is possible on the Playfair cipher as well, however it would be against 625 possible pairs of letters (25x25 alphabets) instead of 26 different possible alphabets.
The Playfair cipher was used mainly to protect important, yet non-critical secrets, as it is quick to use and requires no special equipment.
private static int Mod(int a, int b)
{
return (a % b + b) % b;
}
private static List<int> FindAllOccurrences(string str, char value)
{
List<int> indexes = new List<int>();
int index = 0;
while ((index = str.IndexOf(value, index)) != -1)
indexes.Add(index++);
return indexes;
}
private static string RemoveAllDuplicates(string str, List<int> indexes)
{
string retVal = str;
for (int i = indexes.Count - 1; i >= 1; i--)
retVal = retVal.Remove(indexes[i], 1);
return retVal;
}
private static char[,] GenerateKeySquare(string key)
{
char[,] keySquare = new char[5, 5];
string defaultKeySquare = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
string tempKey = string.IsNullOrEmpty(key) ? "CIPHER" : key.ToUpper();
tempKey = tempKey.Replace("J", "");
tempKey += defaultKeySquare;
for (int i = 0; i < 25; ++i)
{
List<int> indexes = FindAllOccurrences(tempKey, defaultKeySquare[i]);
tempKey = RemoveAllDuplicates(tempKey, indexes);
}
tempKey = tempKey.Substring(0, 25);
for (int i = 0; i < 25; ++i)
keySquare[(i / 5), (i % 5)] = tempKey[i];
return keySquare;
}
private static void GetPosition(ref char[,] keySquare, char ch, ref int row, ref int col)
{
if (ch == 'J')
GetPosition(ref keySquare, 'I', ref row, ref col);
for (int i = 0; i < 5; ++i)
for (int j = 0; j < 5; ++j)
if (keySquare[i, j] == ch)
{
row = i;
col = j;
}
}
private static char[] SameRow(ref char[,] keySquare, int row, int col1, int col2, int encipher)
{
return new char[] { keySquare[row, Mod((col1 + encipher), 5)], keySquare[row, Mod((col2 + encipher), 5)] };
}
private static char[] SameColumn(ref char[,] keySquare, int col, int row1, int row2, int encipher)
{
return new char[] { keySquare[Mod((row1 + encipher), 5), col], keySquare[Mod((row2 + encipher), 5), col] };
}
private static char[] SameRowColumn(ref char[,] keySquare, int row, int col, int encipher)
{
return new char[] { keySquare[Mod((row + encipher), 5), Mod((col + encipher), 5)], keySquare[Mod((row + encipher), 5), Mod((col + encipher), 5)] };
}
private static char[] DifferentRowColumn(ref char[,] keySquare, int row1, int col1, int row2, int col2)
{
return new char[] { keySquare[row1, col2], keySquare[row2, col1] };
}
private static string RemoveOtherChars(string input)
{
string output = input;
for (int i = 0; i < output.Length; ++i)
if (!char.IsLetter(output[i]))
output = output.Remove(i, 1);
return output;
}
private static string AdjustOutput(string input, string output)
{
StringBuilder retVal = new StringBuilder(output);
for (int i = 0; i < input.Length; ++i)
{
if (!char.IsLetter(input[i]))
retVal = retVal.Insert(i, input[i].ToString());
if (char.IsLower(input[i]))
retVal[i] = char.ToLower(retVal[i]);
}
return retVal.ToString();
}
private static string Cipher(string input, string key, bool encipher)
{
string retVal = string.Empty;
char[,] keySquare = GenerateKeySquare(key);
string tempInput = RemoveOtherChars(input);
int e = encipher ? 1 : -1;
if ((tempInput.Length % 2) != 0)
tempInput += "X";
for (int i = 0; i < tempInput.Length; i += 2)
{
int row1 = 0;
int col1 = 0;
int row2 = 0;
int col2 = 0;
GetPosition(ref keySquare, char.ToUpper(tempInput[i]), ref row1, ref col1);
GetPosition(ref keySquare, char.ToUpper(tempInput[i + 1]), ref row2, ref col2);
if (row1 == row2 && col1 == col2)
{
retVal += new string(SameRowColumn(ref keySquare, row1, col1, e));
}
else if (row1 == row2)
{
retVal += new string(SameRow(ref keySquare, row1, col1, col2, e));
}
else if(col1 == col2)
{
retVal += new string(SameColumn(ref keySquare, col1, row1, row2, e));
}
else
{
retVal += new string(DifferentRowColumn(ref keySquare, row1, col1, row2, col2));
}
}
retVal = AdjustOutput(input, retVal);
return retVal;
}
public static string Encipher(string input, string key)
{
return Cipher(input, key, true);
}
public static string Decipher(string input, string key)
{
return Cipher(input, key, false);
}
Example
string text = "Hello World";
string cipherText = Encipher(text, "cipher");
string plainText = Decipher(cipherText, "cipher");
Output
cipherText: "Ecttq Vvgmb"
plainText: "Hello World"