Commit b87b231b authored by Almouhannad Hafez's avatar Almouhannad Hafez

Refactor code

parent e26ab76a
......@@ -4,7 +4,15 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup"
"**Simplified Data Encryption Standard (SDES)** \n",
"***By: Almouhannad Hafez***\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Setup"
]
},
{
......@@ -22,6 +30,13 @@
"%reload_ext autoreload"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Define new instance of SDES class"
]
},
{
"cell_type": "code",
"execution_count": 2,
......@@ -31,16 +46,9 @@
"name": "stdout",
"output_type": "stream",
"text": [
"key:\n",
"10101000000011011100011100110001010011101011010011\n",
"original text:\n",
"Almouhannad.Hafez\n",
"original text in binary:\n",
"010000010110110001101101011011110111010101101000011000010110111001101110011000010110010000101110010010000110000101100110011001010111101000000000\n",
"encrypted:\n",
"001010101011011010111010111001011101000010111000101010000110110000111100101010000110010001000111100001001100000011100001001000101100111000110111\n",
"decrypted:\n",
"Almouhannad.Hafez\n"
"A new instance of SDES was initilized with parameters\n",
"key_length: 50\n",
"rounds_count: 100\n"
]
}
],
......@@ -49,15 +57,220 @@
" key_length = 50,\n",
" rounds_count = 100\n",
")\n",
"\n",
"print(f\"A new instance of SDES was initilized with parameters\\nkey_length: {sdes.key_length}\\nrounds_count: {sdes.rounds_count}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Get a random key"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Radnomly generated key of length 50:\n",
"11100001010100011000010000010000001001111111100001\n"
]
}
],
"source": [
"key = sdes.generate_random_key()\n",
"print(f\"Radnomly generated key of length {sdes.key_length}:\\n{key}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Apply encryption"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Text 'Hello, I'm Almouhannad Hafez' after encryption using sdes:\n",
"010001110101010100101001111001100011001010011110110010000111000010111111011001111001101110110101111001100011111000010000000100010100110010100110111101111000110001001100110110010010110101100100000110101010111000011100001110001011\n"
]
}
],
"source": [
"text = \"Hello, I'm Almouhannad Hafez\"\n",
"encrypted_binary_string = sdes.encrypt(plain_text = text,\n",
" key = key)\n",
"\n",
"print(f\"Text '{text}' after encryption using sdes:\\n{encrypted_binary_string}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Apply decryption\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Decrypted text:\n",
"Hello, I'm Almouhannad Hafez\u0000\n"
]
}
],
"source": [
"decrypted_plain_text = sdes.decrypt(binary_encrypted_input=encrypted_binary_string,\n",
" key = key)\n",
"print(f\"Decrypted text:\\n{decrypted_plain_text}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Let's try other parameters"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"A new instance of SDES was initilized with parameters\n",
"key_length: 9\n",
"rounds_count: 2\n",
"Radnomly generated key of length 9:\n",
"110010000\n",
"Text 'Hello, I'm Almouhannad Hafez' after encryption using sdes:\n",
"111000111100010010010010000101110101110110111011110001100100100110011001101111010011100111000010000101110101101000110111111100101011111010111010010101100101110111100010000011011001110100111111011111101110110101100001000101000011\n",
"Decrypted text:\n",
"Hello, I'm Almouhannad Hafez\u0000\n"
]
}
],
"source": [
"sdes = SDES() # Default params\n",
"print(f\"A new instance of SDES was initilized with parameters\\nkey_length: {sdes.key_length}\\nrounds_count: {sdes.rounds_count}\")\n",
"\n",
"key = sdes.generate_random_key()\n",
"print(f\"key:\\n{key}\")\n",
"text = \"Almouhannad.Hafez\"\n",
"print(f\"original text:\\n{text}\")\n",
"print(f\"original text in binary:\\n{sdes.text_to_binary(text)}\")\n",
"enc = sdes.encrypt(text, key)\n",
"print(f\"encrypted:\\n{enc}\")\n",
"dec = sdes.decrypt(enc, key)\n",
"print(f\"decrypted:\\n{dec}\")\n"
"print(f\"Radnomly generated key of length {sdes.key_length}:\\n{key}\")\n",
"\n",
"text = \"Hello, I'm Almouhannad Hafez\"\n",
"encrypted_binary_string = sdes.encrypt(plain_text = text,\n",
" key = key)\n",
"print(f\"Text '{text}' after encryption using sdes:\\n{encrypted_binary_string}\")\n",
"\n",
"decrypted_plain_text = sdes.decrypt(binary_encrypted_input=encrypted_binary_string,\n",
" key = key)\n",
"print(f\"Decrypted text:\\n{decrypted_plain_text}\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"A new instance of SDES was initilized with parameters\n",
"key_length: 10000000\n",
"rounds_count: 2\n",
"Text 'Hello, I'm Almouhannad Hafez' after encryption using sdes:\n",
"100011000111000000011100011100001110001100110101001110011000100111000010111110011100100110110100011100001110100101111110100100111000000110110100101100111110100101101100000000101110110111001011011111111101101100111101111001001101\n",
"Decrypted text:\n",
"Hello, I'm Almouhannad Hafez\u0000\n"
]
}
],
"source": [
"sdes = SDES(key_length=10000000) # Large key\n",
"print(f\"A new instance of SDES was initilized with parameters\\nkey_length: {sdes.key_length}\\nrounds_count: {sdes.rounds_count}\")\n",
"\n",
"key = sdes.generate_random_key()\n",
"# print(f\"Radnomly generated key of length {sdes.key_length}:\\n{key}\")\n",
"\n",
"text = \"Hello, I'm Almouhannad Hafez\"\n",
"encrypted_binary_string = sdes.encrypt(plain_text = text,\n",
" key = key)\n",
"print(f\"Text '{text}' after encryption using sdes:\\n{encrypted_binary_string}\")\n",
"\n",
"decrypted_plain_text = sdes.decrypt(binary_encrypted_input=encrypted_binary_string,\n",
" key = key)\n",
"print(f\"Decrypted text:\\n{decrypted_plain_text}\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"A new instance of SDES was initilized with parameters\n",
"key_length: 9\n",
"rounds_count: 10000\n",
"Radnomly generated key of length 9:\n",
"110011101\n",
"Text 'Hello, I'm Almouhannad Hafez' after encryption using sdes:\n",
"000011110100111010111100111000111111101011000001110001111101000001101011011111000101001110010111111000111111010110010000100001111011011001101101101010100001100011000110111000001010011101001110101101101000100100101000000100111111\n",
"Decrypted text:\n",
"Hello, I'm Almouhannad Hafez\u0000\n",
"====================\n",
"Encrpytion time: 1.8319964408874512s\n",
"Decrpytion time: 2.1560163497924805s\n"
]
}
],
"source": [
"import time\n",
"\n",
"sdes = SDES(rounds_count=10000) # Large number of rounds\n",
"key = sdes.generate_random_key()\n",
"text = \"Hello, I'm Almouhannad Hafez\"\n",
"start_encryption_time = time.time()\n",
"encrypted_binary_string = sdes.encrypt(plain_text = text,\n",
" key = key)\n",
"end_encryption_time = time.time()\n",
"decrypted_plain_text = sdes.decrypt(binary_encrypted_input=encrypted_binary_string,\n",
" key = key)\n",
"end_decryption_time = time.time()\n",
"\n",
"print(f\"A new instance of SDES was initilized with parameters\\nkey_length: {sdes.key_length}\\nrounds_count: {sdes.rounds_count}\")\n",
"print(f\"Radnomly generated key of length {sdes.key_length}:\\n{key}\")\n",
"print(f\"Text '{text}' after encryption using sdes:\\n{encrypted_binary_string}\")\n",
"print(f\"Decrypted text:\\n{decrypted_plain_text}\")\n",
"\n",
"# Print exection times:\n",
"print(\"==\"*10)\n",
"print(f\"Encrpytion time: {end_encryption_time-start_encryption_time}s\")\n",
"print(f\"Decrpytion time: {end_decryption_time-end_encryption_time}s\")"
]
}
],
......
......@@ -17,11 +17,10 @@ class SDES:
# SDES is a block-cipher algorithm, uses blocks of size 12 bits
self.block_size = 12
# SDED uses a fixed-length key (8bits- key) for each iteration
# SDED uses a fixed-length key (8bits key) for each iteration
self.round_key_length = 8
# S1, S2 boxes:
self.S1 = [["101", "010", "001", "110", "011", "100", "111", "000"],
["001", "100", "110", "010", "000", "111", "101", "011"]]
......@@ -46,63 +45,226 @@ class SDES:
###############################################################################################
def encrypt(self, plain_text: str, key: str) -> str:
"""
Encrypts the given text using SDES with the given key
Parameters:
plain_text (str): The plain text to be encrypted
key (str): The key to be used for encryption
Returns:
encrypted_text (str): encrypted binary text resulting from the encryption
"""
# Type checking
if not isinstance(plain_text, str):
raise TypeError(f"'plain_text' must be str, got {type(plain_text).__name__}")
if not isinstance(key, str):
raise TypeError(f"'key' must be str, got {type(key).__name__}")
# Validation rules
if len(plain_text) == 0:
raise ValueError(f"Input text must not be empty")
if len(key) != self.key_length:
raise ValueError(f"The length of the key must be {self.key_length} bits, got {len(key)} bits")
# Convert the plain text to binary
binary_text = self.text_to_binary(plain_text)
output = binary_text
# Initialize the output with the binary text
encrypted_text = binary_text
# Perform the rounds of encryption
for i in range(self.rounds_count):
output = self.perform_round(i, key, output, 'enc')
return output
encrypted_text = self.perform_round(i, key, encrypted_text, 'enc')
return encrypted_text
def decrypt(self, binary_encrypted_input: str, key: str) -> str:
"""
Decrypts the given binary text using SDES with the given key
Parameters:
binary_encrypted_input (str): binary text to be decrypted
key (str): key to be used for decryption
Returns:
decrypted_plain_text (str): plain text resulting from the decryption
"""
# Type checking
if not isinstance(binary_encrypted_input, str):
raise TypeError(f"'binary_encrypted_input' must be str, got {type(binary_encrypted_input).__name__}")
if not isinstance(key, str):
raise TypeError(f"'key' must be str, got {type(key).__name__}")
# Validation rules
if len(binary_encrypted_input) == 0:
raise ValueError(f"Input binary text must not be empty")
if len(key) != self.key_length:
raise ValueError(f"The length of the key must be {self.key_length} bits, got {len(key)} bits")
# Initialize the output
output = binary_encrypted_input
# Perform the rounds of decryption
for i in range(self.rounds_count):
output = self.perform_round(i, key, output, 'dec')
# Convert the binary output to plain text
decrypted_plain_text = self.binary_to_text(output)
return decrypted_plain_text
def perform_round (self, round_number: int, key: int, input: str, mode: str) -> str:
return decrypted_plain_text
def perform_round(self, round_number: int, key: str, input: str, mode: str) -> str:
"""
Performs a single round of encryption or decryption
Parameters:
round_number (int): round number for the operation
key (str): key to be used for the operation
input (str): binary input to be processed
mode (str): Mode of operation ('enc' for encryption, 'dec' for decryption)
Returns:
output (str): The processed binary output after the round
"""
# Type checking
if not isinstance(round_number, int):
raise TypeError(f"'round_number' must be int, got {type(round_number).__name__}")
if not isinstance(key, str):
raise TypeError(f"'key' must be str, got {type(key).__name__}")
if not isinstance(input, str):
raise TypeError(f"'input' must be str, got {type(input).__name__}")
if not isinstance(mode, str):
raise TypeError(f"'mode' must be str, got {type(mode).__name__}")
# Validation rules
if round_number < 0 or round_number >= self.rounds_count:
raise ValueError(f"'round_number' must be between 0 and {self.rounds_count - 1}, got {round_number}")
if mode not in ['enc', 'dec']:
raise ValueError(f"Invalid mode '{mode}'. Expected 'enc' or 'dec'.")
# Get the blocks from the input
blocks = self.get_blocks(input)
# Determine the round key based on the mode
if mode == 'enc':
round_key = self.get_round_key(key, round_number)
elif mode == 'dec':
# Do the same process of encryption, but using keys in reverse order
# Use keys in reverse order for decryption
round_number_inv = (self.rounds_count - round_number - 1) % self.rounds_count
round_key = self.get_round_key(key, round_number_inv)
round_key = self.get_round_key(key, round_number_inv)
# Initialize output
output = ''
for i in range(len(blocks)):
blocks[i] = self.process_block(round_key, blocks[i])
# Flip LR in the last round
if round_number == self.rounds_count -1:
if round_number == self.rounds_count - 1:
block = blocks[i]
blocks[i] = ''
blocks[i] += block[self.block_size//2 : self.block_size]
blocks[i] += block[0:self.block_size//2]
blocks[i] = block[self.block_size // 2:] + block[:self.block_size // 2]
output += blocks[i]
return output
def process_block(self, round_key: str, old_block: str) -> str:
L_old, R_old = old_block[0:self.block_size//2] , old_block[self.block_size//2 : self.block_size]
"""
Processes a block of data using round key
Parameters:
round_key (str): The key to be used for this round
old_block (str): The block of data to be processed
Returns:
new_block (str): The processed block after applying the round function
"""
# Type checking
if not isinstance(round_key, str):
raise TypeError(f"'round_key' must be str, got {type(round_key).__name__}")
if not isinstance(old_block, str):
raise TypeError(f"'old_block' must be str, got {type(old_block).__name__}")
# Validation rules
if len(round_key) != self.round_key_length:
raise ValueError(f"The length of 'round_key' must be {self.round_key_length} bits, got {len(round_key)} bits")
if len(old_block) != self.block_size:
raise ValueError(f"The length of 'old_block' must be {self.block_size} bits, got {len(old_block)} bits")
# Split the old block into left and right parts
L_old, R_old = old_block[0:self.block_size // 2], old_block[self.block_size // 2:]
# Perform the processing
L_new = R_old
R_new = self.f(round_key, R_old)
R_new = self.binary_strings_xor(R_new, L_old)
new_block = ''
new_block += L_new
new_block += R_new
return new_block
# Combine the new left and right parts into a new block
new_block = L_new + R_new
return new_block
def f(self, key: str, R: str) -> str:
"""
Applies the round function on the right half of the block using round key
Parameters:
key (str): The key to be used for this round
R (str): The right half of the block to be processed
Returns:
new_R (str): The processed right half after applying the round function
"""
# Type checking
if not isinstance(key, str):
raise TypeError(f"'key' must be str, got {type(key).__name__}")
if not isinstance(R, str):
raise TypeError(f"'R' must be str, got {type(R).__name__}")
# Validation rules
if len(key) != self.round_key_length:
raise ValueError(f"The length of 'key' must be {self.round_key_length} bits, got {len(key)} bits")
if len(R) != self.block_size // 2:
raise ValueError(f"The length of 'R' must be {self.block_size // 2} bits, got {len(R)} bits")
# Perform the processing
# Extension
new_R = self.E(R)
# XOR with key
new_R = self.binary_strings_xor(new_R, key)
# Apply S boxes
new_R_L, new_R_R = new_R[0:4], new_R[4:8]
new_R_L = self.apply_S(new_R_L, 1)
new_R_R = self.apply_S(new_R_R, 2)
new_R = ''
new_R += new_R_L
new_R += new_R_R
new_R = new_R_L + new_R_R
return new_R
def E(self, R: str) -> str:
"""
Extends the right half of the block
Parameters:
R (str): The right half of the block to be extended
Returns:
extended_R (str): The extended version of the right half
"""
# Type checking
if not isinstance(R, str):
raise TypeError(f"'R' must be str, got {type(R).__name__}")
# Validation rules
if len(R) != self.block_size // 2:
raise ValueError(f"The length of 'R' must be {self.block_size // 2} bits, got {len(R)} bits")
# Perform the extension
extended_R = ''
extended_R += (R[0] + R[1])
extended_R += R[3]
......@@ -113,9 +275,35 @@ class SDES:
return extended_R
def apply_S(self, R: str, S_number: int) -> str:
"""
Applies the S-box transformation to the input
Parameters:
R (str): The input to be transformed (must be 4 bits)
S_number (int): The S-box number to use (1 or 2)
Returns:
str: The transformed output after applying the S-box
"""
# Type checking
if not isinstance(R, str):
raise TypeError(f"'R' must be str, got {type(R).__name__}")
if not isinstance(S_number, int):
raise TypeError(f"'S_number' must be int, got {type(S_number).__name__}")
# Validation rules
if len(R) != 4:
raise ValueError(f"The length of 'R' must be 4 bits, got {len(R)} bits")
if S_number not in [1, 2]:
raise ValueError("S_number must be either 1 or 2")
# Calculate row and column indices for the S-box lookup
row_index = int(R[0], 2)
col_index = int(R[1:4], 2)
if (S_number == 1):
# Apply the appropriate S-box
if S_number == 1:
return self.S1[row_index][col_index]
else:
return self.S2[row_index][col_index]
......@@ -258,9 +446,40 @@ class SDES:
return blocks
def binary_strings_xor(self, binary_string_1: str, binary_string_2: str) -> str:
"""
Performs the XOR operation on two binary strings
Parameters:
binary_string_1 (str): The first binary string
binary_string_2 (str): The second binary string
Returns:
xor_result_str (str): The result of the XOR operation as a binary string
"""
# Type checking
if not isinstance(binary_string_1, str):
raise TypeError(f"'binary_string_1' must be str, got {type(binary_string_1).__name__}")
if not isinstance(binary_string_2, str):
raise TypeError(f"'binary_string_2' must be str, got {type(binary_string_2).__name__}")
# Validation rules
if len(binary_string_1) != len(binary_string_2):
raise ValueError("Both binary strings must have the same length")
for char in binary_string_1:
if char not in '01':
raise ValueError(f"'binary_string_1' contains non-binary characters: {binary_string_1}")
for char in binary_string_2:
if char not in '01':
raise ValueError(f"'binary_string_2' contains non-binary characters: {binary_string_2}")
# Perform XOR operation after converting to int
num1 = int(binary_string_1, 2)
num2 = int(binary_string_2, 2)
xor_result = num1 ^ num2
xor_result_str = bin(xor_result)[2:]
# Ensure the result is zero-padded to the same length
xor_result_str = xor_result_str.zfill(len(binary_string_1))
return xor_result_str
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment