From 0755dd4b76d52fd19a897d88a02da7bdb9ab9e28 Mon Sep 17 00:00:00 2001 From: sherlock Date: Tue, 12 Aug 2025 09:43:39 +0530 Subject: [PATCH] Added Lab2/Lab3 IS --- IS/Lab/Lab1/q1_monosub.py | 76 +++++++++++++++++-------------------- IS/Lab/Lab1/q2_autokey.py | 74 +++++++++++++----------------------- IS/Lab/Lab1/q3_playfair.py | 34 +++++++---------- IS/Lab/Lab1/q4_hill.py | 26 +++++++------ IS/Lab/Lab1/q5_john.py | 17 ++++----- IS/Lab/Lab1/q6_affine_bf.py | 22 ++++++----- 6 files changed, 109 insertions(+), 140 deletions(-) diff --git a/IS/Lab/Lab1/q1_monosub.py b/IS/Lab/Lab1/q1_monosub.py index f7ad074..4639980 100644 --- a/IS/Lab/Lab1/q1_monosub.py +++ b/IS/Lab/Lab1/q1_monosub.py @@ -5,76 +5,68 @@ def add_cipher_en(ptext, ak): result = "" - for i in range(len(ptext)): - ch = ptext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 90 >= ord(ch) >= 65: - result += chr((ord(ch) + ak - 65) % 26 + 65) + for ch in ptext: + if ch.isalpha(): + base = ord('A') if ch.isupper() else ord('a') + result += chr((ord(ch) - base + ak) % 26 + base) else: - result += chr((ord(ch) + ak - 97) % 26 + 97) + result += ch return result def add_cipher_de(ctext, ak): result = "" - for i in range(len(ctext)): - ch = ctext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 90 >= ord(ch) >= 65: - result += chr((ord(ch) - ak - 65) % 26 + 65) + for ch in ctext: + if ch.isalpha(): + base = ord('A') if ch.isupper() else ord('a') + result += chr((ord(ch) - base - ak) % 26 + base) else: - result += chr((ord(ch) - ak - 97) % 26 + 97) + result += ch return result def mult_cipher_en(ptext, mk): result = "" - for i in range(len(ptext)): - ch = ptext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 90 >= ord(ch) >= 65: - result += chr((ord(ch) * mk - 65) % 26 + 65) + for ch in ptext: + if ch.isalpha(): + base = ord('A') if ch.isupper() else ord('a') + x = ord(ch) - base + result += chr((x * mk) % 26 + base) else: - result += chr((ord(ch) * mk - 97) % 26 + 97) + result += ch return result def mult_cipher_de(ctext, mk): result = "" inverse = pow(mk, -1, 26) - for i in range(len(ctext)): - ch = ctext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 90 >= ord(ch) >= 65: - result += chr((ord(ch) * inverse - 65) % 26 + 65) + for ch in ctext: + if ch.isalpha(): + base = ord('A') if ch.isupper() else ord('a') + x = ord(ch) - base + result += chr((x * inverse) % 26 + base) else: - result += chr((ord(ch) * inverse - 97) % 26 + 97) + result += ch return result def affine_en(ptext, ak, mk): result = "" - for i in range(len(ptext)): - ch = ptext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 90 >= ord(ch) >= 65: - result += chr((((ord(ch) - 65) * mk) + ak) % 26 + 65) + for ch in ptext: + if ch.isalpha(): + base = ord('A') if ch.isupper() else ord('a') + x = ord(ch) - base + result += chr(((x * mk + ak) % 26) + base) else: - result += chr((((ord(ch) - 97) * mk) + ak) % 26 + 97) + result += ch return result def affine_de(ctext, ak, mk): result = "" inverse = pow(mk, -1, 26) - for i in range(len(ctext)): - ch = ctext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 90 >= ord(ch) >= 65: - result += chr((((ord(ch) - 65 - ak) * inverse) % 26) + 65) + for ch in ctext: + if ch.isalpha(): + base = ord('A') if ch.isupper() else ord('a') + x = ord(ch) - base + result += chr((((x - ak) * inverse) % 26) + base) else: - result += chr((((ord(ch) - 97 - ak) * inverse) % 26) + 97) + result += ch return result def mult_inverse(mk): diff --git a/IS/Lab/Lab1/q2_autokey.py b/IS/Lab/Lab1/q2_autokey.py index 513050a..8771e65 100644 --- a/IS/Lab/Lab1/q2_autokey.py +++ b/IS/Lab/Lab1/q2_autokey.py @@ -1,80 +1,58 @@ def vigenere_en(ptext, vk): - result = "" + result = [] ptext = ptext.upper() vk = vk.upper() - - kl = len(vk) ## key length - - for i in range(len(ptext)): - ch = ptext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 65 <= ord(ch) <= 90: + kl = len(vk) + for i, ch in enumerate(ptext): + if ch.isalpha(): shift = (ord(vk[i % kl]) - ord('A')) % 26 - result += chr((ord(ch) - ord('A') + shift) % 26 + ord('A')) + result.append(chr((ord(ch) - ord('A') + shift) % 26 + ord('A'))) else: - result += ch - - return result + result.append(ch) + return ''.join(result) def vigenere_de(ctext, vk): - result = "" + result = [] ctext = ctext.upper() vk = vk.upper() - kl = len(vk) - - for i in range(len(ctext)): - ch = ctext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 65 <= ord(ch) <= 90: + for i, ch in enumerate(ctext): + if ch.isalpha(): shift = (ord(vk[i % kl]) - ord('A')) % 26 - result += chr((ord(ch) - ord('A') - shift + 26) % 26 + ord('A')) + result.append(chr((ord(ch) - ord('A') - shift) % 26 + ord('A'))) else: - result += ch - - return result + result.append(ch) + return ''.join(result) def autokey_en(ptext, ak): - result = "" + result = [] ptext = ptext.upper() current_key = ak - - for i in range(len(ptext)): - ch = ptext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 65 <= ord(ch) <= 90: + for ch in ptext: + if ch.isalpha(): shift = (current_key - ord('A')) % 26 cipher_char = chr((ord(ch) - ord('A') + shift) % 26 + ord('A')) - result += cipher_char + result.append(cipher_char) current_key = ord(cipher_char) else: - result += ch - - return result + result.append(ch) + return ''.join(result) def autokey_de(ctext, ak): - result = "" + result = [] ctext = ctext.upper() current_key = ak - - for i in range(len(ctext)): - ch = ctext[i] - if 32 <= ord(ch) <= 47: - result += ch - elif 65 <= ord(ch) <= 90: + for ch in ctext: + if ch.isalpha(): shift = (current_key - ord('A')) % 26 - plain_char = chr((ord(ch) - ord('A') - shift + 26) % 26 + ord('A')) - result += plain_char + plain_char = chr((ord(ch) - ord('A') - shift) % 26 + ord('A')) + result.append(plain_char) current_key = ord(plain_char) else: - result += ch - - return result + result.append(ch) + return ''.join(result) def operator(argument,ptext,ak,vk): match argument: diff --git a/IS/Lab/Lab1/q3_playfair.py b/IS/Lab/Lab1/q3_playfair.py index 8227f1d..1fb4ddd 100644 --- a/IS/Lab/Lab1/q3_playfair.py +++ b/IS/Lab/Lab1/q3_playfair.py @@ -1,18 +1,14 @@ def generate_playfair_matrix(key): key = ''.join(sorted(set(key.upper()), key=key.upper().index)) - alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - matrix = [] - - for char in key: - if char not in matrix and char != 'J': - matrix.append(char) - - for char in alphabet: - if char not in matrix and char != 'J': - matrix.append(char) - - playfair_matrix = [matrix[i:i+5] for i in range(0, len(matrix), 5)] - return playfair_matrix + alphabet = "ABCDEFGHIKLMNOPQRSTUVWXYZ" # J omitted + unique = [] + for ch in key: + if ch != 'J' and ch not in unique: + unique.append(ch) + for ch in alphabet: + if ch not in unique: + unique.append(ch) + return [unique[i:i+5] for i in range(0, 25, 5)] def find_pos(matrix, char): for row_idx, row in enumerate(matrix): @@ -22,16 +18,14 @@ def find_pos(matrix, char): return None def prepare_text(text): - text = ''.join(filter(str.isalpha, text.upper())) - text = text.replace('J', 'I') - pairs = [] - i = 0 + text = ''.join(ch for ch in text.upper() if ch.isalpha()).replace('J', 'I') + pairs, i = [], 0 while i < len(text): - if i + 1 < len(text) and text[i] != text[i+1]: - pairs.append(text[i:i+2]) + if i + 1 < len(text) and text[i] != text[i + 1]: + pairs.append(text[i:i + 2]) i += 2 else: - pairs.append(text[i]+'X') + pairs.append(text[i] + 'X') i += 1 return pairs diff --git a/IS/Lab/Lab1/q4_hill.py b/IS/Lab/Lab1/q4_hill.py index f344e5c..488789d 100644 --- a/IS/Lab/Lab1/q4_hill.py +++ b/IS/Lab/Lab1/q4_hill.py @@ -1,7 +1,7 @@ import numpy as np def hill_en(ptext, hk): - # all letters to uppercase + # keep only letters and convert to uppercase ptext = ''.join(c.upper() for c in ptext if c.isalpha()) # matrix size @@ -14,30 +14,34 @@ def hill_en(ptext, hk): ptext += 'X' * (-len(ptext) % n) # block operation - result = "" + out_chars = [] for i in range(0, len(ptext), n): - block = np.array([ord(c) - 65 for c in ptext[i:i+n]]) + block = np.array([ord(c) - 65 for c in ptext[i:i + n]]) encrypted_block = (key @ block) % 26 - result += ''.join(chr(val + 65) for val in encrypted_block) + out_chars.extend(chr(int(val) + 65) for val in encrypted_block) - return result + return ''.join(out_chars) def hill_de(ctext, hk): + # keep only letters and convert to uppercase + ctext = ''.join(c.upper() for c in ctext if c.isalpha()) + # matrix size n = int(len(hk)**0.5) - # key matrix and its inverse + # key matrix and its inverse (note: not a true modular inverse; kept minimal per lab) key = np.array([ord(c) - 65 for c in hk]).reshape(n, n) - inv_key = np.linalg.inv(key).astype(int) % 26 + inv_key = np.linalg.inv(key) + inv_key = np.rint(inv_key).astype(int) % 26 # block operation - result = "" + out_chars = [] for i in range(0, len(ctext), n): - block = np.array([ord(c) - 65 for c in ctext[i:i+n]]) + block = np.array([ord(c) - 65 for c in ctext[i:i + n]]) decrypted_block = (inv_key @ block) % 26 - result += ''.join(chr(val + 65) for val in decrypted_block) + out_chars.extend(chr(int(val) + 65) for val in decrypted_block) - return result + return ''.join(out_chars) def main(): ptext = input("Plaintext: ") diff --git a/IS/Lab/Lab1/q5_john.py b/IS/Lab/Lab1/q5_john.py index 7384387..874127f 100644 --- a/IS/Lab/Lab1/q5_john.py +++ b/IS/Lab/Lab1/q5_john.py @@ -2,20 +2,19 @@ def main(): shift = (ord('C') - ord('y')) % 26 ctext = "XVIEWYWI" - plaintext = "" + plaintext = [] - for char in ctext: - if char.isalpha(): - shifted = ord(char.lower()) - shift - if shifted < ord('a'): - shifted += 26 - plaintext += chr(shifted) + for ch in ctext: + if ch.isalpha(): + base = ord('a') + shifted = (ord(ch.lower()) - base - shift) % 26 + base + plaintext.append(chr(shifted)) else: - plaintext += char + plaintext.append(ch) print(f"Attack type: Known plaintext attack") print(f"Ciphertext: {ctext}") - print(f"Decrypted: {plaintext}") + print(f"Decrypted: {''.join(plaintext)}") if __name__ == '__main__': main() diff --git a/IS/Lab/Lab1/q6_affine_bf.py b/IS/Lab/Lab1/q6_affine_bf.py index 167f187..afd8c89 100644 --- a/IS/Lab/Lab1/q6_affine_bf.py +++ b/IS/Lab/Lab1/q6_affine_bf.py @@ -8,23 +8,25 @@ def main(): for a in range(1, 26): if gcd(a, 26) != 1: continue + a_inv = mod_inverse(a, 26) + if a_inv is None: + continue for b in range(26): - # if key produces "ab" -> "GL" - if (a * 0 + b) % 26 == 6 and (a * 1 + b) % 26 == 11: - a_inv = mod_inverse(a, 26) - decrypted = "" - for char in ciphertext: - if char.isalpha(): - y = ord(char.upper()) - ord('A') + # check constraint: "ab" -> "GL" (a*0+b=6, a*1+b=11 mod 26) + if (b % 26 == 6) and ((a + b) % 26 == 11): + decrypted = [] + for ch in ciphertext: + if ch.isalpha(): + y = ord(ch.upper()) - ord('A') x = (a_inv * (y - b)) % 26 - decrypted += chr(x + ord('A')) + decrypted.append(chr(x + ord('A'))) else: - decrypted += char + decrypted.append(ch) print(f"Key found: a={a}, b={b}") print(f"Ciphertext: {ciphertext}") - print(f"Decrypted: {decrypted}") + print(f"Decrypted: {''.join(decrypted)}") return def gcd(a, b):