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 Shared Function [Mod](a As Integer, b As Integer) As Integer
	Return (a Mod b + b) Mod b
End Function

Private Shared Function FindAllOccurrences(str As String, value As Char) As List(Of Integer)
	Dim indexes As New List(Of Integer)()

	Dim index As Integer = 0
	While index <> -1
		index = str.IndexOf(value, index)
		If index <> -1 Then
			indexes.Add(index)
			index += 1
		End If
	End While

	Return indexes
End Function

Private Shared Function RemoveAllDuplicates(str As String, indexes As List(Of Integer)) As String
	Dim retVal As String = str

	For i As Integer = indexes.Count - 1 To 1 Step -1
		retVal = retVal.Remove(indexes(i), 1)
	Next

	Return retVal
End Function

Private Shared Function GenerateKeySquare(key As String) As Char(,)
	Dim keySquare As Char(,) = New Char(4, 4) {}
	Dim defaultKeySquare As String = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
	Dim tempKey As String = If(String.IsNullOrEmpty(key), "CIPHER", key.ToUpper())

	tempKey = tempKey.Replace("J", "")
	tempKey += defaultKeySquare

	For i As Integer = 0 To 24
		Dim indexes As List(Of Integer) = FindAllOccurrences(tempKey, defaultKeySquare(i))
		tempKey = RemoveAllDuplicates(tempKey, indexes)
	Next

	tempKey = tempKey.Substring(0, 25)

	For i As Integer = 0 To 24
		keySquare((i \ 5), (i Mod 5)) = tempKey(i)
	Next

	Return keySquare
End Function

Private Shared Sub GetPosition(ByRef keySquare As Char(,), ch As Char, ByRef row As Integer, ByRef col As Integer)
	If ch = "J"c Then
		GetPosition(keySquare, "I"c, row, col)
	End If

	For i As Integer = 0 To 4
		For j As Integer = 0 To 4
			If keySquare(i, j) = ch Then
				row = i
				col = j
			End If
		Next
	Next
End Sub

Private Shared Function SameRow(ByRef keySquare As Char(,), row As Integer, col1 As Integer, col2 As Integer, encipher As Integer) As Char()
	Return New Char() {keySquare(row, [Mod]((col1 + encipher), 5)), keySquare(row, [Mod]((col2 + encipher), 5))}
End Function

Private Shared Function SameColumn(ByRef keySquare As Char(,), col As Integer, row1 As Integer, row2 As Integer, encipher As Integer) As Char()
	Return New Char() {keySquare([Mod]((row1 + encipher), 5), col), keySquare([Mod]((row2 + encipher), 5), col)}
End Function

Private Shared Function SameRowColumn(ByRef keySquare As Char(,), row As Integer, col As Integer, encipher As Integer) As Char()
	Return New Char() {keySquare([Mod]((row + encipher), 5), [Mod]((col + encipher), 5)), keySquare([Mod]((row + encipher), 5), [Mod]((col + encipher), 5))}
End Function

Private Shared Function DifferentRowColumn(ByRef keySquare As Char(,), row1 As Integer, col1 As Integer, row2 As Integer, col2 As Integer) As Char()
	Return New Char() {keySquare(row1, col2), keySquare(row2, col1)}
End Function

Private Shared Function RemoveOtherChars(input As String) As String
	Dim output As String = input

	Dim i As Integer = 0
	While i < output.Length
		If Not Char.IsLetter(output(i)) Then
			output = output.Remove(i, 1)
		End If
		i += 1
	End While

	Return output
End Function

Private Shared Function AdjustOutput(input As String, output As String) As String
	Dim retVal As New StringBuilder(output)

	For i As Integer = 0 To input.Length - 1
		If Not Char.IsLetter(input(i)) Then
			retVal = retVal.Insert(i, input(i).ToString())
		End If

		If Char.IsLower(input(i)) Then
			retVal(i) = Char.ToLower(retVal(i))
		End If
	Next

	Return retVal.ToString()
End Function

Private Shared Function Cipher(input As String, key As String, encipher As Boolean) As String
	Dim retVal As String = String.Empty
	Dim keySquare As Char(,) = GenerateKeySquare(key)
	Dim tempInput As String = RemoveOtherChars(input)
	Dim e As Integer = If(encipher, 1, -1)

	If (tempInput.Length Mod 2) <> 0 Then
		tempInput += "X"
	End If

	For i As Integer = 0 To tempInput.Length - 1 Step 2
		Dim row1 As Integer = 0
		Dim col1 As Integer = 0
		Dim row2 As Integer = 0
		Dim col2 As Integer = 0

		GetPosition(keySquare, Char.ToUpper(tempInput(i)), row1, col1)
		GetPosition(keySquare, Char.ToUpper(tempInput(i + 1)), row2, col2)

		If row1 = row2 AndAlso col1 = col2 Then
			retVal += New String(SameRowColumn(keySquare, row1, col1, e))
		ElseIf row1 = row2 Then
			retVal += New String(SameRow(keySquare, row1, col1, col2, e))
		ElseIf col1 = col2 Then
			retVal += New String(SameColumn(keySquare, col1, row1, row2, e))
		Else
			retVal += New String(DifferentRowColumn(keySquare, row1, col1, row2, col2))
		End If
	Next

	retVal = AdjustOutput(input, retVal)

	Return retVal
End Function

Public Shared Function Encipher(input As String, key As String) As String
	Return Cipher(input, key, True)
End Function

Public Shared Function Decipher(input As String, key As String) As String
	Return Cipher(input, key, False)
End Function
								


Example

									Dim text As String = "Hello World"
Dim cipherText As String = Encipher(text, "cipher")
Dim plainText As String = Decipher(cipherText, "cipher")
								


Output

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