Information Security and Cryptography-
CS302
Lab Assignment 10
Name: Hetvi Modi
Roll no: U22CS074
1) Design and implement a program to perform encryption and decryption
using the Playfair Cipher with both a 5x5 and a 6x6 matrix. Consider the
following inputs for the program.
a) Input1 – key phrase, Generate key matrix
b) Input2 – plain text, arrange into valid diagrams
c) Output – print Key matrix, print plain txt, and encrypted output
d) For decryption – Input2 is cipher text, no need to rearrange, output
plain text, remove padding
import string
class PlayfairCipher:
def __init__(self, key, size=5):
self.size = size
self.matrix = self.generate_key_matrix(key)
def generate_key_matrix(self, key):
alphabet = string.ascii_uppercase + ("0123456789" if self.size == 6
else "")
key = "".join(dict.fromkeys(key.upper().replace("J", "I")))
key += "".join(filter(lambda x: x not in key, alphabet))
return [list(key[i: i + self.size]) for i in range(0, self.size *
self.size, self.size)]
def find_position(self, char):
for row in range(self.size):
if char in self.matrix[row]:
return row, self.matrix[row].index(char)
return None
def process_text(self, text, pad='X'):
text = text.upper().replace("J", "I")
text = "".join(filter(str.isalnum, text))
i = 0
result = ""
while i < len(text):
a = text[i]
b = text[i + 1] if i + 1 < len(text) else pad
if a == b:
result += a + pad
i += 1
else:
result += a + b
i += 2
return result
def encrypt_pair(self, a, b):
r1, c1 = self.find_position(a)
r2, c2 = self.find_position(b)
if r1 == r2:
return self.matrix[r1][(c1 + 1) % self.size] + self.matrix[r2][(c2
+ 1) % self.size]
elif c1 == c2:
return self.matrix[(r1 + 1) % self.size][c1] + self.matrix[(r2 +
1) % self.size][c2]
else:
return self.matrix[r1][c2] + self.matrix[r2][c1]
def encrypt(self, plaintext):
plaintext = self.process_text(plaintext)
return "".join(self.encrypt_pair(plaintext[i], plaintext[i + 1]) for i
in range(0, len(plaintext), 2))
def decrypt_pair(self, a, b):
r1, c1 = self.find_position(a)
r2, c2 = self.find_position(b)
if r1 == r2:
return self.matrix[r1][(c1 - 1) % self.size] + self.matrix[r2][(c2
- 1) % self.size]
elif c1 == c2:
return self.matrix[(r1 - 1) % self.size][c1] + self.matrix[(r2 -
1) % self.size][c2]
else:
return self.matrix[r1][c2] + self.matrix[r2][c1]
def decrypt(self, ciphertext):
decrypted_text = "".join(self.decrypt_pair(ciphertext[i], ciphertext[i
+ 1]) for i in range(0, len(ciphertext), 2))
return decrypted_text.replace("X", "") # Remove padding
def read_input_file(filename):
with open(filename, "r") as file:
lines = file.readlines()
key = lines[0].strip()
plaintext = lines[1].strip()
return key, plaintext
def write_output_file(filename, key, plaintext, ciphertext, decrypted_text):
with open(filename, "w") as file:
file.write(f"Key Matrix:\n")
file.write(f"{key}\n\n")
file.write(f"Plaintext:\n{plaintext}\n\n")
file.write(f"Encrypted Text:\n{ciphertext}\n\n")
file.write(f"Decrypted Text:\n{decrypted_text}\n")
if __name__ == "__main__":
key, plaintext = read_input_file("input.txt")
playfair = PlayfairCipher(key, size=5)
encrypted_text = playfair.encrypt(plaintext)
decrypted_text = playfair.decrypt(encrypted_text)
write_output_file("output.txt", key, plaintext, encrypted_text,
decrypted_text)
print("Encryption and Decryption completed. Check output.txt for
results.")
2) Design and implement a program to perform encryption and decryption
using the Vigenère Cipher with repeating keywords. Consider the following
inputs for the program.
For Encryption:
a) Input1 – Plaintext and Key
b) Output1 – Ciphertext
For Decryption:
Input2- Ciphertext
Output2- Plaintext
from itertools import cycle
def vigenere_cipher(text, key, decrypt=False):
text = text.upper()
key = key.upper()
key_cycle = cycle(key)
shift = -1 if decrypt else 1
result = ""
for char in text:
if char.isalpha():
key_char = next(key_cycle)
new_char = chr(((ord(char) - 65 + shift * (ord(key_char) - 65)) %
26) + 65)
result += new_char
else:
result += char
return result
def read_input_file(filename):
with open(filename, "r") as file:
lines = file.readlines()
key = lines[0].strip() # First line = Key
plaintext = lines[1].strip() # Second line = Plaintext
return key, plaintext
def write_output_file(filename, key, plaintext, ciphertext, decrypted_text):
with open(filename, "w") as file:
file.write(f"Key: {key}\n\n")
file.write(f"Plaintext: {plaintext}\n\n")
file.write(f"Encrypted Text: {ciphertext}\n\n")
file.write(f"Decrypted Text: {decrypted_text}\n")
if __name__ == "__main__":
key, plaintext = read_input_file("input.txt")
encrypted_text = vigenere_cipher(plaintext, key)
decrypted_text = vigenere_cipher(encrypted_text, key, decrypt=True)
write_output_file("output.txt", key, plaintext, encrypted_text,
decrypted_text)
print("Encryption and Decryption completed. Check output.txt for
results.")
3) Design and implement a program to perform encryption and decryption
using the Vigenère Cipher with a running key (key is as long as plaintext).
Consider the following inputs for the program.
For Encryption:
a) Input3 – Plaintext and Key
b) Output3 – Ciphertext
For Decryption:
a) Input4- Ciphertext
b) Output4- Plaintext
def vigenere_running_key(text, key, decrypt=False):
text = text.upper()
key = key.upper()
shift = -1 if decrypt else 1
result = ""
for t, k in zip(text, key):
if t.isalpha():
new_char = chr(((ord(t) - 65 + shift * (ord(k) - 65)) % 26) + 65)
result += new_char
else:
result += t
return result
def read_input_file(filename):
with open(filename, "r") as file:
lines = file.readlines()
key = lines[0].strip() # First line = Key
plaintext = lines[1].strip() # Second line = Plaintext
return key, plaintext
def write_output_file(filename, key, plaintext, ciphertext, decrypted_text):
with open(filename, "w") as file:
file.write(f"Key: {key}\n\n")
file.write(f"Plaintext: {plaintext}\n\n")
file.write(f"Encrypted Text: {ciphertext}\n\n")
file.write(f"Decrypted Text: {decrypted_text}\n")
if __name__ == "__main__":
key, plaintext = read_input_file("input.txt")
if len(plaintext) != len(key):
print("Error: The key must be the same length as the plaintext!")
else:
encrypted_text = vigenere_running_key(plaintext, key)
decrypted_text = vigenere_running_key(encrypted_text, key,
decrypt=True)
write_output_file("output.txt", key, plaintext, encrypted_text,
decrypted_text)
print("Encryption and Decryption completed. Check output.txt for
results.")
4) Design and implement a program to perform encryption and decryption
using the One time pad. Consider the following inputs for the program.
For Encryption:
a) Input3 – Plaintext and Generate the using a good Random Number
Generator (RNG) Function
b) Output3 – Ciphertext
For Decryption:
a) Input4- Ciphertext
b) Output4- Plaintext
Note: Take input from the text file and store the output in the text file for all
of the above programs.
import random
import string
def one_time_pad(text, key=None, decrypt=False):
if key is None:
key = ''.join(random.choice(string.ascii_uppercase) for _ in
range(len(text)))
result = ""
for t, k in zip(text.upper(), key.upper()):
if t.isalpha():
shift = (ord(k) - 65)
new_char = chr(((ord(t) - 65 - shift) % 26 + 65) if decrypt else
((ord(t) - 65 + shift) % 26 + 65))
result += new_char
else:
result += t
return (result, key) if not decrypt else result
def read_input_file(filename):
with open(filename, "r") as file:
plaintext = file.readline().strip() # Read first line as plaintext
return plaintext
def write_output_file(filename, plaintext, key, ciphertext, decrypted_text):
with open(filename, "w") as file:
file.write(f"Plaintext: {plaintext}\n\n")
file.write(f"Random Key: {key}\n\n")
file.write(f"Encrypted Text: {ciphertext}\n\n")
file.write(f"Decrypted Text: {decrypted_text}\n")
if __name__ == "__main__":
plaintext = read_input_file("input.txt")
encrypted_text, otp_key = one_time_pad(plaintext)
decrypted_text = one_time_pad(encrypted_text, otp_key, decrypt=True)
write_output_file("output.txt", plaintext, otp_key, encrypted_text,
decrypted_text)
print("Encryption and Decryption completed. Check output.txt for
results.")