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*****/
// string.h
// ctype.h
// stdlib.h
/***********************************************/

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

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;
}

char* ToUpper(char* str) {
	int strLen = strlen(str);
	char* output = (char*)malloc(strLen + 1);

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

	output[strLen] = '\0';
	return output;
}

char* GetSubString(char* str, int index, int count) {
	int strLen = strlen(str);
	int lastIndex = index + count;

	if (index >= 0 && lastIndex > strLen) return "";

	char* subStr = (char*)malloc(count + 1);

	for (int i = 0; i < count; i++) {
		subStr[i] = str[index + i];
	}

	subStr[count] = '\0';

	return subStr;
}

char* AppendString(const char* str1, const char* str2) {
	int str1Len = strlen(str1);
	int str2Len = strlen(str2);
	int strLen = str1Len + str2Len + 1;
	char* str = (char*)malloc(strLen);

	for (int i = 0; i < str1Len; i++)
		str[i] = str1[i];

	for (int i = 0; i < str2Len; i++)
		str[(str1Len + i)] = str2[i];

	str[strLen - 1] = '\0';

	return str;
}

char* RemoveString(char* str, int index, int count) {
	int strLen = strlen(str);
	int lastIndex = index + count;

	char* s = GetSubString(str, 0, index);
	s = AppendString(s, GetSubString(str, lastIndex, strLen - lastIndex));

	return s;
}

char* InsertString(char* str, int index, char* subStr) {
	char* s = GetSubString(str, 0, index);
	s = AppendString(s, subStr);
	s = AppendString(s, GetSubString(str, index, strlen(str) - index));

	return s;
}

char* RemoveChar(char* str, char ch) {
	char* output = str;

	for (int i = 0; i < strlen(output); ++i)
		if (output[i] == ch)
			output = RemoveString(output, i, 1);

	return output;
}

int* AddItemInArray(int* arr, int count, int item) {
	int* newArr = (int*)malloc(sizeof(int) * (count + 1));

	for (int i = 0; i < count; ++i) {
		newArr[i] = arr[i];
	}

	newArr[count] = item;

	return newArr;
}

int* FindAllOccurrences(char* str, char value, int* count)
{
	int* indexes = (int*)malloc(sizeof(int));
	char *tmp = str;
	*count = 0;

	tmp = strchr(tmp, value);
	while (tmp != NULL) {
		indexes = AddItemInArray(indexes, *count, (tmp - str));
		++(*count);
		tmp = strchr(tmp + 1, value);
	}

	return indexes;
}

char* RemoveAllDuplicates(char* str, int* indexes, int count)
{
	char* retVal = str;

	for (int i = count - 1; i >= 1; i--)
		retVal = RemoveString(retVal, indexes[i], 1);

	return retVal;
}

char** GenerateKeySquare(char* key)
{
	char** keySquare = Create2DArray(5, 5);
	char* defaultKeySquare = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
	char* tempKey = (strlen(key) <= 0) ? "CIPHER" : ToUpper(key);

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

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

	tempKey = GetSubString(tempKey, 0, 25);

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

	return keySquare;
}

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;
			}
}

char* SameRow(char** keySquare, int row, int col1, int col2, int encipher)
{
	char* output = (char*)malloc(3);
	output[0] = keySquare[row][Mod((col1 + encipher), 5)];
	output[1] = keySquare[row][Mod((col2 + encipher), 5)];
	output[2] = '\0';
	return output;
}

char* SameColumn(char** keySquare, int col, int row1, int row2, int encipher)
{
	char* output = (char*)malloc(3);
	output[0] = keySquare[Mod((row1 + encipher), 5)][col];
	output[1] = keySquare[Mod((row2 + encipher), 5)][col];
	output[2] = '\0';
	return output;
}

char* SameRowColumn(char** keySquare, int row, int col, int encipher)
{
	char* output = (char*)malloc(3);
	output[0] = keySquare[Mod((row + encipher), 5)][Mod((col + encipher), 5)];
	output[1] = keySquare[Mod((row + encipher), 5)][Mod((col + encipher), 5)];
	output[2] = '\0';
	return output;
}

char* DifferentRowColumn(char** keySquare, int row1, int col1, int row2, int col2)
{
	char* output = (char*)malloc(3);
	output[0] = keySquare[row1][col2];
	output[1] = keySquare[row2][col1];
	output[2] = '\0';
	return output;
}

char* RemoveOtherChars(char* input)
{
	char* output = input;
	int strLen = strlen(input);

	for (int i = 0; i < strLen; ++i)
		if (output[i] != '\0' && !isalpha(output[i]))
			output = RemoveString(output, i, 1);

	return output;
}

char* AdjustOutput(char* input, char* output)
{
	char* retVal = output;
	int strLen = strlen(input);

	for (int i = 0; i < strLen; ++i)
	{
		if (!isalpha(input[i])) {
			char s[2] = { input[i], '\0' };
			retVal = InsertString(retVal, i, s);
		}

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

	return retVal;
}

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

	if ((tempInputLen % 2) != 0)
		tempInput = AppendString(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 = AppendString(retVal, SameRowColumn(keySquare, row1, col1, e));
		}
		else if (row1 == row2)
		{
			char* a = SameRow(keySquare, row1, col1, col2, e);
			retVal = AppendString(retVal, a);
		}
		else if (col1 == col2)
		{
			retVal = AppendString(retVal, SameColumn(keySquare, col1, row1, row2, e));
		}
		else
		{
			retVal = AppendString(retVal, DifferentRowColumn(keySquare, row1, col1, row2, col2));
		}
	}

	retVal = AdjustOutput(input, retVal);

	return retVal;
}

char* Encipher(char* input, char* key)
{
	return Cipher(input, key, true);
}

char* Decipher(char* input, char* key)
{
	return Cipher(input, key, false);
}
								


Example

									char* text = "Hello World";
char* cipherText = Encipher(text, "cipher");
char* plainText = Decipher(cipherText, "cipher");
								


Output

									cipherText:	"Ecttq Vvgmb"
plainText:	"Hello World"