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.



									/*****Please include following header files*****/
// vector
// string
// ctype.h
// stdlib.h
/***********************************************/

/*****Please use following namespaces*****/
// std
/*****************************************/

static int Mod(int a, int b)
{
	return (a % b + b) % b;
}

static char** Create2DArray(int rowCount, int colCount) {
	char** arr = new char*[rowCount];

	for (int i = 0; i < rowCount; ++i)
		arr[i] = new char[colCount];

	return arr;
}

static string ToUpper(string str) {
	string output = str;
	int strLen = str.size();

	for (int i = 0; i < strLen; ++i)
		output[i] = toupper(output[i]);

	return output;
}

static string RemoveChar(string str, char ch) {
	string output = str;

	for (int i = 0; i < output.size(); ++i)
		if (output[i] == ch)
			output = output.erase(i, 1);

	return output;
}

static vector<int> FindAllOccurrences(string str, char value)
{
	vector<int> indexes;

	int index = 0;
	while ((index = str.find(value, index)) != -1)
		indexes.push_back(index++);

	return indexes;
}

static string RemoveAllDuplicates(string str, vector<int> indexes)
{
	string retVal = str;

	for (int i = indexes.size() - 1; i >= 1; i--)
		retVal = retVal.erase(indexes[i], 1);

	return retVal;
}

static char** GenerateKeySquare(string key)
{
	char** keySquare = Create2DArray(5, 5);
	string defaultKeySquare = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
	string tempKey = key.empty() ? "CIPHER" : ToUpper(key);

	tempKey = RemoveChar(tempKey, 'J');
	tempKey += defaultKeySquare;

	for (int i = 0; i < 25; ++i)
	{
		vector<int> indexes = FindAllOccurrences(tempKey, defaultKeySquare[i]);
		tempKey = RemoveAllDuplicates(tempKey, indexes);
	}

	tempKey = tempKey.substr(0, 25);

	for (int i = 0; i < 25; ++i)
		keySquare[(i / 5)][(i % 5)] = tempKey[i];

	return keySquare;
}

static void GetPosition(char** keySquare, char ch, int* row, int* col)
{
	if (ch == 'J')
		GetPosition(keySquare, 'I', row, col);

	for (int i = 0; i < 5; ++i)
		for (int j = 0; j < 5; ++j)
			if (keySquare[i][j] == ch)
			{
				*row = i;
				*col = j;
				return;
			}
}

static char* SameRow(char** keySquare, int row, int col1, int col2, int encipher)
{
	return new char[2] { keySquare[row][Mod((col1 + encipher), 5)], keySquare[row][Mod((col2 + encipher), 5)] };
}

static char* SameColumn(char** keySquare, int col, int row1, int row2, int encipher)
{
	return new char[2] { keySquare[Mod((row1 + encipher), 5)][col], keySquare[Mod((row2 + encipher), 5)][col] };
}

static char* SameRowColumn(char** keySquare, int row, int col, int encipher)
{
	return new char[2] { keySquare[Mod((row + encipher), 5)][Mod((col + encipher), 5)], keySquare[Mod((row + encipher), 5)][Mod((col + encipher), 5)] };
}

static char* DifferentRowColumn(char** keySquare, int row1, int col1, int row2, int col2)
{
	return new char[2] { keySquare[row1][col2], keySquare[row2][col1] };
}

static string RemoveOtherChars(string input)
{
	string output = input;
	int strLen = input.size();

	for (int i = 0; i < strLen; ++i)
		if (!isalpha(output[i]))
			output = output.erase(i, 1);

	return output;
}

static string AdjustOutput(string input, string output)
{
	string retVal = output;
	int strLen = input.size();

	for (int i = 0; i < strLen; ++i)
	{
		if (!isalpha(input[i]))
			retVal = retVal.insert(i, 1, input[i]);

		if (islower(input[i]))
			retVal[i] = tolower(retVal[i]);
	}

	return retVal;
}

static string Cipher(string input, string key, bool encipher)
{
	string retVal = "";
	char** keySquare = GenerateKeySquare(key);
	string tempInput = RemoveOtherChars(input);
	int e = encipher ? 1 : -1;
	int tempInputLen = tempInput.size();

	if ((tempInputLen % 2) != 0)
		tempInput += "X";

	for (int i = 0; i < tempInputLen; i += 2)
	{
		int row1 = 0;
		int col1 = 0;
		int row2 = 0;
		int col2 = 0;

		GetPosition(keySquare, toupper(tempInput[i]), &row1, &col1);
		GetPosition(keySquare, toupper(tempInput[i + 1]), &row2, &col2);

		if (row1 == row2 && col1 == col2)
		{
			retVal += string(SameRowColumn(keySquare, row1, col1, e), 2);
		}
		else if (row1 == row2)
		{
			retVal += string(SameRow(keySquare, row1, col1, col2, e), 2);
		}
		else if (col1 == col2)
		{
			retVal += string(SameColumn(keySquare, col1, row1, row2, e), 2);
		}
		else
		{
			retVal += string(DifferentRowColumn(keySquare, row1, col1, row2, col2), 2);
		}
	}

	retVal = AdjustOutput(input, retVal);

	return retVal;
}

static string Encipher(string input, string key)
{
	return Cipher(input, key, true);
}

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"