101 lines
3.0 KiB
Python
101 lines
3.0 KiB
Python
import random
|
|
from sympy import isprime, gcd
|
|
|
|
# Define the 27-character alphabet mapping
|
|
ALPHABET = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
ALPHABET_MAP = {char: idx for idx, char in enumerate(ALPHABET)}
|
|
REVERSE_ALPHABET_MAP = {idx: char for idx, char in enumerate(ALPHABET)}
|
|
|
|
|
|
# Extended Euclidean Algorithm to find modular inverse
|
|
def modular_inverse(a, m):
|
|
"""Returns the modular inverse of a under modulo m, or None if it doesn't exist."""
|
|
m0, x0, x1 = m, 0, 1
|
|
while a > 1:
|
|
q = a // m
|
|
a, m = m, a % m
|
|
x0, x1 = x1 - q * x0, x0
|
|
if x1 < 0:
|
|
x1 += m0
|
|
return x1
|
|
|
|
|
|
# RSA key generation function
|
|
def generate_rsa_keys(bit_length=512):
|
|
p = generate_large_prime(bit_length)
|
|
q = generate_large_prime(bit_length)
|
|
|
|
n = p * q
|
|
phi = (p - 1) * (q - 1) # euler's function
|
|
|
|
e = 65537
|
|
while gcd(e, phi) != 1:
|
|
e = random.randint(2, phi - 1)
|
|
|
|
d = modular_inverse(e, phi)
|
|
if d is None:
|
|
raise ValueError("Modular inverse for the chosen e does not exist.")
|
|
|
|
return (n, e), (n, d)
|
|
|
|
|
|
def generate_large_prime(bit_length):
|
|
"""Generates a random prime number of approximately bit_length bits."""
|
|
while True:
|
|
candidate = random.getrandbits(bit_length)
|
|
if isprime(candidate):
|
|
return candidate
|
|
|
|
|
|
# RSA encryption
|
|
def rsa_encrypt(plaintext, public_key):
|
|
n, e = public_key
|
|
# Convert plaintext to numeric format using the alphabet map
|
|
numeric_plaintext = [ALPHABET_MAP[char] for char in plaintext if char in ALPHABET_MAP]
|
|
# Encrypt each character in the numeric plaintext
|
|
ciphertext = [pow(char, e, n) for char in numeric_plaintext]
|
|
return ciphertext
|
|
|
|
|
|
# RSA decryption
|
|
def rsa_decrypt(ciphertext, private_key):
|
|
n, d = private_key
|
|
# Decrypt each character in the ciphertext
|
|
decrypted_numbers = [pow(char, d, n) for char in ciphertext]
|
|
# Convert decrypted numbers back to characters
|
|
plaintext = ''.join(REVERSE_ALPHABET_MAP[num] for num in decrypted_numbers)
|
|
return plaintext
|
|
|
|
|
|
# Validation functions
|
|
def validate_plaintext(plaintext):
|
|
"""Validates that the plaintext contains only characters from the 27-character alphabet."""
|
|
for char in plaintext:
|
|
if char not in ALPHABET_MAP:
|
|
raise ValueError(f"Invalid character in plaintext: {char}")
|
|
|
|
|
|
def validate_ciphertext(ciphertext, n):
|
|
"""Validates that each part of the ciphertext is a number less than n."""
|
|
for part in ciphertext:
|
|
if not (0 <= part < n):
|
|
raise ValueError(f"Invalid ciphertext value: {part}")
|
|
|
|
|
|
# Example usage
|
|
if __name__ == "__main__":
|
|
# Generate keys
|
|
public_key, private_key = generate_rsa_keys()
|
|
|
|
# Plaintext to encrypt
|
|
plaintext = "HELLO WORLD"
|
|
validate_plaintext(plaintext)
|
|
|
|
# Encrypt the plaintext
|
|
ciphertext = rsa_encrypt(plaintext, public_key)
|
|
print("Ciphertext:", ciphertext)
|
|
|
|
# Validate ciphertext and decrypt
|
|
validate_ciphertext(ciphertext, public_key[0])
|
|
decrypted_text = rsa_decrypt(ciphertext, private_key)
|
|
print("Decrypted Text:", decrypted_text) |