mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-23 21:11:08 +00:00
fix(mypy): type annotations for cipher algorithms (#4306)
* fix(mypy): type annotations for cipher algorithms * Update mypy workflow to include cipher directory * fix: mypy errors in hill_cipher.py * fix build errors
This commit is contained in:
parent
806b3864c3
commit
60895366c0
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
|||
python -m pip install mypy pytest-cov -r requirements.txt
|
||||
# FIXME: #4052 fix mypy errors in the exclude directories and remove them below
|
||||
- run: mypy --ignore-missing-imports
|
||||
--exclude '(ciphers|conversions|data_structures|digital_image_processing|dynamic_programming|graphs|linear_algebra|maths|matrix|other|project_euler|scripts|searches|strings*)/$' .
|
||||
--exclude '(conversions|data_structures|digital_image_processing|dynamic_programming|graphs|linear_algebra|maths|matrix|other|project_euler|scripts|searches|strings*)/$' .
|
||||
- name: Run tests
|
||||
run: pytest --doctest-modules --ignore=project_euler/ --ignore=scripts/ --cov-report=term-missing:skip-covered --cov=. .
|
||||
- if: ${{ success() }}
|
||||
|
|
|
@ -241,9 +241,7 @@ class DiffieHellman:
|
|||
return sha256(str(shared_key).encode()).hexdigest()
|
||||
|
||||
@staticmethod
|
||||
def is_valid_public_key_static(
|
||||
local_private_key_str: str, remote_public_key_str: str, prime: int
|
||||
) -> bool:
|
||||
def is_valid_public_key_static(remote_public_key_str: int, prime: int) -> bool:
|
||||
# check if the other public key is valid based on NIST SP800-56
|
||||
if 2 <= remote_public_key_str and remote_public_key_str <= prime - 2:
|
||||
if pow(remote_public_key_str, (prime - 1) // 2, prime) == 1:
|
||||
|
@ -257,9 +255,7 @@ class DiffieHellman:
|
|||
local_private_key = int(local_private_key_str, base=16)
|
||||
remote_public_key = int(remote_public_key_str, base=16)
|
||||
prime = primes[group]["prime"]
|
||||
if not DiffieHellman.is_valid_public_key_static(
|
||||
local_private_key, remote_public_key, prime
|
||||
):
|
||||
if not DiffieHellman.is_valid_public_key_static(remote_public_key, prime):
|
||||
raise ValueError("Invalid public key")
|
||||
shared_key = pow(remote_public_key, local_private_key, prime)
|
||||
return sha256(str(shared_key).encode()).hexdigest()
|
||||
|
|
|
@ -64,13 +64,12 @@ class HillCipher:
|
|||
|
||||
to_int = numpy.vectorize(lambda x: round(x))
|
||||
|
||||
def __init__(self, encrypt_key: int):
|
||||
def __init__(self, encrypt_key: numpy.ndarray) -> None:
|
||||
"""
|
||||
encrypt_key is an NxN numpy array
|
||||
"""
|
||||
self.encrypt_key = self.modulus(encrypt_key) # mod36 calc's on the encrypt key
|
||||
self.check_determinant() # validate the determinant of the encryption key
|
||||
self.decrypt_key = None
|
||||
self.break_key = encrypt_key.shape[0]
|
||||
|
||||
def replace_letters(self, letter: str) -> int:
|
||||
|
@ -139,8 +138,8 @@ class HillCipher:
|
|||
|
||||
for i in range(0, len(text) - self.break_key + 1, self.break_key):
|
||||
batch = text[i : i + self.break_key]
|
||||
batch_vec = [self.replace_letters(char) for char in batch]
|
||||
batch_vec = numpy.array([batch_vec]).T
|
||||
vec = [self.replace_letters(char) for char in batch]
|
||||
batch_vec = numpy.array([vec]).T
|
||||
batch_encrypted = self.modulus(self.encrypt_key.dot(batch_vec)).T.tolist()[
|
||||
0
|
||||
]
|
||||
|
@ -151,7 +150,7 @@ class HillCipher:
|
|||
|
||||
return encrypted
|
||||
|
||||
def make_decrypt_key(self):
|
||||
def make_decrypt_key(self) -> numpy.ndarray:
|
||||
"""
|
||||
>>> hill_cipher = HillCipher(numpy.array([[2, 5], [1, 6]]))
|
||||
>>> hill_cipher.make_decrypt_key()
|
||||
|
@ -184,17 +183,15 @@ class HillCipher:
|
|||
>>> hill_cipher.decrypt('85FF00')
|
||||
'HELLOO'
|
||||
"""
|
||||
self.decrypt_key = self.make_decrypt_key()
|
||||
decrypt_key = self.make_decrypt_key()
|
||||
text = self.process_text(text.upper())
|
||||
decrypted = ""
|
||||
|
||||
for i in range(0, len(text) - self.break_key + 1, self.break_key):
|
||||
batch = text[i : i + self.break_key]
|
||||
batch_vec = [self.replace_letters(char) for char in batch]
|
||||
batch_vec = numpy.array([batch_vec]).T
|
||||
batch_decrypted = self.modulus(self.decrypt_key.dot(batch_vec)).T.tolist()[
|
||||
0
|
||||
]
|
||||
vec = [self.replace_letters(char) for char in batch]
|
||||
batch_vec = numpy.array([vec]).T
|
||||
batch_decrypted = self.modulus(decrypt_key.dot(batch_vec)).T.tolist()[0]
|
||||
decrypted_batch = "".join(
|
||||
self.replace_digits(num) for num in batch_decrypted
|
||||
)
|
||||
|
@ -203,12 +200,12 @@ class HillCipher:
|
|||
return decrypted
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
N = int(input("Enter the order of the encryption key: "))
|
||||
hill_matrix = []
|
||||
|
||||
print("Enter each row of the encryption key with space separated integers")
|
||||
for i in range(N):
|
||||
for _ in range(N):
|
||||
row = [int(x) for x in input().split()]
|
||||
hill_matrix.append(row)
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ def mixed_keyword(key: str = "college", pt: str = "UNIVERSITY") -> str:
|
|||
# print(temp)
|
||||
alpha = []
|
||||
modalpha = []
|
||||
for i in range(65, 91):
|
||||
t = chr(i)
|
||||
for j in range(65, 91):
|
||||
t = chr(j)
|
||||
alpha.append(t)
|
||||
if t not in temp:
|
||||
temp.append(t)
|
||||
|
@ -38,23 +38,23 @@ def mixed_keyword(key: str = "college", pt: str = "UNIVERSITY") -> str:
|
|||
r = int(26 / 4)
|
||||
# print(r)
|
||||
k = 0
|
||||
for i in range(r):
|
||||
t = []
|
||||
for _ in range(r):
|
||||
s = []
|
||||
for j in range(len_temp):
|
||||
t.append(temp[k])
|
||||
s.append(temp[k])
|
||||
if not (k < 25):
|
||||
break
|
||||
k += 1
|
||||
modalpha.append(t)
|
||||
modalpha.append(s)
|
||||
# print(modalpha)
|
||||
d = {}
|
||||
j = 0
|
||||
k = 0
|
||||
for j in range(len_temp):
|
||||
for i in modalpha:
|
||||
if not (len(i) - 1 >= j):
|
||||
for m in modalpha:
|
||||
if not (len(m) - 1 >= j):
|
||||
break
|
||||
d[alpha[k]] = i[j]
|
||||
d[alpha[k]] = m[j]
|
||||
if not k < 25:
|
||||
break
|
||||
k += 1
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
from typing import Literal
|
||||
|
||||
LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
|
||||
def translate_message(key, message, mode):
|
||||
def translate_message(
|
||||
key: str, message: str, mode: Literal["encrypt", "decrypt"]
|
||||
) -> str:
|
||||
"""
|
||||
>>> translate_message("QWERTYUIOPASDFGHJKLZXCVBNM","Hello World","encrypt")
|
||||
'Pcssi Bidsm'
|
||||
|
@ -40,7 +44,7 @@ def decrypt_message(key: str, message: str) -> str:
|
|||
return translate_message(key, message, "decrypt")
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
message = "Hello World"
|
||||
key = "QWERTYUIOPASDFGHJKLZXCVBNM"
|
||||
mode = "decrypt" # set to 'encrypt' or 'decrypt'
|
||||
|
|
|
@ -83,7 +83,7 @@ def decrypt(message: str) -> str:
|
|||
return decipher
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
message = "Morse code here"
|
||||
result = encrypt(message.upper())
|
||||
print(result)
|
||||
|
|
|
@ -2,7 +2,8 @@ import random
|
|||
|
||||
|
||||
class Onepad:
|
||||
def encrypt(self, text: str) -> ([str], [int]):
|
||||
@staticmethod
|
||||
def encrypt(text: str) -> tuple[list[int], list[int]]:
|
||||
"""Function to encrypt text using pseudo-random numbers"""
|
||||
plain = [ord(i) for i in text]
|
||||
key = []
|
||||
|
@ -14,14 +15,14 @@ class Onepad:
|
|||
key.append(k)
|
||||
return cipher, key
|
||||
|
||||
def decrypt(self, cipher: [str], key: [int]) -> str:
|
||||
@staticmethod
|
||||
def decrypt(cipher: list[int], key: list[int]) -> str:
|
||||
"""Function to decrypt text using pseudo-random numbers."""
|
||||
plain = []
|
||||
for i in range(len(key)):
|
||||
p = int((cipher[i] - (key[i]) ** 2) / key[i])
|
||||
plain.append(chr(p))
|
||||
plain = "".join([i for i in plain])
|
||||
return plain
|
||||
return "".join([i for i in plain])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import itertools
|
||||
import string
|
||||
from typing import Generator, Iterable
|
||||
|
||||
|
||||
def chunker(seq, size):
|
||||
def chunker(seq: Iterable[str], size: int) -> Generator[tuple[str, ...], None, None]:
|
||||
it = iter(seq)
|
||||
while True:
|
||||
chunk = tuple(itertools.islice(it, size))
|
||||
|
@ -37,7 +38,7 @@ def prepare_input(dirty: str) -> str:
|
|||
return clean
|
||||
|
||||
|
||||
def generate_table(key: str) -> [str]:
|
||||
def generate_table(key: str) -> list[str]:
|
||||
|
||||
# I and J are used interchangeably to allow
|
||||
# us to use a 5x5 table (25 letters)
|
||||
|
|
|
@ -28,7 +28,7 @@ alphabet = {
|
|||
}
|
||||
|
||||
|
||||
def generate_table(key: str) -> [(str, str)]:
|
||||
def generate_table(key: str) -> list[tuple[str, str]]:
|
||||
"""
|
||||
>>> generate_table('marvin') # doctest: +NORMALIZE_WHITESPACE
|
||||
[('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'),
|
||||
|
@ -60,30 +60,21 @@ def decrypt(key: str, words: str) -> str:
|
|||
return encrypt(key, words)
|
||||
|
||||
|
||||
def get_position(table: [(str, str)], char: str) -> (int, int) or (None, None):
|
||||
def get_position(table: tuple[str, str], char: str) -> tuple[int, int]:
|
||||
"""
|
||||
>>> table = [
|
||||
... ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'),
|
||||
... ('ABCDEFGHIJKLM', 'STUVWXYZNOPQR'), ('ABCDEFGHIJKLM', 'QRSTUVWXYZNOP'),
|
||||
... ('ABCDEFGHIJKLM', 'WXYZNOPQRSTUV'), ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST')]
|
||||
>>> get_position(table, 'A')
|
||||
(None, None)
|
||||
>>> get_position(generate_table('marvin')[0], 'M')
|
||||
(0, 12)
|
||||
"""
|
||||
if char in table[0]:
|
||||
row = 0
|
||||
else:
|
||||
row = 1 if char in table[1] else -1
|
||||
return (None, None) if row == -1 else (row, table[row].index(char))
|
||||
# `char` is either in the 0th row or the 1st row
|
||||
row = 0 if char in table[0] else 1
|
||||
col = table[row].index(char)
|
||||
return row, col
|
||||
|
||||
|
||||
def get_opponent(table: [(str, str)], char: str) -> str:
|
||||
def get_opponent(table: tuple[str, str], char: str) -> str:
|
||||
"""
|
||||
>>> table = [
|
||||
... ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'),
|
||||
... ('ABCDEFGHIJKLM', 'STUVWXYZNOPQR'), ('ABCDEFGHIJKLM', 'QRSTUVWXYZNOP'),
|
||||
... ('ABCDEFGHIJKLM', 'WXYZNOPQRSTUV'), ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST')]
|
||||
>>> get_opponent(table, 'A')
|
||||
'A'
|
||||
>>> get_opponent(generate_table('marvin')[0], 'M')
|
||||
'T'
|
||||
"""
|
||||
row, col = get_position(table, char.upper())
|
||||
if row == 1:
|
||||
|
@ -97,14 +88,16 @@ if __name__ == "__main__":
|
|||
|
||||
doctest.testmod() # Fist ensure that all our tests are passing...
|
||||
"""
|
||||
ENTER KEY: marvin
|
||||
ENTER TEXT TO ENCRYPT: jessica
|
||||
ENCRYPTED: QRACRWU
|
||||
DECRYPTED WITH KEY: JESSICA
|
||||
Demo:
|
||||
|
||||
Enter key: marvin
|
||||
Enter text to encrypt: jessica
|
||||
Encrypted: QRACRWU
|
||||
Decrypted with key: JESSICA
|
||||
"""
|
||||
key = input("ENTER KEY: ").strip()
|
||||
text = input("ENTER TEXT TO ENCRYPT: ").strip()
|
||||
key = input("Enter key: ").strip()
|
||||
text = input("Enter text to encrypt: ").strip()
|
||||
cipher_text = encrypt(key, text)
|
||||
|
||||
print(f"ENCRYPTED: {cipher_text}")
|
||||
print(f"DECRYPTED WITH KEY: {decrypt(key, cipher_text)}")
|
||||
print(f"Encrypted: {cipher_text}")
|
||||
print(f"Decrypted with key: {decrypt(key, cipher_text)}")
|
||||
|
|
|
@ -20,7 +20,7 @@ def encrypt(input_string: str, key: int) -> str:
|
|||
...
|
||||
TypeError: sequence item 0: expected str instance, int found
|
||||
"""
|
||||
grid = [[] for _ in range(key)]
|
||||
temp_grid: list[list[str]] = [[] for _ in range(key)]
|
||||
lowest = key - 1
|
||||
|
||||
if key <= 0:
|
||||
|
@ -31,8 +31,8 @@ def encrypt(input_string: str, key: int) -> str:
|
|||
for position, character in enumerate(input_string):
|
||||
num = position % (lowest * 2) # puts it in bounds
|
||||
num = min(num, lowest * 2 - num) # creates zigzag pattern
|
||||
grid[num].append(character)
|
||||
grid = ["".join(row) for row in grid]
|
||||
temp_grid[num].append(character)
|
||||
grid = ["".join(row) for row in temp_grid]
|
||||
output_string = "".join(grid)
|
||||
|
||||
return output_string
|
||||
|
@ -63,7 +63,7 @@ def decrypt(input_string: str, key: int) -> str:
|
|||
if key == 1:
|
||||
return input_string
|
||||
|
||||
temp_grid = [[] for _ in range(key)] # generates template
|
||||
temp_grid: list[list[str]] = [[] for _ in range(key)] # generates template
|
||||
for position in range(len(input_string)):
|
||||
num = position % (lowest * 2) # puts it in bounds
|
||||
num = min(num, lowest * 2 - num) # creates zigzag pattern
|
||||
|
@ -84,7 +84,7 @@ def decrypt(input_string: str, key: int) -> str:
|
|||
return output_string
|
||||
|
||||
|
||||
def bruteforce(input_string: str) -> dict:
|
||||
def bruteforce(input_string: str) -> dict[int, str]:
|
||||
"""Uses decrypt function by guessing every key
|
||||
|
||||
>>> bruteforce("HWe olordll")[4]
|
||||
|
|
|
@ -20,7 +20,7 @@ def dencrypt(s: str, n: int = 13) -> str:
|
|||
return out
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
s0 = input("Enter message: ")
|
||||
|
||||
s1 = dencrypt(s0, 13)
|
||||
|
|
|
@ -7,7 +7,114 @@ DEFAULT_BLOCK_SIZE = 128
|
|||
BYTE_SIZE = 256
|
||||
|
||||
|
||||
def main():
|
||||
def get_blocks_from_text(
|
||||
message: str, block_size: int = DEFAULT_BLOCK_SIZE
|
||||
) -> list[int]:
|
||||
message_bytes = message.encode("ascii")
|
||||
|
||||
block_ints = []
|
||||
for block_start in range(0, len(message_bytes), block_size):
|
||||
block_int = 0
|
||||
for i in range(block_start, min(block_start + block_size, len(message_bytes))):
|
||||
block_int += message_bytes[i] * (BYTE_SIZE ** (i % block_size))
|
||||
block_ints.append(block_int)
|
||||
return block_ints
|
||||
|
||||
|
||||
def get_text_from_blocks(
|
||||
block_ints: list[int], message_length: int, block_size: int = DEFAULT_BLOCK_SIZE
|
||||
) -> str:
|
||||
message: list[str] = []
|
||||
for block_int in block_ints:
|
||||
block_message: list[str] = []
|
||||
for i in range(block_size - 1, -1, -1):
|
||||
if len(message) + i < message_length:
|
||||
ascii_number = block_int // (BYTE_SIZE ** i)
|
||||
block_int = block_int % (BYTE_SIZE ** i)
|
||||
block_message.insert(0, chr(ascii_number))
|
||||
message.extend(block_message)
|
||||
return "".join(message)
|
||||
|
||||
|
||||
def encrypt_message(
|
||||
message: str, key: tuple[int, int], blockSize: int = DEFAULT_BLOCK_SIZE
|
||||
) -> list[int]:
|
||||
encrypted_blocks = []
|
||||
n, e = key
|
||||
|
||||
for block in get_blocks_from_text(message, blockSize):
|
||||
encrypted_blocks.append(pow(block, e, n))
|
||||
return encrypted_blocks
|
||||
|
||||
|
||||
def decrypt_message(
|
||||
encrypted_blocks: list[int],
|
||||
message_length: int,
|
||||
key: tuple[int, int],
|
||||
block_size: int = DEFAULT_BLOCK_SIZE,
|
||||
) -> str:
|
||||
decrypted_blocks = []
|
||||
n, d = key
|
||||
for block in encrypted_blocks:
|
||||
decrypted_blocks.append(pow(block, d, n))
|
||||
return get_text_from_blocks(decrypted_blocks, message_length, block_size)
|
||||
|
||||
|
||||
def read_key_file(key_filename: str) -> tuple[int, int, int]:
|
||||
with open(key_filename) as fo:
|
||||
content = fo.read()
|
||||
key_size, n, EorD = content.split(",")
|
||||
return (int(key_size), int(n), int(EorD))
|
||||
|
||||
|
||||
def encrypt_and_write_to_file(
|
||||
message_filename: str,
|
||||
key_filename: str,
|
||||
message: str,
|
||||
block_size: int = DEFAULT_BLOCK_SIZE,
|
||||
) -> str:
|
||||
key_size, n, e = read_key_file(key_filename)
|
||||
if key_size < block_size * 8:
|
||||
sys.exit(
|
||||
"ERROR: Block size is %s bits and key size is %s bits. The RSA cipher "
|
||||
"requires the block size to be equal to or greater than the key size. "
|
||||
"Either decrease the block size or use different keys."
|
||||
% (block_size * 8, key_size)
|
||||
)
|
||||
|
||||
encrypted_blocks = [str(i) for i in encrypt_message(message, (n, e), block_size)]
|
||||
|
||||
encrypted_content = ",".join(encrypted_blocks)
|
||||
encrypted_content = f"{len(message)}_{block_size}_{encrypted_content}"
|
||||
with open(message_filename, "w") as fo:
|
||||
fo.write(encrypted_content)
|
||||
return encrypted_content
|
||||
|
||||
|
||||
def read_from_file_and_decrypt(message_filename: str, key_filename: str) -> str:
|
||||
key_size, n, d = read_key_file(key_filename)
|
||||
with open(message_filename) as fo:
|
||||
content = fo.read()
|
||||
message_length_str, block_size_str, encrypted_message = content.split("_")
|
||||
message_length = int(message_length_str)
|
||||
block_size = int(block_size_str)
|
||||
|
||||
if key_size < block_size * 8:
|
||||
sys.exit(
|
||||
"ERROR: Block size is %s bits and key size is %s bits. The RSA cipher "
|
||||
"requires the block size to be equal to or greater than the key size. "
|
||||
"Did you specify the correct key file and encrypted file?"
|
||||
% (block_size * 8, key_size)
|
||||
)
|
||||
|
||||
encrypted_blocks = []
|
||||
for block in encrypted_message.split(","):
|
||||
encrypted_blocks.append(int(block))
|
||||
|
||||
return decrypt_message(encrypted_blocks, message_length, (n, d), block_size)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
filename = "encrypted_file.txt"
|
||||
response = input(r"Encrypt\Decrypt [e\d]: ")
|
||||
|
||||
|
@ -21,130 +128,23 @@ def main():
|
|||
rkg.makeKeyFiles("rsa", 1024)
|
||||
|
||||
message = input("\nEnter message: ")
|
||||
pubKeyFilename = "rsa_pubkey.txt"
|
||||
pubkey_filename = "rsa_pubkey.txt"
|
||||
print("Encrypting and writing to %s..." % (filename))
|
||||
encryptedText = encryptAndWriteToFile(filename, pubKeyFilename, message)
|
||||
encryptedText = encrypt_and_write_to_file(filename, pubkey_filename, message)
|
||||
|
||||
print("\nEncrypted text:")
|
||||
print(encryptedText)
|
||||
|
||||
elif mode == "decrypt":
|
||||
privKeyFilename = "rsa_privkey.txt"
|
||||
privkey_filename = "rsa_privkey.txt"
|
||||
print("Reading from %s and decrypting..." % (filename))
|
||||
decryptedText = readFromFileAndDecrypt(filename, privKeyFilename)
|
||||
decrypted_text = read_from_file_and_decrypt(filename, privkey_filename)
|
||||
print("writing decryption to rsa_decryption.txt...")
|
||||
with open("rsa_decryption.txt", "w") as dec:
|
||||
dec.write(decryptedText)
|
||||
dec.write(decrypted_text)
|
||||
|
||||
print("\nDecryption:")
|
||||
print(decryptedText)
|
||||
|
||||
|
||||
def getBlocksFromText(message: int, blockSize: int = DEFAULT_BLOCK_SIZE) -> [int]:
|
||||
messageBytes = message.encode("ascii")
|
||||
|
||||
blockInts = []
|
||||
for blockStart in range(0, len(messageBytes), blockSize):
|
||||
blockInt = 0
|
||||
for i in range(blockStart, min(blockStart + blockSize, len(messageBytes))):
|
||||
blockInt += messageBytes[i] * (BYTE_SIZE ** (i % blockSize))
|
||||
blockInts.append(blockInt)
|
||||
return blockInts
|
||||
|
||||
|
||||
def getTextFromBlocks(
|
||||
blockInts: [int], messageLength: int, blockSize: int = DEFAULT_BLOCK_SIZE
|
||||
) -> str:
|
||||
message = []
|
||||
for blockInt in blockInts:
|
||||
blockMessage = []
|
||||
for i in range(blockSize - 1, -1, -1):
|
||||
if len(message) + i < messageLength:
|
||||
asciiNumber = blockInt // (BYTE_SIZE ** i)
|
||||
blockInt = blockInt % (BYTE_SIZE ** i)
|
||||
blockMessage.insert(0, chr(asciiNumber))
|
||||
message.extend(blockMessage)
|
||||
return "".join(message)
|
||||
|
||||
|
||||
def encryptMessage(
|
||||
message: str, key: (int, int), blockSize: int = DEFAULT_BLOCK_SIZE
|
||||
) -> [int]:
|
||||
encryptedBlocks = []
|
||||
n, e = key
|
||||
|
||||
for block in getBlocksFromText(message, blockSize):
|
||||
encryptedBlocks.append(pow(block, e, n))
|
||||
return encryptedBlocks
|
||||
|
||||
|
||||
def decryptMessage(
|
||||
encryptedBlocks: [int],
|
||||
messageLength: int,
|
||||
key: (int, int),
|
||||
blockSize: int = DEFAULT_BLOCK_SIZE,
|
||||
) -> str:
|
||||
decryptedBlocks = []
|
||||
n, d = key
|
||||
for block in encryptedBlocks:
|
||||
decryptedBlocks.append(pow(block, d, n))
|
||||
return getTextFromBlocks(decryptedBlocks, messageLength, blockSize)
|
||||
|
||||
|
||||
def readKeyFile(keyFilename: str) -> (int, int, int):
|
||||
with open(keyFilename) as fo:
|
||||
content = fo.read()
|
||||
keySize, n, EorD = content.split(",")
|
||||
return (int(keySize), int(n), int(EorD))
|
||||
|
||||
|
||||
def encryptAndWriteToFile(
|
||||
messageFilename: str,
|
||||
keyFilename: str,
|
||||
message: str,
|
||||
blockSize: int = DEFAULT_BLOCK_SIZE,
|
||||
) -> str:
|
||||
keySize, n, e = readKeyFile(keyFilename)
|
||||
if keySize < blockSize * 8:
|
||||
sys.exit(
|
||||
"ERROR: Block size is %s bits and key size is %s bits. The RSA cipher "
|
||||
"requires the block size to be equal to or greater than the key size. "
|
||||
"Either decrease the block size or use different keys."
|
||||
% (blockSize * 8, keySize)
|
||||
)
|
||||
|
||||
encryptedBlocks = encryptMessage(message, (n, e), blockSize)
|
||||
|
||||
for i in range(len(encryptedBlocks)):
|
||||
encryptedBlocks[i] = str(encryptedBlocks[i])
|
||||
encryptedContent = ",".join(encryptedBlocks)
|
||||
encryptedContent = f"{len(message)}_{blockSize}_{encryptedContent}"
|
||||
with open(messageFilename, "w") as fo:
|
||||
fo.write(encryptedContent)
|
||||
return encryptedContent
|
||||
|
||||
|
||||
def readFromFileAndDecrypt(messageFilename: str, keyFilename: str) -> str:
|
||||
keySize, n, d = readKeyFile(keyFilename)
|
||||
with open(messageFilename) as fo:
|
||||
content = fo.read()
|
||||
messageLength, blockSize, encryptedMessage = content.split("_")
|
||||
messageLength = int(messageLength)
|
||||
blockSize = int(blockSize)
|
||||
|
||||
if keySize < blockSize * 8:
|
||||
sys.exit(
|
||||
"ERROR: Block size is %s bits and key size is %s bits. The RSA cipher "
|
||||
"requires the block size to be equal to or greater than the key size. "
|
||||
"Did you specify the correct key file and encrypted file?"
|
||||
% (blockSize * 8, keySize)
|
||||
)
|
||||
|
||||
encryptedBlocks = []
|
||||
for block in encryptedMessage.split(","):
|
||||
encryptedBlocks.append(int(block))
|
||||
|
||||
return decryptMessage(encryptedBlocks, messageLength, (n, d), blockSize)
|
||||
print(decrypted_text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -13,7 +13,7 @@ import math
|
|||
import random
|
||||
|
||||
|
||||
def rsafactor(d: int, e: int, N: int) -> [int]:
|
||||
def rsafactor(d: int, e: int, N: int) -> list[int]:
|
||||
"""
|
||||
This function returns the factors of N, where p*q=N
|
||||
Return: [p, q]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import random
|
||||
import string
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class ShuffledShiftCipher:
|
||||
|
@ -26,7 +27,7 @@ class ShuffledShiftCipher:
|
|||
cip2 = ShuffledShiftCipher()
|
||||
"""
|
||||
|
||||
def __init__(self, passcode: str = None):
|
||||
def __init__(self, passcode: Optional[str] = None) -> None:
|
||||
"""
|
||||
Initializes a cipher object with a passcode as it's entity
|
||||
Note: No new passcode is generated if user provides a passcode
|
||||
|
@ -36,13 +37,13 @@ class ShuffledShiftCipher:
|
|||
self.__key_list = self.__make_key_list()
|
||||
self.__shift_key = self.__make_shift_key()
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
:return: passcode of the cipher object
|
||||
"""
|
||||
return "Passcode is: " + "".join(self.__passcode)
|
||||
|
||||
def __neg_pos(self, iterlist: list) -> list:
|
||||
def __neg_pos(self, iterlist: list[int]) -> list[int]:
|
||||
"""
|
||||
Mutates the list by changing the sign of each alternate element
|
||||
|
||||
|
@ -54,7 +55,7 @@ class ShuffledShiftCipher:
|
|||
iterlist[i] *= -1
|
||||
return iterlist
|
||||
|
||||
def __passcode_creator(self) -> list:
|
||||
def __passcode_creator(self) -> list[str]:
|
||||
"""
|
||||
Creates a random password from the selection buffer of
|
||||
1. uppercase letters of the English alphabet
|
||||
|
@ -65,10 +66,10 @@ class ShuffledShiftCipher:
|
|||
:return: a password of a random length between 10 to 20
|
||||
"""
|
||||
choices = string.ascii_letters + string.digits
|
||||
password = [random.choice(choices) for i in range(random.randint(10, 20))]
|
||||
password = [random.choice(choices) for _ in range(random.randint(10, 20))]
|
||||
return password
|
||||
|
||||
def __make_key_list(self) -> list:
|
||||
def __make_key_list(self) -> list[str]:
|
||||
"""
|
||||
Shuffles the ordered character choices by pivoting at breakpoints
|
||||
Breakpoints are the set of characters in the passcode
|
||||
|
@ -99,7 +100,7 @@ class ShuffledShiftCipher:
|
|||
# creates points known as breakpoints to break the key_list_options at those
|
||||
# points and pivot each substring
|
||||
breakpoints = sorted(set(self.__passcode))
|
||||
temp_list = []
|
||||
temp_list: list[str] = []
|
||||
|
||||
# algorithm for creating a new shuffled list, keys_l, out of key_list_options
|
||||
for i in key_list_options:
|
||||
|
@ -109,7 +110,7 @@ class ShuffledShiftCipher:
|
|||
# keys_l
|
||||
if i in breakpoints or i == key_list_options[-1]:
|
||||
keys_l.extend(temp_list[::-1])
|
||||
temp_list = []
|
||||
temp_list.clear()
|
||||
|
||||
# returning a shuffled keys_l to prevent brute force guessing of shift key
|
||||
return keys_l
|
||||
|
@ -167,7 +168,7 @@ class ShuffledShiftCipher:
|
|||
return encoded_message
|
||||
|
||||
|
||||
def test_end_to_end(msg: str = "Hello, this is a modified Caesar cipher"):
|
||||
def test_end_to_end(msg: str = "Hello, this is a modified Caesar cipher") -> str:
|
||||
"""
|
||||
>>> test_end_to_end()
|
||||
'Hello, this is a modified Caesar cipher'
|
||||
|
|
|
@ -15,7 +15,7 @@ def remove_duplicates(key: str) -> str:
|
|||
return key_no_dups
|
||||
|
||||
|
||||
def create_cipher_map(key: str) -> dict:
|
||||
def create_cipher_map(key: str) -> dict[str, str]:
|
||||
"""
|
||||
Returns a cipher map given a keyword.
|
||||
:param key: keyword to use
|
||||
|
@ -40,7 +40,7 @@ def create_cipher_map(key: str) -> dict:
|
|||
return cipher_alphabet
|
||||
|
||||
|
||||
def encipher(message: str, cipher_map: dict) -> str:
|
||||
def encipher(message: str, cipher_map: dict[str, str]) -> str:
|
||||
"""
|
||||
Enciphers a message given a cipher map.
|
||||
:param message: Message to encipher
|
||||
|
@ -52,7 +52,7 @@ def encipher(message: str, cipher_map: dict) -> str:
|
|||
return "".join(cipher_map.get(ch, ch) for ch in message.upper())
|
||||
|
||||
|
||||
def decipher(message: str, cipher_map: dict) -> str:
|
||||
def decipher(message: str, cipher_map: dict[str, str]) -> str:
|
||||
"""
|
||||
Deciphers a message given a cipher map
|
||||
:param message: Message to decipher
|
||||
|
@ -67,7 +67,7 @@ def decipher(message: str, cipher_map: dict) -> str:
|
|||
return "".join(rev_cipher_map.get(ch, ch) for ch in message.upper())
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
"""
|
||||
Handles I/O
|
||||
:return: void
|
||||
|
|
|
@ -4,7 +4,7 @@ import sys
|
|||
LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
message = input("Enter message: ")
|
||||
key = "LFWOAYUISVKMNXPBDCRJTQEGHZ"
|
||||
resp = input("Encrypt/Decrypt [e/d]: ")
|
||||
|
@ -68,7 +68,7 @@ def translateMessage(key: str, message: str, mode: str) -> str:
|
|||
return translated
|
||||
|
||||
|
||||
def getRandomKey():
|
||||
def getRandomKey() -> str:
|
||||
key = list(LETTERS)
|
||||
random.shuffle(key)
|
||||
return "".join(key)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# https://en.wikipedia.org/wiki/Trifid_cipher
|
||||
|
||||
|
||||
def __encryptPart(messagePart: str, character2Number: dict) -> str:
|
||||
def __encryptPart(messagePart: str, character2Number: dict[str, str]) -> str:
|
||||
one, two, three = "", "", ""
|
||||
tmp = []
|
||||
|
||||
|
@ -16,7 +16,9 @@ def __encryptPart(messagePart: str, character2Number: dict) -> str:
|
|||
return one + two + three
|
||||
|
||||
|
||||
def __decryptPart(messagePart: str, character2Number: dict) -> (str, str, str):
|
||||
def __decryptPart(
|
||||
messagePart: str, character2Number: dict[str, str]
|
||||
) -> tuple[str, str, str]:
|
||||
tmp, thisPart = "", ""
|
||||
result = []
|
||||
|
||||
|
@ -32,7 +34,9 @@ def __decryptPart(messagePart: str, character2Number: dict) -> (str, str, str):
|
|||
return result[0], result[1], result[2]
|
||||
|
||||
|
||||
def __prepare(message: str, alphabet: str) -> (str, str, dict, dict):
|
||||
def __prepare(
|
||||
message: str, alphabet: str
|
||||
) -> tuple[str, str, dict[str, str], dict[str, str]]:
|
||||
# Validate message and alphabet, set to upper and remove spaces
|
||||
alphabet = alphabet.replace(" ", "").upper()
|
||||
message = message.replace(" ", "").upper()
|
||||
|
|
|
@ -8,7 +8,7 @@ text. The type of transposition cipher demonstrated under is the ROUTE cipher.
|
|||
"""
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
message = input("Enter message: ")
|
||||
key = int(input("Enter key [2-%s]: " % (len(message) - 1)))
|
||||
mode = input("Encryption/Decryption [e/d]: ")
|
||||
|
|
|
@ -5,7 +5,7 @@ import time
|
|||
from . import transposition_cipher as transCipher
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
inputFile = "Prehistoric Men.txt"
|
||||
outputFile = "Output.txt"
|
||||
key = int(input("Enter key: "))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
|
||||
def main():
|
||||
def main() -> None:
|
||||
message = input("Enter message: ")
|
||||
key = input("Enter key [alphanumeric]: ")
|
||||
mode = input("Encrypt/Decrypt [e/d]: ")
|
||||
|
|
|
@ -28,7 +28,7 @@ class XORCipher:
|
|||
# private field
|
||||
self.__key = key
|
||||
|
||||
def encrypt(self, content: str, key: int) -> [str]:
|
||||
def encrypt(self, content: str, key: int) -> list[str]:
|
||||
"""
|
||||
input: 'content' of type string and 'key' of type int
|
||||
output: encrypted string 'content' as a list of chars
|
||||
|
@ -53,7 +53,7 @@ class XORCipher:
|
|||
|
||||
return ans
|
||||
|
||||
def decrypt(self, content: str, key: int) -> [str]:
|
||||
def decrypt(self, content: str, key: int) -> list[str]:
|
||||
"""
|
||||
input: 'content' of type list and 'key' of type int
|
||||
output: decrypted string 'content' as a list of chars
|
||||
|
|
Loading…
Reference in New Issue
Block a user