diff --git a/main.py b/main.py index 5d71befdf8e8fb9a92432374ff8b8ae8b0503abe..6c8587e98b25c13552b25af6472b89953bb220f9 100644 --- a/main.py +++ b/main.py @@ -4,6 +4,14 @@ Authors : Rayyan BELHI, Dario GENGA Date : 2022 """ +""" +Note : The methods 'get_bezout_coefficients' and 'modular_inverse' were done by Gawen ACKERMANN, Florian BURGENER, +Quentin FASLER & Dario GENGA in another lesson. +Those methods are required if the Python version is lower than 3.8. + +With Python 3.8+ we can use the built-in 'pow' function to calculate the modular inverse, where y = pow(x, -1, p). +""" + # Return a mod b def modulo(a, b): @@ -95,6 +103,65 @@ def xor(a, b): return res +def get_bezout_coefficients(a, b): + """Find the Bézout coefficients of a and b. + + Args: + a (int): The number a + b (int): The number b. + + Returns: + tuple: Bézout coefficients. + """ + r = [a, b] + x = [1, 0] + y = [0, 1] + q = [0, 0] + i = 2 + + while True: + r.append(r[i - 2] % r[i - 1]) + + # Continue until the rest is equal to 0 + if r[i] == 0: + break + q.append(int(r[i - 2] / r[i - 1])) + x.append(x[i - 2] - q[i] * x[i - 1]) + y.append(y[i - 2] - q[i] * y[i - 1]) + + i += 1 + return x[-1], y[-1] + + +def modular_inverse(a, n): + """Compute the modular inverse of a number a modulo n. + + Args: + a (int): The number to reverse. + n (int): The modulo. + + Returns: + int: The reversed number. + """ + if type(a) == str: + a = int(a, 2) + + coefficients = get_bezout_coefficients(a, n) + + if a * coefficients[0] % n == 1: + return format(coefficients[0] % n, '04b') + return None + + +def inverse_add_mod(a): + if type(a) == str: + a = int(a, 2) + + res = 16 - a + + return format(res, '04b') + + # Shift the 6 first bit of the key to the end def shift_key(key): bit_to_shift = key[0:6] @@ -121,10 +188,54 @@ def create_subkeys_table(key): return subkeys -# Encrypt the text with the key by using the IDEA algorithm -def encrypt(plaintext, key): +# Modify the subkeys table into a 2d array where each array correspond to a round +def create_subkeys_table_with_rounds(subkeys_table): + subkeys_table_with_rounds = [] + round_keys = [] + + for i, key in enumerate(subkeys_table): + round_keys.append(key) + if modulo(i + 1, 6) == 0: + subkeys_table_with_rounds.append(round_keys) + round_keys = [] + + # The final round have fewer keys than the other rounds, so we have to add it afterward + subkeys_table_with_rounds.append(round_keys) + + return subkeys_table_with_rounds + + +def create_decryption_subkeys_table(subkeys_table): + decryption_subkeys = [] + # Modify the subkeys table into a 2d array where each array correspond to a round + subkeys_table = create_subkeys_table_with_rounds(subkeys_table) + + remaining_round = 4 + while remaining_round >= 0: + k1 = modular_inverse(subkeys_table[remaining_round][0], 17) + k2 = inverse_add_mod(subkeys_table[remaining_round][1]) + k3 = inverse_add_mod(subkeys_table[remaining_round][2]) + k4 = modular_inverse(subkeys_table[remaining_round][3], 17) + + decryption_subkeys.append(k1) + decryption_subkeys.append(k2) + decryption_subkeys.append(k3) + decryption_subkeys.append(k4) + + if remaining_round > 0: + k5 = subkeys_table[remaining_round - 1][4] + k6 = subkeys_table[remaining_round - 1][5] + decryption_subkeys.append(k5) + decryption_subkeys.append(k6) + + remaining_round -= 1 + + return decryption_subkeys + + +# Encrypt the text with the subkeys by using the simplified IDEA algorithm +def encrypt(plaintext, subkeys): input_block = plaintext - subkeys = create_subkeys_table(key) current_round = 0 total_rounds = 4 @@ -172,15 +283,26 @@ def encrypt(plaintext, key): return ciphertext +# Decrypt the ciphertext with the subkeys table by using the simplified IDEA algorithm +def decrypt(ciphertext, subkeys_table): + decryption_keys = create_decryption_subkeys_table(subkeys_table) + return encrypt(ciphertext, decryption_keys) + + def main(): plaintext = '1001110010101100' key = '11011100011011110011111101011001' expected_ciphertext = '1011101101001011' - ciphertext = encrypt(plaintext, key) - print("The original message is : " + plaintext) print("The key is : " + key) + + subkeys = create_subkeys_table(key) + + print("Starting the encryption...") + + ciphertext = encrypt(plaintext, subkeys) + print("The ciphertext obtained is : " + ciphertext) if ciphertext == expected_ciphertext: @@ -188,6 +310,17 @@ def main(): else: print("An error has occurred during the encryption...") + print("Starting the decryption...") + + decrypted_text = decrypt(ciphertext, subkeys) + + print("The decrypted message is : " + decrypted_text) + + if decrypted_text == plaintext: + print("The decryption has been successful !") + else: + print("An error has occurred during the decryption...") + if __name__ == "__main__": main()