Information Security(3170720) 230763107014
PRACTICAL-1
AIM:- Implement the Caesar cipher encryption and decryption techniques.
The Caesar cipher is a classical encryption technique used for securing messages by shifting letters
in the alphabet by a fixed number of positions. It is a type of substitution cipher where each letter
in the plaintext is replaced by another letter a fixed number of positions down the alphabet. The
number of positions shifted is called the key or shift.
Formula:- C=(P+K)mod26
• C: Encrypted character (ciphertext)
• P: Plaintext character (converted to a number, where A=0, B=1, ..., Z=25)
• K: Key (number of positions to shift)
• mod: Modulo operator (wraps values around after 26)
PROGRAM:-
def encrypt(plaintext, key):
encrypted = ""
for char in plaintext:
if char.isalpha():
base = ord('A') if char.isupper() else ord('a')
encrypted += chr((ord(char) - base + key) % 26 + base)
else:
encrypted += char
return encrypted
def decrypt(ciphertext, key):
return encrypt(ciphertext, -key)
if __name__ == "__main__":
message = input("Enter the plaintext: ")
key = int(input("Enter the Key (number): "))
1
Information Security(3170720) 230763107014
encrypted_msg = encrypt(message, key)
print(f"Encrypted message: {encrypted_msg}")
decrypted_msg = decrypt(encrypted_msg, key)
print(f"Decrypted message: {decrypted_msg}")
OUTPUT:
2
Information Security(3170720) 230763107014
PRACTICAL-2
AIM:- Implement the Monoalphabetic encryption and decryption techniques.
A Monoalphabetic Cipher is a substitution cipher where each letter in the plaintext is replaced by
a fixed corresponding letter from a single substitution alphabet.The substitution alphabet is a
permutation of the regular alphabet.Each letter maps to exactly one other letter throughout the
entire message.Unlike polyalphabetic ciphers, the substitution does not change during encryption.
PROGRAM:-
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
key = input("Enter 26-letter key (A-Z, unique): ").upper()
if len(key) != 26 or not key.isalpha() or len(set(key)) != 26:
print("Invalid key! Key must be 26 unique letters A-Z.")
exit()
text = input("Enter text to encrypt: ").upper()
encrypted = ""
for ch in text:
if ch in alphabet:
encrypted += key[alphabet.index(ch)]
else:
encrypted += ch
print("Encrypted:", encrypted)
decrypted = ""
for ch in encrypted:
if ch in key:
decrypted += alphabet[key.index(ch)]
else:
decrypted += ch
print("Decrypted:", decrypted)
3
Information Security(3170720) 230763107014
OUTPUT:-
4
Information Security(3170720) 230763107014
PRACTICAL-3
AIM:- Implement Playfair Cipher Encryption-Decryption.
The Playfair Cipher is an encryption technique that works by encrypting pairs of letters (called digraphs).
It was invented by Charles Wheatstone in 1854, and popularized by Lord Playfair. The cipher is designed
to be more secure than simpler ciphers like the Caesar Cipher by using a 5x5 matrix and encrypting pairs
of letters instead of single letters. It was primarily used in the early 20th century but is now considered
insecure for modern applications.
Key Components of the Playfair Cipher:
1. Key Matrix: The Playfair Cipher relies on a 5x5 matrix of letters. The matrix is populated with a keyword
(or key), followed by the rest of the alphabet (excluding the letter "J").
The letter "J" is typically merged with "I" because only 25 letters fit in the 5x5 grid.
Example: Key = "playfair example"
PROGRAM:-
def generate_key_matrix(key):
key = key.upper().replace('J', 'I')
matrix = []
used = set()
for char in key:
if char.isalpha() and char not in used:
used.add(char)
matrix.append(char)
for char in "ABCDEFGHIKLMNOPQRSTUVWXYZ":
if char not in used:
used.add(char)
matrix.append(char)
key_matrix = [matrix[i*5:(i+1)*5] for i in range(5)]
print("\n Key Matrix (5x5):")
for row in key_matrix:
print(" | ".join(row))
return key_matrix
5
Information Security(3170720) 230763107014
def find_position(matrix, char):
for i in range(5):
for j in range(5):
if matrix[i][j] == char:
return i, j
return None
def preprocess_text(text):
text = text.upper().replace('J', 'I').replace(' ', '')
result = ''
i=0
while i < len(text):
a = text[i]
if i + 1 < len(text):
b = text[i + 1]
if a == b:
result += a + 'X'
i += 1
else:
result += a + b
i += 2
else:
result += a + 'X'
i += 1
return result
def encrypt_pair(matrix, a, b):
row1, col1 = find_position(matrix, a)
row2, col2 = find_position(matrix, b)
if row1 == row2:
6
Information Security(3170720) 230763107014
return matrix[row1][(col1 + 1) % 5] + matrix[row2][(col2 + 1) % 5]
elif col1 == col2:
return matrix[(row1 + 1) % 5][col1] + matrix[(row2 + 1) % 5][col2]
else:
return matrix[row1][col2] + matrix[row2][col1]
def decrypt_pair(matrix, a, b):
row1, col1 = find_position(matrix, a)
row2, col2 = find_position(matrix, b)
if row1 == row2:
return matrix[row1][(col1 - 1) % 5] + matrix[row2][(col2 - 1) % 5]
elif col1 == col2:
return matrix[(row1 - 1) % 5][col1] + matrix[(row2 - 1) % 5][col2]
else:
return matrix[row1][col2] + matrix[row2][col1]
def playfair_encrypt(plaintext, key):
matrix = generate_key_matrix(key)
processed = preprocess_text(plaintext)
encrypted = ''
print("\n Encrypting Pairs:")
for i in range(0, len(processed), 2):
a, b = processed[i], processed[i+1]
encrypted_pair = encrypt_pair(matrix, a, b)
print(f"{a}{b} -> {encrypted_pair}")
encrypted += encrypted_pair
return encrypted
def playfair_decrypt(ciphertext, key):
matrix = generate_key_matrix(key)
decrypted = ''
7
Information Security(3170720) 230763107014
print("\n Decrypting Pairs:")
for i in range(0, len(ciphertext), 2):
a, b = ciphertext[i], ciphertext[i+1]
decrypted_pair = decrypt_pair(matrix, a, b)
print(f"{a}{b} -> {decrypted_pair}")
decrypted += decrypted_pair
return decrypted
# --- MAIN PROGRAM ---
key = input("Enter key: ")
plaintext = input("Enter plaintext: ")
print("\nPlaintext:", plaintext)
cipher = playfair_encrypt(plaintext, key)
print("\n Encrypted Text:", cipher)
decrypted = playfair_decrypt(cipher, key)
print("\n Decrypted Text:", decrypted)
OUTPUT:-
8
Information Security(3170720) 230763107014
PRACTICAL-4
AIM : Implement Hill Cipher Encryption-Decryption.
The Hill Cipher is a symmetric key substitution cipher based on linear algebra. It uses matrix
multiplication to encrypt blocks of plaintext letters. Formula:
• P = Plaintext block (as a column vector)
• K = Key matrix (n×n)
• C = Ciphertext block
• All operations are modulo 26 (for 26 letters A-Z)
Encryption: C=(K×P)mod 26
Decryption: P=(K−1×C)mod 26 Where K−1 is the modular inverse of the key matrix under
modulo 26.
CODE:-
import numpy as np
def mod_inverse(a, m):
a=a%m
for x in range(1, m):
if (a * x) % m == 1:
return x
return None
def generate_key_matrix(key, n):
key = key.upper().replace(" ", "")
if len(key) != n * n:
raise ValueError(f"Key length must be {n*n} characters for a {n}x{n} matrix")
key_matrix = np.array([ord(char) - 65 for char in key]).reshape(n, n)
return key_matrix
def hill_encrypt(plaintext, key_matrix):
plaintext = plaintext.upper().replace(" ", "")
n = key_matrix.shape[0]
9
Information Security(3170720) 230763107014
while len(plaintext) % n != 0:
plaintext += 'X'
ciphertext = ""
print("\n--- Encryption Process ---")
for i in range(0, len(plaintext), n):
block = plaintext[i:i+n]
vector = np.array([ord(char) - 65 for char in block])
print(f"\nPlaintext Block '{block}' as Vector:", vector)
encrypted_vector = np.dot(key_matrix, vector) % 26
print("Encrypted Vector:", encrypted_vector)
ciphertext += ''.join([chr(num + 65) for num in encrypted_vector])
return ciphertext
def hill_decrypt(ciphertext, key_matrix):
n = key_matrix.shape[0]
det = int(np.round(np.linalg.det(key_matrix))) % 26
det_inv = mod_inverse(det, 26)
if det_inv is None:
raise ValueError("Key matrix is not invertible modulo 26")
adjugate = np.round(det * np.linalg.inv(key_matrix)).astype(int) % 26
matrix_mod_inv = (det_inv * adjugate) % 26
print("\nInverse Key Matrix (mod 26):\n", matrix_mod_inv.astype(int))
print("\n--- Decryption Process ---")
plaintext = ""
for i in range(0, len(ciphertext), n):
block = ciphertext[i:i+n]
vector = np.array([ord(char) - 65 for char in block])
print(f"\nCipher Block '{block}' as Vector:", vector)
10
Information Security(3170720) 230763107014
decrypted_vector = np.dot(matrix_mod_inv, vector) % 26
print("Decrypted Vector:", decrypted_vector)
plaintext += ''.join([chr(int(num) + 65) for num in decrypted_vector])
return plaintext
plaintext = input("Enter plaintext: ")
n = int(input("Enter size of key matrix (e.g., 2 for 2x2, 3 for 3x3): "))
key_string = input(f"Enter key string ({n*n} characters): ")
key_matrix = generate_key_matrix(key_string, n)
print("\nKey Matrix:\n", key_matrix)
ciphertext = hill_encrypt(plaintext, key_matrix)
print("\nCiphertext:", ciphertext)
decrypted_text = hill_decrypt(ciphertext, key_matrix)
print("\nDecrypted Text:", decrypted_text)
OUTPUT:-
11
Information Security(3170720) 230763107014
PRACTICAL-5
AIM:- Implement Polyalphabetic Cipher Encryption-Decryption.
A Polyalphabetic Cipher uses multiple substitution alphabets to encrypt a message, making it
more secure than a monoalphabetic cipher like Caesar cipher. The Vigenère cipher is a classic
example. To implement it, you'll need a key, which can be a word or phrase. The encryption
process involves shifting each letter of the plaintext based on the corresponding letter in the key
(using modulo 26 for alphabet wrap-around). Decryption reverses this process.
The formulas are as follows:
• Encryption: C = (P + K) mod 26
• Decryption: P = (C - K + 26) mod 26 Where:
C: is the ciphertext letter (represented by its numerical position in the alphabet, A=0, B=1, ...
Z=25). P: is the plaintext letter (represented by its numerical position in the alphabet).
K: is the keyword letter (also represented by its numerical position).
mod 26: represents the modulo operation (the remainder after division by 26).
CODE:-
def generate_key(msg, key):
key = list(key)
if len(msg) == len(key):
return "".join(key)
else:
for i in range(len(msg) - len(key)):
key.append(key[i % len(key)])
return "".join(key)
def encrypt_vigenere(msg, key):
encrypted_text = []
key = generate_key(msg, key)
for i in range(len(msg)):
char = msg[i]
if char.isupper():
encrypted_char = chr((ord(char) + ord(key[i]) - 2 * ord('A')) % 26 + ord('A'))
12
Information Security(3170720) 230763107014
elif char.islower():
encrypted_char = chr((ord(char) + ord(key[i]) - 2 * ord('a')) % 26 + ord('a'))
else:
encrypted_char = char
encrypted_text.append(encrypted_char)
return "".join(encrypted_text)
def decrypt_vigenere(msg, key):
decrypted_text = []
key = generate_key(msg, key)
for i in range(len(msg)):
char = msg[i]
if char.isupper():
decrypted_char = chr((ord(char) - ord(key[i]) + 26) % 26 + ord('A'))
elif char.islower():
decrypted_char = chr((ord(char) - ord(key[i]) + 26) % 26 + ord('a'))
else:
decrypted_char = char
decrypted_text.append(decrypted_char)
return "".join(decrypted_text)
text_to_encrypt = input("Enter the text to encrypt: ")
key = input("Enter the key: ")
print("Generated Key:", generate_key(text_to_encrypt, key))
encrypted_text = encrypt_vigenere(text_to_encrypt, key)
print(f"Encrypted Text: {encrypted_text}")
decrypted_text = decrypt_vigenere(encrypted_text, key)
print(f"Decrypted Text: {decrypted_text}")
13
Information Security(3170720) 230763107014
OUTPUT:-
14
Information Security(3170720) 230763107014
PRACTICAL-6
AIM:- Implement Rail Fence Cipher Encryption-Decryption.
• The Rail Fence Cipher is a transposition cipher (not substitution).
• It rearranges the order of letters without changing them.
• The text is written in a zig-zag pattern across multiple "rails" (rows), then read row by row to
form the ciphertext.
CODE:-
def rail_fence_encrypt(text, rails):
text = text.replace(" ", "")
fence = [['\n' for i in range(len(text))]
for j in range(rails)]
row, step = 0, 1
for i in range(len(text)):
fence[row][i] = text[i]
if row == 0:
step = 1
elif row == rails - 1:
step = -1
row += step
encrypted_text = []
for r in range(rails):
for c in range(len(text)):
if fence[r][c] != '\n':
encrypted_text.append(fence[r][c])
return "".join(encrypted_text)
def rail_fence_decrypt(cipher, rails):
cipher = cipher.replace(" ", "")
fence = [['\n' for i in range(len(cipher))]
for j in range(rails)]
15
Information Security(3170720) 230763107014
row, step = 0, 1
for i in range(len(cipher)):
fence[row][i] = '*'
if row == 0:
step = 1
elif row == rails - 1:
step = -1
row += step
index = 0
for r in range(rails):
for c in range(len(cipher)):
if fence[r][c] == '*' and index < len(cipher):
fence[r][c] = cipher[index]
index += 1
result = []
row, step = 0, 1
for i in range(len(cipher)):
result.append(fence[row][i])
if row == 0:
step = 1
elif row == rails - 1:
step = -1
row += step
return "".join(result)
text = input("Enter text: ")
rails = int(input("Enter number of rails: "))
encrypted = rail_fence_encrypt(text, rails)
print("Encrypted Text:", encrypted)decrypted = rail_fence_decrypt(encrypted,
rails)print("Decrypted Text:", decrypted)
16
Information Security(3170720) 230763107014
OUTPUT:-
17
Information Security(3170720) 230763107014
PRACTICAL-7
AIM:- Implement Columnar Transposition Cipher Encryption-Decryption.
• It is a transposition cipher, meaning it rearranges letters without changing them.
• A keyword (key) is used to decide the column order.
• The plaintext is written into a grid (rows × columns), then read column by column according
to the alphabetical order of the key letters.
CODE:-
import math
def encrypt_columnar_transposition(text, key):
text = text.replace(" ", "").upper()
key = key.upper()
num_cols = len(key)
num_rows = math.ceil(len(text) / num_cols)
padded_length = num_cols * num_rows
text += "X" * (padded_length - len(text))
matrix = [list(text[i:i+num_cols]) for i in range(0, len(text), num_cols)]
key_order = sorted(list(key))
col_order = [key.index(k) for k in key_order]
ciphertext = ""
for col in col_order:
for row in matrix:
ciphertext += row[col]
return ciphertext
def decrypt_columnar_transposition(ciphertext, key):
key = key.upper()
num_cols = len(key)
num_rows = math.ceil(len(ciphertext) / num_cols)
key_order = sorted(list(key))
col_order = [key.index(k) for k in key_order]
18
Information Security(3170720) 230763107014
matrix = [['' for _ in range(num_cols)] for _ in range(num_rows)]
index = 0
for col in col_order:
for row in range(num_rows):
if index < len(ciphertext):
matrix[row][col] = ciphertext[index]
index += 1
plaintext = ""
for row in matrix:
plaintext += "".join(row)
return plaintext
text = input("Enter text: ")
key = input("Enter key: ")
encrypted = encrypt_columnar_transposition(text, key)
print("Encrypted Text:", encrypted)
decrypted = decrypt_columnar_transposition(encrypted, key)
print("Decrypted Text:", decrypted)
OUTPUT:
19