From e96ae3dc924b14f3f8c17bd5beea0d65bed29e1a Mon Sep 17 00:00:00 2001 From: aryan1165 Date: Thu, 28 Sep 2023 21:40:04 +0530 Subject: [PATCH 01/12] Added permutation_cipher.py --- ciphers/permutation_cipher.py | 130 ++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 ciphers/permutation_cipher.py diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py new file mode 100644 index 000000000000..5991b6ccc4d0 --- /dev/null +++ b/ciphers/permutation_cipher.py @@ -0,0 +1,130 @@ +""" +The Permutation Cipher, implemented above, is a simple encryption +technique that rearranges the characters in a message based on a secret key. +It divides the message into blocks and applies a permutation to the characters +within each block according to the key. The key is a sequence of unique integers +that determine the order of character rearrangement. For more info read:- +https://www.nku.edu/~christensen/1402%20permutation%20ciphers.pdf + +""" +import random + + +def generate_valid_block_size(message_length) -> int: + """ + Generate a valid block size that is a factor of the message length. + + Args: + message_length (int): The length of the message. + + Returns: + int: A valid block size. + + Example: + generate_valid_block_size(12) + 3 + """ + while True: + block_size = random.randint(2, message_length) + if message_length % block_size == 0: + return block_size + + +def generate_permutation_key(block_size) -> list: + """ + Generate a random permutation key of a specified block size. + + Args: + block_size (int): The size of each permutation block. + + Returns: + list[int]: A list containing a random permutation of digits. + + Example: + generate_permutation_key(4) + [3, 4, 1, 2] + """ + digits = list(range(1, block_size + 1)) + random.shuffle(digits) + key = digits + return key + + +def encrypt(message, key=None, block_size=None) -> tuple: + """ + Encrypt a message using a permutation cipher with block rearrangement using a key. + + Args: + message (str): The plaintext message to be encrypted. + key (list[int]): The permutation key for decryption. + block_size (int): The size of each permutation block. + + Returns: + tuple: A tuple containing the encrypted message and the encryption key. + + Example: + >>> encrypted_message, key = encrypt("HELLO WORLD") + >>> decrypted_message = decrypt(encrypted_message, key) + >>> decrypted_message + 'HELLO WORLD' + """ + message = message.upper() + message_length = len(message) + + if key is None or block_size is None: + block_size = generate_valid_block_size(message_length) + key = generate_permutation_key(block_size) + + encrypted_message = "" + + for i in range(0, message_length, block_size): + block = message[i : i + block_size] + rearranged_block = [block[digit - 1] for digit in key] + encrypted_message += "".join(rearranged_block) + + return encrypted_message, key + + +def decrypt(encrypted_message, key) -> str: + """ + Decrypt an encrypted message using a permutation cipher with block rearrangement. + + Args: + encrypted_message (str): The encrypted message. + key (list[int]): The permutation key for decryption. + + Returns: + str: The decrypted plaintext message. + + Example: + >>> encrypted_message, key = encrypt("HELLO WORLD") + >>> decrypted_message = decrypt(encrypted_message, key) + >>> decrypted_message + 'HELLO WORLD' + """ + key_length = len(key) + decrypted_message = "" + + for i in range(0, len(encrypted_message), key_length): + block = encrypted_message[i : i + key_length] + original_block = [""] * key_length + for j, digit in enumerate(key): + original_block[digit - 1] = block[j] + decrypted_message += "".join(original_block) + + return decrypted_message + + +def main() -> None: + message = "HELLO WORLD" + encrypted_message, key = encrypt(message) + + decrypted_message = decrypt(encrypted_message, key) + print(f"Decrypted message: {decrypted_message}") + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + main() From 214e45c971970d6858d1f01db83be5aee4008c2c Mon Sep 17 00:00:00 2001 From: aryan1165 Date: Sun, 1 Oct 2023 09:33:05 +0530 Subject: [PATCH 02/12] Added type hints for parameters --- ciphers/permutation_cipher.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index 5991b6ccc4d0..8fb5a218e244 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -10,7 +10,7 @@ import random -def generate_valid_block_size(message_length) -> int: +def generate_valid_block_size(message_length: int) -> int: """ Generate a valid block size that is a factor of the message length. @@ -30,7 +30,7 @@ def generate_valid_block_size(message_length) -> int: return block_size -def generate_permutation_key(block_size) -> list: +def generate_permutation_key(block_size: int) -> list: """ Generate a random permutation key of a specified block size. @@ -50,7 +50,9 @@ def generate_permutation_key(block_size) -> list: return key -def encrypt(message, key=None, block_size=None) -> tuple: +def encrypt( + message: str, key: list | None = None, block_size: int | None = None +) -> tuple: """ Encrypt a message using a permutation cipher with block rearrangement using a key. @@ -85,7 +87,7 @@ def encrypt(message, key=None, block_size=None) -> tuple: return encrypted_message, key -def decrypt(encrypted_message, key) -> str: +def decrypt(encrypted_message: str, key: list) -> str: """ Decrypt an encrypted message using a permutation cipher with block rearrangement. From c51a20ebb0ebf4d2e3446a45d6aad7c99dab0b6d Mon Sep 17 00:00:00 2001 From: aryan1165 Date: Sun, 1 Oct 2023 09:51:17 +0530 Subject: [PATCH 03/12] Added doctest in functions --- ciphers/permutation_cipher.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index 8fb5a218e244..2f6a587c1789 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -21,8 +21,8 @@ def generate_valid_block_size(message_length: int) -> int: int: A valid block size. Example: - generate_valid_block_size(12) - 3 + >>> generate_valid_block_size(2) + 2 """ while True: block_size = random.randint(2, message_length) @@ -41,8 +41,8 @@ def generate_permutation_key(block_size: int) -> list: list[int]: A list containing a random permutation of digits. Example: - generate_permutation_key(4) - [3, 4, 1, 2] + >>> generate_permutation_key(1) + [1] """ digits = list(range(1, block_size + 1)) random.shuffle(digits) @@ -118,6 +118,13 @@ def decrypt(encrypted_message: str, key: list) -> str: def main() -> None: + """ + Driver function to pass message to get encrypted, then decrypted. + + Example: + >>> main() + Decrypted message: HELLO WORLD + """ message = "HELLO WORLD" encrypted_message, key = encrypt(message) From e62f0509f3eaba90accbb794855d3635d8a820dd Mon Sep 17 00:00:00 2001 From: aryan1165 <111041731+aryan1165@users.noreply.github.com> Date: Sun, 1 Oct 2023 14:53:32 +0530 Subject: [PATCH 04/12] Update ciphers/permutation_cipher.py Ya i felt the same but held back because there is a implementation of transposition_cipher.py. But that's is different from the one i have implemented here. Co-authored-by: Tianyi Zheng --- ciphers/permutation_cipher.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index 2f6a587c1789..ccd11db3bd43 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -1,11 +1,11 @@ """ -The Permutation Cipher, implemented above, is a simple encryption -technique that rearranges the characters in a message based on a secret key. -It divides the message into blocks and applies a permutation to the characters -within each block according to the key. The key is a sequence of unique integers -that determine the order of character rearrangement. For more info read:- -https://www.nku.edu/~christensen/1402%20permutation%20ciphers.pdf +The permutation cipher, also called the transposition cipher, is a simple encryption +technique that rearranges the characters in a message based on a secret key. It +divides the message into blocks and applies a permutation to the characters within +each block according to the key. The key is a sequence of unique integers that +determine the order of character rearrangement. +For more info: https://www.nku.edu/~christensen/1402%20permutation%20ciphers.pdf """ import random From 249a763c27047020c82a6cabc398f026adaf78b8 Mon Sep 17 00:00:00 2001 From: aryan1165 <111041731+aryan1165@users.noreply.github.com> Date: Sun, 1 Oct 2023 14:53:50 +0530 Subject: [PATCH 05/12] Update ciphers/permutation_cipher.py Co-authored-by: Tianyi Zheng --- ciphers/permutation_cipher.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index ccd11db3bd43..e6fc5a432f8d 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -46,8 +46,7 @@ def generate_permutation_key(block_size: int) -> list: """ digits = list(range(1, block_size + 1)) random.shuffle(digits) - key = digits - return key + return digits def encrypt( From ccf850e2b1a290d696912f9b0f20403616a35fa1 Mon Sep 17 00:00:00 2001 From: aryan1165 <111041731+aryan1165@users.noreply.github.com> Date: Sun, 1 Oct 2023 14:54:00 +0530 Subject: [PATCH 06/12] Update ciphers/permutation_cipher.py Co-authored-by: Tianyi Zheng --- ciphers/permutation_cipher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index e6fc5a432f8d..e0b0b03d321f 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -44,7 +44,7 @@ def generate_permutation_key(block_size: int) -> list: >>> generate_permutation_key(1) [1] """ - digits = list(range(1, block_size + 1)) + digits = list(range(block_size)) random.shuffle(digits) return digits From ad2d09449bd5bd5b14d1148fa793507f33f1c8a6 Mon Sep 17 00:00:00 2001 From: aryan1165 <111041731+aryan1165@users.noreply.github.com> Date: Sun, 1 Oct 2023 14:54:17 +0530 Subject: [PATCH 07/12] Update ciphers/permutation_cipher.py Co-authored-by: Tianyi Zheng --- ciphers/permutation_cipher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index e0b0b03d321f..1b3dd06a0986 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -30,7 +30,7 @@ def generate_valid_block_size(message_length: int) -> int: return block_size -def generate_permutation_key(block_size: int) -> list: +def generate_permutation_key(block_size: int) -> list[int]: """ Generate a random permutation key of a specified block size. From 668b30f50b91a4d0d0c4e237b58ce487d7d73ea7 Mon Sep 17 00:00:00 2001 From: aryan1165 <111041731+aryan1165@users.noreply.github.com> Date: Sun, 1 Oct 2023 14:54:48 +0530 Subject: [PATCH 08/12] Update ciphers/permutation_cipher.py Co-authored-by: Tianyi Zheng --- ciphers/permutation_cipher.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index 1b3dd06a0986..d08ded733cc1 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -50,8 +50,8 @@ def generate_permutation_key(block_size: int) -> list[int]: def encrypt( - message: str, key: list | None = None, block_size: int | None = None -) -> tuple: + message: str, key: list[int] | None = None, block_size: int | None = None +) -> tuple[str, list[int]]: """ Encrypt a message using a permutation cipher with block rearrangement using a key. From 473dd863d1ee9e50653f332d8a0830b9fef3fff5 Mon Sep 17 00:00:00 2001 From: aryan1165 <111041731+aryan1165@users.noreply.github.com> Date: Sun, 1 Oct 2023 14:54:56 +0530 Subject: [PATCH 09/12] Update ciphers/permutation_cipher.py Co-authored-by: Tianyi Zheng --- ciphers/permutation_cipher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index d08ded733cc1..cfa0ef67c132 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -86,7 +86,7 @@ def encrypt( return encrypted_message, key -def decrypt(encrypted_message: str, key: list) -> str: +def decrypt(encrypted_message: str, key: list[int]) -> str: """ Decrypt an encrypted message using a permutation cipher with block rearrangement. From 8051d4405758a9d0b0973175dad7a468003b79a7 Mon Sep 17 00:00:00 2001 From: aryan1165 <111041731+aryan1165@users.noreply.github.com> Date: Sun, 1 Oct 2023 14:55:04 +0530 Subject: [PATCH 10/12] Update ciphers/permutation_cipher.py Co-authored-by: Tianyi Zheng --- ciphers/permutation_cipher.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index cfa0ef67c132..29b1d3a4d603 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -24,10 +24,11 @@ def generate_valid_block_size(message_length: int) -> int: >>> generate_valid_block_size(2) 2 """ - while True: - block_size = random.randint(2, message_length) - if message_length % block_size == 0: - return block_size + block_sizes = [ + block_size for block_size in range(2, message_length + 1) + if message_length % block_size == 0 + ] + return random.choice(block_size) def generate_permutation_key(block_size: int) -> list[int]: From 97b2cb982cfcc9d933babab2fbe35c5bd6e5e92a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 09:26:08 +0000 Subject: [PATCH 11/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- ciphers/permutation_cipher.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index 29b1d3a4d603..abb190baa168 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -25,7 +25,8 @@ def generate_valid_block_size(message_length: int) -> int: 2 """ block_sizes = [ - block_size for block_size in range(2, message_length + 1) + block_size + for block_size in range(2, message_length + 1) if message_length % block_size == 0 ] return random.choice(block_size) From 9e0daad415a8208fb8d7f15a5b3bbbe7c131d641 Mon Sep 17 00:00:00 2001 From: aryan1165 Date: Sun, 1 Oct 2023 15:17:18 +0530 Subject: [PATCH 12/12] Changes --- ciphers/permutation_cipher.py | 49 +++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/ciphers/permutation_cipher.py b/ciphers/permutation_cipher.py index 2f6a587c1789..c27f424f2b40 100644 --- a/ciphers/permutation_cipher.py +++ b/ciphers/permutation_cipher.py @@ -1,10 +1,10 @@ """ -The Permutation Cipher, implemented above, is a simple encryption -technique that rearranges the characters in a message based on a secret key. -It divides the message into blocks and applies a permutation to the characters -within each block according to the key. The key is a sequence of unique integers -that determine the order of character rearrangement. For more info read:- -https://www.nku.edu/~christensen/1402%20permutation%20ciphers.pdf +The permutation cipher, also called the transposition cipher, is a simple encryption +technique that rearranges the characters in a message based on a secret key. It +divides the message into blocks and applies a permutation to the characters within +each block according to the key. The key is a sequence of unique integers that +determine the order of character rearrangement. +For more info: https://www.nku.edu/~christensen/1402%20permutation%20ciphers.pdf """ import random @@ -21,16 +21,19 @@ def generate_valid_block_size(message_length: int) -> int: int: A valid block size. Example: - >>> generate_valid_block_size(2) - 2 + >>> random.seed(1) + >>> generate_valid_block_size(12) + 3 """ - while True: - block_size = random.randint(2, message_length) - if message_length % block_size == 0: - return block_size + block_sizes = [ + block_size + for block_size in range(2, message_length + 1) + if message_length % block_size == 0 + ] + return random.choice(block_sizes) -def generate_permutation_key(block_size: int) -> list: +def generate_permutation_key(block_size: int) -> list[int]: """ Generate a random permutation key of a specified block size. @@ -41,18 +44,18 @@ def generate_permutation_key(block_size: int) -> list: list[int]: A list containing a random permutation of digits. Example: - >>> generate_permutation_key(1) - [1] + >>> random.seed(0) + >>> generate_permutation_key(4) + [2, 0, 1, 3] """ - digits = list(range(1, block_size + 1)) + digits = list(range(block_size)) random.shuffle(digits) - key = digits - return key + return digits def encrypt( - message: str, key: list | None = None, block_size: int | None = None -) -> tuple: + message: str, key: list[int] | None = None, block_size: int | None = None +) -> tuple[str, list[int]]: """ Encrypt a message using a permutation cipher with block rearrangement using a key. @@ -81,13 +84,13 @@ def encrypt( for i in range(0, message_length, block_size): block = message[i : i + block_size] - rearranged_block = [block[digit - 1] for digit in key] + rearranged_block = [block[digit] for digit in key] encrypted_message += "".join(rearranged_block) return encrypted_message, key -def decrypt(encrypted_message: str, key: list) -> str: +def decrypt(encrypted_message: str, key: list[int]) -> str: """ Decrypt an encrypted message using a permutation cipher with block rearrangement. @@ -111,7 +114,7 @@ def decrypt(encrypted_message: str, key: list) -> str: block = encrypted_message[i : i + key_length] original_block = [""] * key_length for j, digit in enumerate(key): - original_block[digit - 1] = block[j] + original_block[digit] = block[j] decrypted_message += "".join(original_block) return decrypted_message