PYTHON CRYPTOGRAPHY PLAYFAIR CIPHER ALGORITHM
DESCRIPTION:
Playfair cipher is the first and best-known digraph substitution cipher, which uses the technique of symmetry encryption, Playfair cipher is the best-known multi-letter encryption cipher.
EXPLANATION:
Generating the Key square:
1) It is based on a 5 x 5 matrix of letters constructed using a keyword. Here all 25 letters in the matrix are unique.
2) Firstly fill the matrix with the letters of the keyword (dropping any duplicate letters).
3) Now fill the remaining empty locations with the rest of the letters of the alphabets in order (A...Z).
4) As a 5x5 matrix can hold only 25 elements, and 2 alphabets can be paired. (It is a convention to put both "I" and "J" in the same space.)
Encrypting the Plain Text:
Before encrypting the text, you need to divide the Playfair cipher plaintext into digraphs - pairs of two letters. In the case of plaintext with an odd number of letters, add the letter 'Z' to the last letter. If there are any double letters in the plain text, replace the second occurrence of the letter with 'Z', e.g., "butter" -> "butzer"
Rules for Playfair Cipher Encryption:
- Case I: Both the letters in the digraph are in the same row, Consider the letters right of each alphabet. Thus, if one of the digraph letters is the rightmost alphabet in the grid, consider the leftmost alphabet in the same row.
- Case II: Both the letters in the digraph is in the same column, Consider the letters below each alphabet. Thus, if one of the digraph letters is the grid's bottommost letter, consider the topmost alphabet in the same column.
- Case III: Neither Case I or II is true, Form a rectangle with the two letters in the digraph and consider the rectangle's horizontal opposite corners.
Decrypting the Cipher Text:
The decryption of the Playfair cipher follows the same process in reverse. The receiver has the same key and key table and can decrypt the message using the key.
Rules for Playfair Cipher Decryption:
- Case I: Both the letters in the digraph are in the same row, Consider the letters left of each alphabet. Thus, if one of the digraph letters is the leftmost letter in the grid, consider the rightmost alphabet in the same row.
- Case II: Both the letters in the digraph is in the same column, Consider the letters above each alphabet. Thus, if one of the digraph letters is the topmost letter in the grid, consider the bottommost alphabet in the same column.
- Case III: Neither Case I or II is true, Form a rectangle with the two letters in the digraph and consider the rectangle's horizontal opposite corners.
CODE:
import itertools
import string
from typing import Generator, Iterable
def chunker(seq: Iterable[str], size: int) -> Generator[tuple[str, ...], None, None]:
it = iter(seq)
while True:
chunk = tuple(itertools.islice(it, size))
if not chunk:
return
yield chunk
def prepare_input(dirty):
"""
Prepare the plaintext by up-casing it
and separating repeated letters with X's
"""
dirty = "".join([c.upper() for c in dirty if c in string.ascii_letters])
clean = ""
if len(dirty) < 2:
return dirty
for i in range(len(dirty) - 1):
clean += dirty[i]
if dirty[i] == dirty[i + 1]:
clean += "X"
clean += dirty[-1]
if len(clean) & 1:
clean += "X"
return clean
def generate_table(key: str) -> list[str]:
alphabet = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
table = []
for char in key.upper():
if char not in table and char in alphabet:
table.append(char)
for char in alphabet:
if char not in table:
table.append(char)
return table
def encrypt(plaintext, key):
table = generate_table(key)
plaintext = prepare_input(plaintext)
ciphertext = ""
for char1, char2 in chunker(plaintext, 2):
row1, col1 = divmod(table.index(char1), 5)
row2, col2 = divmod(table.index(char2), 5)
if row1 == row2:
ciphertext += table[row1 * 5 + (col1 + 1) % 5]
ciphertext += table[row2 * 5 + (col2 + 1) % 5]
elif col1 == col2:
ciphertext += table[((row1 + 1) % 5) * 5 + col1]
ciphertext += table[((row2 + 1) % 5) * 5 + col2]
else:
ciphertext += table[row1 * 5 + col2]
ciphertext += table[row2 * 5 + col1]
return ciphertext
def decrypt(ciphertext, key):
table = generate_table(key)
plaintext = ""
for char1, char2 in chunker(ciphertext, 2):
row1, col1 = divmod(table.index(char1), 5)
row2, col2 = divmod(table.index(char2), 5)
if row1 == row2:
plaintext += table[row1 * 5 + (col1 - 1) % 5]
plaintext += table[row2 * 5 + (col2 - 1) % 5]
elif col1 == col2:
plaintext += table[((row1 - 1) % 5) * 5 + col1]
plaintext += table[((row2 - 1) % 5) * 5 + col2]
else:
plaintext += table[row1 * 5 + col2]
plaintext += table[row2 * 5 + col1]
return plaintext
print("1. Encrypt the Text")
print("2. Decrypt the Text")
mode = int(input("Enter the mode : "))
if(mode==1):
msg = input("Enter your message: ")
key = input("Enter the key: ")
result = encrypt(msg, key)
print(result)
elif(mode==2):
msg = input("Enter your message: ")
key = input("Enter the key: ")
result = decrypt(msg, key)
print(result)
else:
print("Invalid Input")
OUTPUT:
Comments