Merge remote-tracking branch 'origin/main'
This commit is contained in:
		
						commit
						5149846c61
					
				
					 6 changed files with 109 additions and 140 deletions
				
			
		| 
						 | 
				
			
			@ -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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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: ")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue