Play Fair Cipher Encryption Using Python3
Hi everyone since I’m into cryptography these days I thought why don’t I give a try to code the algorithms that are used to encrypt. My most favorite one is PlayFair Cipher, so I thought it would be easy to code but really took me a lot of hours. First let’s see what is PlayFair Cipher and working of the algorithm and then we can dive into the code.
PlayFair Cipher
It is first practical digraph substitution cipher. It has 25*25 = 625 possible diagraphs. Diagraph means encrypt using 2 letter rather than 1 letter. Playfair is significantly harder to break since the frequency analysis used for simple substitution ciphers does not work with it.
How does PlayFair Cipher Encryption algorithm work?
I will explain with an example, so let us take plaintext as PASSIVE ATTACK IS STILL BAD and key is PROGRAMMING
There are three steps in the algorithm:
1. Separate the Plaintext into pairs of text.
2. Generate Key Matrix or Key Square.
3. Encrypt Plaintext using Key square or Key Matrix from step 2.
STEP 1 : Separate the Plaintext into pair of text:
Our plaintext is Passive attack is still bad, I am going to split the sentence into pairs of letter.
Here we go,
[[p,a],[s,x],[s,i],[v,e],[a,t],[t,a],[c,k],[i,s],[s,t],[i,l],[l,b],[a,d]]
This is our plainText 2D List .
Rules to be followed while splitting the plaintext are as follows, please read it carefully because this is the most important thing.
1.While splitting text into pairs, if the letters are same in a pair then insert filler x .Filler, it can be low frequency alphabet i.e which occur less number of times in English words for example j, z, w etc.
eg . for above plaintext I got a pair [s,s] ->[s,x]. If the letter are same we cannot encrypt it will be the same letter as before so we are inserting filler x before ‘s’.
2. At the end if only one letter is left it has no pair we can insert our filler x.
eg : consider red as plain text we can split it as [[r,e],[d,x]]
3.If you want to keep spaces while encrypting you can replace white space with filler x.
Let us dive into Step 2
STEP 2 : Generate Key Matrix or Key Square
Generating Key Matrix or Key Square of size 5*5, it will always be 5*5 because only 26 alphabets are there. Our Key is PROGRAMMING
The Key Sqaure is
Rules used to fill the key matrix/ key square are pretty simple. Here they are
1.In our key there may be repeated letters while filling the key matrix/key square a letter should occur only one time so reduce our key where every letter occurs only once. In above example PROGRAMMING key is reduced to PROGAMIN
2.Rest of the boxes in the key matrix/ key square is filled by the rest of alphabets that are not present in key in lexicographical order.Then the important point i and j are considered as same in this matrix according to your problem statement fill I or J in the matrix . If both are present then represent both i and j as I or J. Since the Key I used here has ‘I’ in it I placed ‘I’ instead of ‘J’.
3. If you feel little bit confused look at above image(fig 1) for reference.
Now our key matrix is ready and we are going to encrypt our message(plaintext). And this is going to be real fun .
STEP 3 : Encrypt Plaintext using Key square /Key Matrix
Our plaintext 2D List is [[p,a],[s,x],[s,i],[v,e],[a,t],[t,a],[c,k],[i,s],[s,t],[i,l],[l,b],[a,d]].
First we are going to encrypt ‘p’ and ‘a’. Look at the image above. Position of ‘p’ and ‘a’ are in same row but different column so encrypt the letter with letter in same row with next column.
p->r , a->p
Next is ‘s’ and ‘x’. Position of ‘s’ and ‘x’ are in different row but same column so encrypt the letter with letter in different row with same column. So ‘s’ is going to be ‘x’ and ‘x’ is ‘o’.
s->x , x->o
Next is ‘s’ and ‘i’. Position of ‘s’ and ‘i’ are in different row but different column so encrypt the letter with letter present at intersection of ‘s’ and ‘i’ . So ‘s’ is going to be ‘q’ and ‘i’ is ‘n’.Here we keep our row constant and we are going to interchange the column only.
so s->q , i->n
So do the same for every pair of letter present in the message.
Now I am going to summarize the rules that are used to encrypt the message for better understanding.
1.If the row of the letter in a pair is same then encrypt with letter at position same row but column+1 i.e next column
2.If the column of the letter in a pair is same then encrypt with letter at position same column but row+1 i.e next row
3.If the column and row both are different keep the row constant interchange the column that is for ‘s’ and ‘i’ . Position of ‘s’ is[3,2] (Note I started indexing from 0) and ‘i’ is [1,1] .So ‘s’ is encrypted with letter at position [3,1](row is same but column is interchanged) and that is ‘q’ and for ‘i’ is encrypted with letter at position [1,2] and that is ‘n’.
Finally the encrypted message would look like RPXOQNWDGUUGKUQNTUMQTMPK
Hurray ! that’s it , Now you have learned the algorithm to encrypt the message using Playfair Cipher.
Now we will dive into how to code the above algorithm using Python3. I will explain how to code the algorithm in 3 steps as I did for the algorithm. The three steps are as follows.
1. Separate the Plaintext into pairs of text.
2. Generate Key Matrix or Key Square
3. Encrypt Plaintext using Key square or Key Matrix
1.Separate the Plaintext into pairs of text.
def plainTextConversion(s,key):
i = 0
sList = list(s.strip())
n = len(sList)
while(n>0):
temp=[]
checkSame=False
#print(sList,'sList')
for j in range(0,2):
if j<len(sList) and sList[j] not in temp :
temp.append(sList[j])
checkSame = False
elif j<len(sList) and sList[j] in temp :
temp.append('x')
checkSame = True
else:
checkSame = False
continue
#print(temp,'temp')
sList.remove(sList[0])
# print(checkSame)
if len(temp)>1 and checkSame == False:
sList.remove(sList[0])
plainText.append(temp)
n=n-2
elif len(temp)>1 and checkSame == True:
#do noting
plainText.append(temp)
n=n-1
elif len(temp)<1 and checkSame == True:
# do nothing
plainText.append(temp)
else:
temp.append('x')
plainText.append(temp)
n=n-2
#print(n,'n')
#print(plainText,'plainText')
print(plainText,'final')
res = playFairCipher(plainText,key)
return res
if __name__ == '__main__':s = input ('enter plainText : ')
key = input('enter key text : ')
s = ''.join(s.split())
key = ''.join(key.split())
print(s,'[s]')
result = plainTextConversion(s,key)
print (result)
Here, In this code I get key and plaiText as Input and remoe the whitespace using join() and split() function. I have created tempList to store the plaintext pairs and then in while loop I am checking repeated characters are present in the message and whether every pair has two letters or at end any letter is left alone so that we can insert filler and All the rules listed in the Step 1.
Next checksame is used to check whether letters in a pair is same or not, if they are same then insert filler x. And also I removed the letter from the list which are checked and converted into pair of list, so it will be bit easier for me to code and I don’t need to use nested for loops . After checking the conditions I appended the temp which contains the pair to plainText List.
Now Step 1 is completed.
2. Generate Key Matrix or Key Square
plainText=[]
keyMatrix = []
cipherTextList =[]def index_2d(keyMatrix, v):
for i, x in enumerate(keyMatrix):
if v in x:
return [i, x.index(v)]
def keyMatrixGeneration(keyMatrix,reducedAlphabet):
alphacounter = 0
alpha = len(reducedAlphabet)
#print(alpha,'[alpha]')
while alphacounter < alpha and len(reducedAlphabet[alphacounter:alphacounter+5]) :
tempReducedAlphabet = []
#print(reducedAlphabet[0:5],'[reducedAlphabet temp]')
tempReducedAlphabet.append(reducedAlphabet[alphacounter:alphacounter+5])
alphacounter+=5
keyMatrix.extend(tempReducedAlphabet)
if alphacounter > alpha and len(reducedAlphabet[alphacounter-5:]):
tempReducedAlphabet = []
tempReducedAlphabet.append(reducedAlphabet[alphacounter-5:])
keyMatrix.append(tempReducedAlphabet)
return keyMatrix
def playFairCipher(plainText,key):
# create key matrix
#print(key,'[key]')
#print('[playFairCipher def]')
cipherText = ''
keyList = list(key.strip(' '))
keyListSet = set(keyList) # use this to find difference in alphabet and key
reducedKeyList = []
for ch in keyList:
if ch not in reducedKeyList:
reducedKeyList.append(ch)
tempKey = []
#print(keyListSet,reducedKeyList)
k = len(reducedKeyList)
counter = 0
alphabet = list('abcdefghijklmnopqrstuvwxyz')
alphabetSet = set(alphabet)
keycount = 5
#print(k)
if k==5:
#print('k==5')
keyMatrix.append(reducedKeyList[0:5])
elif k>5:
while keycount<=k:
keyMatrix.append(reducedKeyList[keycount-5:keycount])
keycount+=5
if keycount > k:
keyMatrix.append(reducedKeyList[keycount-5:])
else:
keyMatrix.append(reducedKeyList)
print(keyMatrix,'[before keyMatrix]')
reducedAlphabetSet = alphabetSet-keyListSet
#print(reducedAlphabetSet,'[reducedAlphabetSet]')
reducedAlphabet = list(reducedAlphabetSet)
reducedAlphabet.sort()
#print(reducedAlphabet,'[reducedAlphabet list]')
if 'i'and 'j' in reducedAlphabet:
reducedAlphabet.remove('j')
if 'i' not in reducedAlphabet and 'j' not in reducedAlphabet:
ind = index_2d(keyMatrix,'j')
print(ind,keyMatrix[ind[0]][ind[1]])
keyMatrix[ind[0]].remove(keyMatrix[ind[0]][ind[1]])
lengthCheck = False
keyN = 0
# generation of key matrix
for i in range(0,len(keyMatrix)):
if len(keyMatrix[i])<5:
lengthCheck=True
keyN = i
if lengthCheck==True:
tempReducedAlphabet = []
tempReducedAlphabet.extend(reducedAlphabet[0:5-len(keyMatrix[keyN])])
#print(tempReducedAlphabet,'[tempReducedAlphabet]')
keyMatrix[keyN].extend(tempReducedAlphabet)
for i in tempReducedAlphabet:
reducedAlphabet.remove(i)
#print(reducedAlphabet,'[reducedAlphabet]')
keyMatrixGeneration(keyMatrix,reducedAlphabet)
else:
keyMatrixGeneration(keyMatrix,reducedAlphabet)
print(keyMatrix,'[keymatrix]')
For me this is the most tedious part I struggled a bit in this. This code has two functions playFairCipher and keyMatrixGeneration.
First In playFairCipher I reduced the key i.e removed repeated characters using set datatype so KeyListSet is our reduced KeyList which has alphabet only one time no repeated characters and using Set Difference I am going remove the alphabets that are present in key already and sort them in lexicographical order using list sort method beacause set is unindexed datatype so after converting the difference i.e reducedAlphabet into list. If both I and J present in reducedAlphabet if present I removed ‘j’and if ‘i’ and ‘j’ both are present in keyList I removed ‘j’. This is not a problem if you follow the same while decryption only one rule it should be ‘i’ or ‘j’ not both.
After removing the repeated characters and all other things I used some logic to append the these alphabets to the keyMatrix. If the keyList length is not divisible by 5 then the last row’s length will be less than 5 , So from there we have to start extend the list.
KeyMatrixGeneration function is all about appending the alphabet since the size is constant I appended 5 alphabet at a time.
With This code you will be able to create Key Matrix/ Key Square. Now, we entered the last step. Last but not least the real encryption happens with step 3.
3. Encrypt Plaintext using Key square or Key Matrix
# matching plainText with key matrix
for i in range(0,len(plainText)):
first=[]
second=[]
first.extend(index_2d(keyMatrix,plainText[i][0]))
second.extend(index_2d(keyMatrix,plainText[i][1]))
if first[0]!=second[0] and first[1]!=second[1]:
cipherText += keyMatrix[first[0]][second[1]]+ keyMatrix[second[0]][first[1]]
elif first[0]==second[0]:
if first[1]+1<len(keyMatrix[first[0]]):
cipherText+=keyMatrix[first[0]][first[1]+1]
else:
cipherText+=keyMatrix[first[0]][0]
if second[1]+1<len(keyMatrix[second[0]]):
cipherText+=keyMatrix[first[0]][second[1]+1]
else:
cipherText+=keyMatrix[first[0]][0]
else:
if first[0]+1<len(keyMatrix):
cipherText+=keyMatrix[first[0]+1][first[1]]
else:
cipherText+=keyMatrix[0][first[1]]
if second[0]+1<len(keyMatrix):
cipherText+=keyMatrix[second[0]+1][second[1]]
else:
cipherText+=keyMatrix[0][second[1]]
#print(first,'[first]')
print(cipherText,'[cipherText]')
return cipherText
Add this code at the end of the PlayFairCipher function. In this I used if and else condition to check whether they are in same or in different row or same column or different column using index_2d function which is already present in step 2. For your reference I will write the index_2d function code here.
def index_2d(keyMatrix, v):
for i, x in enumerate(keyMatrix):
if v in x:
return [i, x.index(v)]
It takes the list in which value to be found and the value to be found as arguments. It returns the indices of the value. First represent first letter in the pair and second represent second in the pair. With these value I progammed the rules that I said while explaining the algorithm Step 3 feel free to read those rules again if you feel like you don’t understand the code.
Hurray! You have learned how to program PlayFairCipher Encryption Using Python 3.
Below is the entire Code of PlayFairCipher Encryption.
plainText=[]
keyMatrix = []
cipherTextList =[]def index_2d(keyMatrix, v):
for i, x in enumerate(keyMatrix):
if v in x:
return [i, x.index(v)]
def keyMatrixGeneration(keyMatrix,reducedAlphabet):
alphacounter = 0
alpha = len(reducedAlphabet)
#print(alpha,'[alpha]')
while alphacounter < alpha and len(reducedAlphabet[alphacounter:alphacounter+5]) :
tempReducedAlphabet = []
#print(reducedAlphabet[0:5],'[reducedAlphabet temp]')
tempReducedAlphabet.append(reducedAlphabet[alphacounter:alphacounter+5])
alphacounter+=5
keyMatrix.extend(tempReducedAlphabet)
if alphacounter > alpha and len(reducedAlphabet[alphacounter-5:]):
tempReducedAlphabet = []
tempReducedAlphabet.append(reducedAlphabet[alphacounter-5:])
keyMatrix.append(tempReducedAlphabet)
return keyMatrix
def playFairCipher(plainText,key):
# create key matrix
#print(key,'[key]')
#print('[playFairCipher def]')
cipherText = ''
keyList = list(key.strip(' '))
keyListSet = set(keyList) # use this to find difference in alphabet and key
reducedKeyList = []
for ch in keyList:
if ch not in reducedKeyList:
reducedKeyList.append(ch)
tempKey = []
#print(keyListSet,reducedKeyList)
k = len(reducedKeyList)
counter = 0
alphabet = list('abcdefghijklmnopqrstuvwxyz')
alphabetSet = set(alphabet)
keycount = 5
#print(k)
if k==5:
#print('k==5')
keyMatrix.append(reducedKeyList[0:5])
elif k>5:
while keycount<=k:
keyMatrix.append(reducedKeyList[keycount-5:keycount])
keycount+=5
if keycount > k:
keyMatrix.append(reducedKeyList[keycount-5:])
else:
keyMatrix.append(reducedKeyList)
print(keyMatrix,'[before keyMatrix]')
reducedAlphabetSet = alphabetSet-keyListSet
#print(reducedAlphabetSet,'[reducedAlphabetSet]')
reducedAlphabet = list(reducedAlphabetSet)
reducedAlphabet.sort()
#print(reducedAlphabet,'[reducedAlphabet list]')
if 'i'and 'j' in reducedAlphabet:
reducedAlphabet.remove('j')
if 'i' not in reducedAlphabet and 'j' not in reducedAlphabet:
ind = index_2d(keyMatrix,'j')
print(ind,keyMatrix[ind[0]][ind[1]])
keyMatrix[ind[0]].remove(keyMatrix[ind[0]][ind[1]])
lengthCheck = False
keyN = 0
# generation of key matrix
for i in range(0,len(keyMatrix)):
if len(keyMatrix[i])<5:
lengthCheck=True
keyN = i
if lengthCheck==True:
tempReducedAlphabet = []
tempReducedAlphabet.extend(reducedAlphabet[0:5-len(keyMatrix[keyN])])
#print(tempReducedAlphabet,'[tempReducedAlphabet]')
keyMatrix[keyN].extend(tempReducedAlphabet)
for i in tempReducedAlphabet:
reducedAlphabet.remove(i)
#print(reducedAlphabet,'[reducedAlphabet]')
keyMatrixGeneration(keyMatrix,reducedAlphabet)
else:
keyMatrixGeneration(keyMatrix,reducedAlphabet)
print(keyMatrix,'[keymatrix]')
# matching plainText with key matrix
for i in range(0,len(plainText)):
first=[]
second=[]
first.extend(index_2d(keyMatrix,plainText[i][0]))
second.extend(index_2d(keyMatrix,plainText[i][1]))
if first[0]!=second[0] and first[1]!=second[1]:
cipherText += keyMatrix[first[0]][second[1]]+ keyMatrix[second[0]][first[1]]
elif first[0]==second[0]:
if first[1]+1<len(keyMatrix[first[0]]):
cipherText+=keyMatrix[first[0]][first[1]+1]
else:
cipherText+=keyMatrix[first[0]][0]
if second[1]+1<len(keyMatrix[second[0]]):
cipherText+=keyMatrix[first[0]][second[1]+1]
else:
cipherText+=keyMatrix[first[0]][0]
else:
if first[0]+1<len(keyMatrix):
cipherText+=keyMatrix[first[0]+1][first[1]]
else:
cipherText+=keyMatrix[0][first[1]]
if second[0]+1<len(keyMatrix):
cipherText+=keyMatrix[second[0]+1][second[1]]
else:
cipherText+=keyMatrix[0][second[1]]
#print(first,'[first]')
print(cipherText,'[cipherText]')
return cipherText
def plainTextConversion(s,key):
i = 0
sList = list(s.strip())
n = len(sList)
while(n>0):
temp=[]
checkSame=False
#print(sList,'sList')
for j in range(0,2):
if j<len(sList) and sList[j] not in temp :
temp.append(sList[j])
checkSame = False
elif j<len(sList) and sList[j] in temp :
temp.append('x')
checkSame = True
else:
checkSame = False
continue
#print(temp,'temp')
sList.remove(sList[0])
# print(checkSame)
if len(temp)>1 and checkSame == False:
sList.remove(sList[0])
plainText.append(temp)
n=n-2
elif len(temp)>1 and checkSame == True:
#do noting
plainText.append(temp)
n=n-1
elif len(temp)<1 and checkSame == True:
# do nothing
plainText.append(temp)
else:
temp.append('x')
plainText.append(temp)
n=n-2
#print(n,'n')
#print(plainText,'plainText')
print(plainText,'final')
res = playFairCipher(plainText,key)
return res
if __name__ == '__main__':s = input ('enter plainText : ')
key = input('enter key text : ')
s = ''.join(s.split())
key = ''.join(key.split())
print(s,'[s]')
result = plainTextConversion(s,key)
print (result)
This is all. I hope you Understand this code .
Happy coding 😄
Coding is addictive fun too