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"