From 991e74f58905298c61a2b140019909bc66cb0044 Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Mon, 26 May 2025 23:00:06 +0400 Subject: [PATCH 01/12] Parser --- .gitignore | 2 ++ lab_3/main.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 .gitignore create mode 100644 lab_3/main.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..de61102d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/lab_2/task_1/ +/lab_2/task_2/ diff --git a/lab_3/main.py b/lab_3/main.py new file mode 100644 index 000000000..5cf862c98 --- /dev/null +++ b/lab_3/main.py @@ -0,0 +1,34 @@ +import argparse + + +def parse_arguments() -> argparse.Namespace: + """ + Function parses arguments from cmd + :return: object with arguments + """ + parser = argparse.ArgumentParser( + description="Hybrid crypto system (RSA + ChaCha20)", + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + parser.add_argument('-s', '--settings', default = 'settings.json', help = 'Path to JSON file containing settings') + group = parser.add_mutually_exclusive_group(required = True) + + group.add_argument('-gen', '--generation', action='store_true', help='Generate keys') + group.add_argument('-enc', '--encryption', action='store_true', help='Encrypt file') + group.add_argument('-dec', '--decryption', action='store_true', help='Decrypt file') + + return parser.parse_args() + +def main() : + args = parse_arguments() + + match True: + case args.generation: + print("1") + case args.encryption: + print("2") + case args.decryption: + print("3") + +if __name__ == '__main__': + main() \ No newline at end of file From 94430789ae0dbf155a7d3ac3322a7a35c4510c3b Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Tue, 27 May 2025 09:54:49 +0400 Subject: [PATCH 02/12] File manager --- lab_3/file_manager.py | 34 ++++++++++++++++++++++++++++++++++ lab_3/settings.json | 8 ++++++++ 2 files changed, 42 insertions(+) create mode 100644 lab_3/file_manager.py create mode 100644 lab_3/settings.json diff --git a/lab_3/file_manager.py b/lab_3/file_manager.py new file mode 100644 index 000000000..e1b119c7c --- /dev/null +++ b/lab_3/file_manager.py @@ -0,0 +1,34 @@ +import json + + +class FileManager: + + @staticmethod + def save_bytes(path: str, data: bytes): + with open(path, "wb") as f: + f.write(data) + + @staticmethod + def load_bytes(path: str) -> bytes: + with open(path, "rb") as f: + return f.read() + + @staticmethod + def load_json(json_path: str) -> dict: + """ + Method read json file as a dict with requirements + :param json_path: path of json file + :return: dictionary + """ + try: + with open(json_path, 'r', encoding='utf-8') as f: + return json.load(f) + except FileNotFoundError: + raise FileNotFoundError(f"JSON file not found: {json_path}") + except json.JSONDecodeError: + raise ValueError(f"Invalid JSON format in file: {json_path}") + + @staticmethod + def load_settings(path: str) -> dict: + """Загрузить настройки из JSON-файла.""" + return FileManager.load_json(path) \ No newline at end of file diff --git a/lab_3/settings.json b/lab_3/settings.json new file mode 100644 index 000000000..e1580e084 --- /dev/null +++ b/lab_3/settings.json @@ -0,0 +1,8 @@ +{ + "initial_file":"texts/initial_file.txt", + "encrypted_file":"texts/encrypted_file.txt", + "decrypted_file":"texts/decrypted_file.txt", + "symmetric_key":"keys/symmetric_key.txt", + "public_key":"keys/public_key.pem", + "private_key":"keys/private_key.pem" +} From 4926d6c96e1e953e677eb03b01065dd967bd69ce Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Tue, 27 May 2025 16:36:28 +0400 Subject: [PATCH 03/12] Rename --- lab_3/hybrid_system.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lab_3/hybrid_system.py diff --git a/lab_3/hybrid_system.py b/lab_3/hybrid_system.py new file mode 100644 index 000000000..e69de29bb From de61c8be45417dc941f706f2f09569746a9f8026 Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Tue, 27 May 2025 16:40:15 +0400 Subject: [PATCH 04/12] Rename --- lab_3/hybrid_system.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lab_3/hybrid_system.py b/lab_3/hybrid_system.py index e69de29bb..efca996cc 100644 --- a/lab_3/hybrid_system.py +++ b/lab_3/hybrid_system.py @@ -0,0 +1 @@ +import \ No newline at end of file From dce9f27e2e0d4cf6a73488cc9c80fefd12f59aa2 Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Tue, 27 May 2025 16:43:37 +0400 Subject: [PATCH 05/12] Rename --- lab_3/hybrid_system.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lab_3/hybrid_system.py b/lab_3/hybrid_system.py index efca996cc..e69de29bb 100644 --- a/lab_3/hybrid_system.py +++ b/lab_3/hybrid_system.py @@ -1 +0,0 @@ -import \ No newline at end of file From 005cdc28cb8b97e80171b2456529db9c3689533c Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Tue, 27 May 2025 16:52:29 +0400 Subject: [PATCH 06/12] Change variant --- lab_3/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lab_3/main.py b/lab_3/main.py index 5cf862c98..40158bc03 100644 --- a/lab_3/main.py +++ b/lab_3/main.py @@ -7,7 +7,7 @@ def parse_arguments() -> argparse.Namespace: :return: object with arguments """ parser = argparse.ArgumentParser( - description="Hybrid crypto system (RSA + ChaCha20)", + description="Hybrid crypto system (RSA + 3DES)", formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument('-s', '--settings', default = 'settings.json', help = 'Path to JSON file containing settings') From 5874a8ad4bb594a7a2966f22eb664257312f0d52 Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Wed, 28 May 2025 11:07:38 +0400 Subject: [PATCH 07/12] Completing the file_manager.py --- .../asymmetric.py} | 0 lab_3/cryptosystem/hybrid_system.py | 0 lab_3/cryptosystem/symmetric.py | 0 lab_3/file_manager.py | 38 +++++++++++++------ lab_3/main.py | 8 ++-- 5 files changed, 32 insertions(+), 14 deletions(-) rename lab_3/{hybrid_system.py => cryptosystem/asymmetric.py} (100%) create mode 100644 lab_3/cryptosystem/hybrid_system.py create mode 100644 lab_3/cryptosystem/symmetric.py diff --git a/lab_3/hybrid_system.py b/lab_3/cryptosystem/asymmetric.py similarity index 100% rename from lab_3/hybrid_system.py rename to lab_3/cryptosystem/asymmetric.py diff --git a/lab_3/cryptosystem/hybrid_system.py b/lab_3/cryptosystem/hybrid_system.py new file mode 100644 index 000000000..e69de29bb diff --git a/lab_3/cryptosystem/symmetric.py b/lab_3/cryptosystem/symmetric.py new file mode 100644 index 000000000..e69de29bb diff --git a/lab_3/file_manager.py b/lab_3/file_manager.py index e1b119c7c..bf4d16e6f 100644 --- a/lab_3/file_manager.py +++ b/lab_3/file_manager.py @@ -4,14 +4,35 @@ class FileManager: @staticmethod - def save_bytes(path: str, data: bytes): - with open(path, "wb") as f: - f.write(data) + def save_bytes(path: str, data: bytes) -> None: + """ + Writing data to a file + :param path: path to file to save + :param data: data to save + :return: None + """ + try: + with open(path, "wb") as f: + f.write(data) + except Exception as e: + raise Exception(f"An error occurred with the file: {str(e)}.") + except FileNotFoundError: + raise FileNotFoundError(f"The file was not found.") @staticmethod def load_bytes(path: str) -> bytes: - with open(path, "rb") as f: - return f.read() + """ + Reading data from a file + :param path: path to the file + :return: bytes format object + """ + try: + with open(path, "rb") as f: + return f.read() + except Exception as e: + raise Exception(f"An error occurred with the file: {str(e)}.") + except FileNotFoundError: + raise FileNotFoundError(f"The file was not found.") @staticmethod def load_json(json_path: str) -> dict: @@ -26,9 +47,4 @@ def load_json(json_path: str) -> dict: except FileNotFoundError: raise FileNotFoundError(f"JSON file not found: {json_path}") except json.JSONDecodeError: - raise ValueError(f"Invalid JSON format in file: {json_path}") - - @staticmethod - def load_settings(path: str) -> dict: - """Загрузить настройки из JSON-файла.""" - return FileManager.load_json(path) \ No newline at end of file + raise ValueError(f"Invalid JSON format in file: {json_path}") \ No newline at end of file diff --git a/lab_3/main.py b/lab_3/main.py index 40158bc03..2db8950c1 100644 --- a/lab_3/main.py +++ b/lab_3/main.py @@ -1,5 +1,6 @@ import argparse +from file_manager import FileManager def parse_arguments() -> argparse.Namespace: """ @@ -21,14 +22,15 @@ def parse_arguments() -> argparse.Namespace: def main() : args = parse_arguments() + settings = FileManager.load_json(args.settings) match True: case args.generation: - print("1") + print("1", settings) case args.encryption: - print("2") + print("2", settings) case args.decryption: - print("3") + print("3", settings) if __name__ == '__main__': main() \ No newline at end of file From 37efc9e26e02bf1a20705db356732621b21e8d11 Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Mon, 9 Jun 2025 00:13:08 +0400 Subject: [PATCH 08/12] intermediate result --- lab_3/cryptosystem/asymmetric.py | 68 +++++++++++++++++++++++++++ lab_3/cryptosystem/hybrid_system.py | 40 ++++++++++++++++ lab_3/cryptosystem/symmetric.py | 45 ++++++++++++++++++ lab_3/file_manager.py | 12 ++--- lab_3/keys/private_key.pem | 28 +++++++++++ lab_3/keys/public_key.pem | 9 ++++ lab_3/keys/symmetric_key.txt | 1 + lab_3/main.py | 72 +++++++++++++++++++++++------ lab_3/texts/initial_file.txt | 11 +++++ 9 files changed, 265 insertions(+), 21 deletions(-) create mode 100644 lab_3/keys/private_key.pem create mode 100644 lab_3/keys/public_key.pem create mode 100644 lab_3/keys/symmetric_key.txt create mode 100644 lab_3/texts/initial_file.txt diff --git a/lab_3/cryptosystem/asymmetric.py b/lab_3/cryptosystem/asymmetric.py index e69de29bb..3a6c65cb0 100644 --- a/lab_3/cryptosystem/asymmetric.py +++ b/lab_3/cryptosystem/asymmetric.py @@ -0,0 +1,68 @@ +from cryptography.hazmat.primitives.asymmetric import rsa, padding +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.backends import default_backend + +from file_manager import FileManager + + +class AsymmetricRSA: + def __init__(self, key_size=2048): + self.key_size = key_size + self.private_key = None + self.public_key = None + + def generate_keys(self): + self.private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=self.key_size, + backend=default_backend() + ) + self.public_key = self.private_key.public_key() + + def export_keys(self, private_path: str, public_path: str): + private_pem = self.private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption() + ) + public_pem = self.public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo + ) + FileManager.save_bytes(private_path, private_pem) + FileManager.save_bytes(public_path, public_pem) + + def load_private_key(self, path): + key_data = FileManager.load_bytes(path) + self.private_key = serialization.load_pem_private_key( + key_data, + password=None, + backend=default_backend() + ) + + def load_public_key(self, path): + key_data = FileManager.load_bytes(path) + self.public_key = serialization.load_pem_public_key( + key_data, + backend=default_backend() + ) + + def encrypt(self, data: bytes) -> bytes: + return self.public_key.encrypt( + data, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) + ) + + def decrypt(self, data: bytes) -> bytes: + return self.private_key.decrypt( + data, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) + ) \ No newline at end of file diff --git a/lab_3/cryptosystem/hybrid_system.py b/lab_3/cryptosystem/hybrid_system.py index e69de29bb..45c68a502 100644 --- a/lab_3/cryptosystem/hybrid_system.py +++ b/lab_3/cryptosystem/hybrid_system.py @@ -0,0 +1,40 @@ +from .asymmetric import AsymmetricRSA +from file_manager import FileManager +from .symmetric import Symmetric3DES + + +class HybridCryptoSystem: + asym = AsymmetricRSA() + sym = None + + @classmethod + def generate_keys(cls, key_length): + """Generate both RSA and 3DES keys""" + cls.asym.generate_keys() + cls.sym = Symmetric3DES(key_length) + cls.sym.generate_key() + + @classmethod + def save_keys(cls, private_path: str, public_path: str, symmetric_path: str): + """Save all generated keys to files""" + cls.asym.export_keys(private_path, public_path) + FileManager.save_bytes(symmetric_path, cls.sym.key) + + @classmethod + def encrypt(cls, plaintext: bytes) -> dict: + """Encrypt data using hybrid approach""" + ct_message = cls.sym.encrypt(plaintext) + ct_key = cls.asym.encrypt(cls.sym.key) + return { + 'encrypted_key': ct_key, + 'encrypted_message': ct_message + } + + @classmethod + def decrypt(cls, encrypted_key: bytes, encrypted_message: bytes) -> bytes: + """Decrypt data using hybrid approach""" + key = cls.asym.decrypt(encrypted_key) + temp_sym = Symmetric3DES(len(key)*8) + temp_sym.key = key + plaintext = temp_sym.decrypt(encrypted_message) + return plaintext \ No newline at end of file diff --git a/lab_3/cryptosystem/symmetric.py b/lab_3/cryptosystem/symmetric.py index e69de29bb..04cf286d4 100644 --- a/lab_3/cryptosystem/symmetric.py +++ b/lab_3/cryptosystem/symmetric.py @@ -0,0 +1,45 @@ +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives import padding as sym_padding +from cryptography.hazmat.backends import default_backend +import os + + +class Symmetric3DES: + def __init__(self, key_length_bits=192): + if key_length_bits not in (64, 128, 192): + raise ValueError("3DES key length must be 64, 128 or 192 bits") + self.key_length_bytes = key_length_bits // 8 + self.key = None + + def generate_key(self): + self.key = os.urandom(self.key_length_bytes) + + def encrypt(self, plaintext: bytes) -> bytes: + iv = os.urandom(8) # 3DES block size is 8 bytes + padder = sym_padding.PKCS7(64).padder() # 64 bits = 8 bytes block size + padded_data = padder.update(plaintext) + padder.finalize() + + cipher = Cipher( + algorithms.TripleDES(self.key), + modes.CBC(iv), + backend = default_backend() + ) + encryptor = cipher.encryptor() + ciphertext = encryptor.update(padded_data) + encryptor.finalize() + return iv + ciphertext + + def decrypt(self, ciphertext: bytes) -> bytes: + iv = ciphertext[:8] + ct = ciphertext[8:] + + cipher = Cipher( + algorithms.TripleDES(self.key), + modes.CBC(iv), + backend = default_backend() + ) + decryptor = cipher.decryptor() + padded_plaintext = decryptor.update(ct) + decryptor.finalize() + + unpadder = sym_padding.PKCS7(64).unpadder() + plaintext = unpadder.update(padded_plaintext) + unpadder.finalize() + return plaintext \ No newline at end of file diff --git a/lab_3/file_manager.py b/lab_3/file_manager.py index bf4d16e6f..6db5b2e9d 100644 --- a/lab_3/file_manager.py +++ b/lab_3/file_manager.py @@ -14,10 +14,10 @@ def save_bytes(path: str, data: bytes) -> None: try: with open(path, "wb") as f: f.write(data) - except Exception as e: - raise Exception(f"An error occurred with the file: {str(e)}.") except FileNotFoundError: - raise FileNotFoundError(f"The file was not found.") + raise FileNotFoundError(f"The file was not found: {path}") + except Exception as e: + raise Exception(f"An error occurred with the file: {str(e)}") @staticmethod def load_bytes(path: str) -> bytes: @@ -29,10 +29,10 @@ def load_bytes(path: str) -> bytes: try: with open(path, "rb") as f: return f.read() - except Exception as e: - raise Exception(f"An error occurred with the file: {str(e)}.") except FileNotFoundError: - raise FileNotFoundError(f"The file was not found.") + raise FileNotFoundError(f"The file was not found: {path}") + except Exception as e: + raise Exception(f"An error occurred with the file: {str(e)}") @staticmethod def load_json(json_path: str) -> dict: diff --git a/lab_3/keys/private_key.pem b/lab_3/keys/private_key.pem new file mode 100644 index 000000000..042c789b2 --- /dev/null +++ b/lab_3/keys/private_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSQzUH3kEHAnPf +DbgwOF7ElMy3RNytB0M/3+1FEEuJLm7eFdNp8lxfnq54ND67afBidotHlRYJHMme +dj3z1Rziu9nT7HSlSEkWP7B8hEQwQAhCW6rD6ukuWucTVj3I44IFw/7xVZEtkf2H +3YvyysyDILn3/19mc8BBzvg4sZiQF9hWfhSg5MnB397ziIS8eZDLDRwkD7MIiVdf +w9U8ufuNzwou4hODCacFr4gzCIzthET94KNY+Rl8BjsG7KlpLmoOuk1qpvi/qY4/ +piaEVy8lps/T4NlSzgLjg/vY8RFJc6cAuXqoobzmVn3jiqHz3D+kD80ALp7W0xqC +StCzdWNDAgMBAAECggEABRgZv2oNrnf+ixRP0EmqI7fsycsb6ZlE2NXtCRpSKi2u +altvA6C0LW2wkaFgz7Uxj/RW5YVIKZcn9cETOSzo0tl1EPxbZLglBSpf26ejG0qO +qKtRFNQRK2bwzqtToRVZ/7FcinsY1fJoIq2MbkJzKzSH+bX9mR0+0DL0GQBWHBxc +iQr/rsCTx+XkFN18/SHAydcsHHVeIxaQEZ2J3pKEGxfzPEUEHGjCDgocWSbfTyE5 +JyKYh8t1E72ZGMjiuwEFELphC7S14zW9MWaqXBfYvJhAmihEtHWOb19YbnWznaF5 +MQ9wicwK4CVk631wSOmIFZvt6oDdQprYcmvVrz2ZoQKBgQDwamYJ9EU/Ohs4kKeR +OdIoMQiHiXOqqfBVztzDYm98FhVbCHjXrBLVaRMhZ0V/TDxxG9/hw1bzW2LHNC8q +ReMtuwPj+3VSmNEt14uoA4Ftf0ze4FafNK3Cms9ZAUJhL1TsREu58LuADy9fKjqA +puPJLpK3I+POnk4T6aiM43fyMQKBgQDf5G4V757Xrr3p8swD0tOZKjpPVbg3YAAa +Zhx0ihkNaZe1Xs0BcDe4K4/9JfuJxrqcEmmLcfivbkZBfXwl3eimGhT+RIHo+l+2 +SX4j5iaHDWkxqtBqkApwDTcR7b/UnYHyRi2VcECL8QC0XQgxj328R+QGu19T3pnh +Z+3tzPH7swKBgQCeJP82MQ6UBr79OHphl21crtRzg8EoVF0ZtNeXVtsK/uPRXANR +q4lABLxmzq3yjM19gd6FfZ9muYiCjRsxbYOBA3INt813JbsDsrPVM2kiBAkm2t9g +HqDmUDtwytlFYIM2X76Ic4iDNnns2bReCGnyXsZ33g3uTkgB5UPQWZj/IQKBgHoz +OYqrgK0D6RAZvxSPK4K7s5u9k5BVy3idJwbMoSPa8DzEA2y3jRHuZOaspn/qgcvR +mN3NVQibTalNDke0uNh//9lQFv/MOBVMQ5bgdULdJP9A1gRznd7Ot7IHa95mIZjU +iOi5neFDpzjKVkCGqv/q1SB/gGZMZvzKNujGJYVVAoGBAIcrKhj3G6zpPkpRKxfw +YlttBN2+cX0GCZi301WICV/XI+PCR5PE0PmWkh3Ic3rWU5TD6bYk/E/DFcfbFCva +SV0fCj7OVz2N6CC90waYdJRcWi78srVIs1ej69gkKj8Idb73O2sE2AVHmxPQeM19 +gljPAnfjE2JxqS/7ZhrTuxHO +-----END PRIVATE KEY----- diff --git a/lab_3/keys/public_key.pem b/lab_3/keys/public_key.pem new file mode 100644 index 000000000..3f1138434 --- /dev/null +++ b/lab_3/keys/public_key.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0kM1B95BBwJz3w24MDhe +xJTMt0TcrQdDP9/tRRBLiS5u3hXTafJcX56ueDQ+u2nwYnaLR5UWCRzJnnY989Uc +4rvZ0+x0pUhJFj+wfIREMEAIQluqw+rpLlrnE1Y9yOOCBcP+8VWRLZH9h92L8srM +gyC59/9fZnPAQc74OLGYkBfYVn4UoOTJwd/e84iEvHmQyw0cJA+zCIlXX8PVPLn7 +jc8KLuITgwmnBa+IMwiM7YRE/eCjWPkZfAY7BuypaS5qDrpNaqb4v6mOP6YmhFcv +JabP0+DZUs4C44P72PERSXOnALl6qKG85lZ944qh89w/pA/NAC6e1tMagkrQs3Vj +QwIDAQAB +-----END PUBLIC KEY----- diff --git a/lab_3/keys/symmetric_key.txt b/lab_3/keys/symmetric_key.txt new file mode 100644 index 000000000..8f7d4d5f9 --- /dev/null +++ b/lab_3/keys/symmetric_key.txt @@ -0,0 +1 @@ +W3E \ No newline at end of file diff --git a/lab_3/main.py b/lab_3/main.py index 2db8950c1..3286733cc 100644 --- a/lab_3/main.py +++ b/lab_3/main.py @@ -1,36 +1,78 @@ import argparse +from cryptosystem.hybrid_system import HybridCryptoSystem from file_manager import FileManager + def parse_arguments() -> argparse.Namespace: """ Function parses arguments from cmd :return: object with arguments """ parser = argparse.ArgumentParser( - description="Hybrid crypto system (RSA + 3DES)", - formatter_class=argparse.ArgumentDefaultsHelpFormatter + description = "Hybrid crypto system (RSA + 3DES)", + formatter_class = argparse.ArgumentDefaultsHelpFormatter ) - parser.add_argument('-s', '--settings', default = 'settings.json', help = 'Path to JSON file containing settings') - group = parser.add_mutually_exclusive_group(required = True) + parser.add_argument('-s', '--settings', default = 'settings.json', + help = 'Path to JSON file containing settings') - group.add_argument('-gen', '--generation', action='store_true', help='Generate keys') - group.add_argument('-enc', '--encryption', action='store_true', help='Encrypt file') - group.add_argument('-dec', '--decryption', action='store_true', help='Decrypt file') + parser.add_argument('-k', '--key_length', type = int, choices = [64, 128, 192], default = 192, + help = 'Symmetric key length in bits (64, 128 or 192)') + + group = parser.add_mutually_exclusive_group(required = True) + group.add_argument('-gen', '--generation', action = 'store_true', help = 'Generate keys') + group.add_argument('-enc', '--encryption', action = 'store_true', help = 'Encrypt file') + group.add_argument('-dec', '--decryption', action = 'store_true', help = 'Decrypt file') return parser.parse_args() -def main() : +def main(): args = parse_arguments() settings = FileManager.load_json(args.settings) - match True: - case args.generation: - print("1", settings) - case args.encryption: - print("2", settings) - case args.decryption: - print("3", settings) + if args.generation: + HybridCryptoSystem.generate_keys(args.key_length) + HybridCryptoSystem.save_keys( + settings["private_key"], + settings["public_key"], + settings["symmetric_key"] + ) + print( + f"Keys generated and saved:\n" + f" - Private key: {settings['private_key']}\n" + f" - Public key: {settings['public_key']}\n" + f" - Symmetric key: {settings['symmetric_key']}" + ) + elif args.encryption: + HybridCryptoSystem.asym.load_public_key(settings["public_key"]) + HybridCryptoSystem.sym.generate_key() + + plaintext = FileManager.load_bytes(settings["initial_file"]) + + encrypted_data = HybridCryptoSystem.encrypt(plaintext) + + data_to_save = ( + len(encrypted_data['encrypted_key']).to_bytes(4, 'big') + + encrypted_data['encrypted_key'] + + encrypted_data['encrypted_message'] + ) + FileManager.save_bytes(settings["encrypted_file"], data_to_save) + + print(f"File encrypted and saved to {settings['encrypted_file']}") + elif args.decryption: + HybridCryptoSystem.asym.load_private_key(settings["private_key"]) + + data = FileManager.load_bytes(settings["encrypted_file"]) + key_len = int.from_bytes(data[:4], 'big') + encrypted_key = data[4:4 + key_len] + encrypted_message = data[4 + key_len:] + + plaintext = HybridCryptoSystem.decrypt(encrypted_key, encrypted_message) + + FileManager.save_bytes(settings["decrypted_file"], plaintext) + + print(f"File decrypted and saved to {settings['decrypted_file']}") + if __name__ == '__main__': main() \ No newline at end of file diff --git a/lab_3/texts/initial_file.txt b/lab_3/texts/initial_file.txt new file mode 100644 index 000000000..6fdc249f0 --- /dev/null +++ b/lab_3/texts/initial_file.txt @@ -0,0 +1,11 @@ +== История разработки == +Впервые список реплик персонажа был составлен 26 мая в документе ''script_replics.doc''. К 28 мая список был переработан, и реплики в тот же день пошли на озвучку. +Первыми были озвучены монологи Торговца ('''trader_monolog1''' и '''trader_monolog2'''), позднее - все остальные реплики. +Реплики вошли в сборку [[Build 1842|'xrCore' build 1842, Jun 17 2004]], и их состав оставался без изменений вплоть до декабря 2004 года. + +3 декабря 2004 года в документе ''scenes_sound.doc'' был составлен новый список реплик для различных персонажей, в том числе и Сидоровича: в него вошли сценарные реплики и реплики про использование КПК. Позднее, 13 декабря, был составлен окончательный вариант, после чего список был отдан на озвучку. К 15 декабря реплики были озвучены, и они вошли в состав сборки [[Build 1994|'xrCore' build 1994, Dec 16 2004]]. Позже реплики были переозвучены, а их содержание переделано, и они вошли уже в состав сборки [[Build 2212|'xrCore' build 2212, Jan 22 2005]]. + + + + + From f02cf4e586ea0fbb7516eb9ac73d2be4bebe84bc Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Mon, 9 Jun 2025 11:48:45 +0400 Subject: [PATCH 09/12] Rework: Key Generation --- lab_3/cryptosystem/asymmetric.py | 98 +++++++++++++++++----------- lab_3/cryptosystem/hybrid_system.py | 64 +++++++++--------- lab_3/cryptosystem/symmetric.py | 78 +++++++++++----------- lab_3/keys/private_key.pem | 52 +++++++-------- lab_3/keys/public_key.pem | 14 ++-- lab_3/keys/symmetric_key.txt | Bin 8 -> 256 bytes lab_3/main.py | 95 ++++++++++++++------------- 7 files changed, 215 insertions(+), 186 deletions(-) diff --git a/lab_3/cryptosystem/asymmetric.py b/lab_3/cryptosystem/asymmetric.py index 3a6c65cb0..2c6b95e4c 100644 --- a/lab_3/cryptosystem/asymmetric.py +++ b/lab_3/cryptosystem/asymmetric.py @@ -1,54 +1,73 @@ from cryptography.hazmat.primitives.asymmetric import rsa, padding -from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.backends import default_backend from file_manager import FileManager class AsymmetricRSA: - def __init__(self, key_size=2048): - self.key_size = key_size - self.private_key = None - self.public_key = None - - def generate_keys(self): - self.private_key = rsa.generate_private_key( + @staticmethod + def generate_keys() -> (rsa.RSAPrivateKey, rsa.RSAPublicKey): + """ + Generates public and private RSA keys + :return: Private key, public key + """ + private_key = rsa.generate_private_key( public_exponent=65537, - key_size=self.key_size, - backend=default_backend() + key_size=2048 ) - self.public_key = self.private_key.public_key() + public_key = private_key.public_key() + return private_key, public_key - def export_keys(self, private_path: str, public_path: str): - private_pem = self.private_key.private_bytes( + @staticmethod + def export_keys(private_key: rsa.RSAPrivateKey, public_key: rsa.RSAPublicKey, + private_path: str, public_path: str) -> None: + """ + Serialization of asymmetric keys + :param private_key: Private key + :param public_key: Public key + :param private_path: Path to file to save private key + :param public_path: Path to file to save public key + :return: None + """ + private_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption() ) - public_pem = self.public_key.public_bytes( + public_pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo ) FileManager.save_bytes(private_path, private_pem) FileManager.save_bytes(public_path, public_pem) - def load_private_key(self, path): - key_data = FileManager.load_bytes(path) - self.private_key = serialization.load_pem_private_key( - key_data, - password=None, - backend=default_backend() - ) + # @staticmethod + # def load_private_key(self, path): + # key_data = FileManager.load_bytes(path) + # self.private_key = serialization.load_pem_private_key( + # key_data, + # password=None, + # backend=default_backend() + # ) + # + # @staticmethod + # def load_public_key(self, path): + # key_data = FileManager.load_bytes(path) + # self.public_key = serialization.load_pem_public_key( + # key_data, + # backend=default_backend() + # ) - def load_public_key(self, path): - key_data = FileManager.load_bytes(path) - self.public_key = serialization.load_pem_public_key( - key_data, - backend=default_backend() - ) - - def encrypt(self, data: bytes) -> bytes: - return self.public_key.encrypt( + @staticmethod + def encrypt(data: bytes, public_key: rsa.RSAPublicKey) -> bytes: + """ + Encrypting data with public rsa-key with using OAEP encrypting standard with SHA256 hash-algorithm + :param data: Data for encryption + :param public_key: Public key + :return: Encrypted data + """ + return public_key.encrypt( data, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), @@ -57,12 +76,13 @@ def encrypt(self, data: bytes) -> bytes: ) ) - def decrypt(self, data: bytes) -> bytes: - return self.private_key.decrypt( - data, - padding.OAEP( - mgf=padding.MGF1(algorithm=hashes.SHA256()), - algorithm=hashes.SHA256(), - label=None - ) - ) \ No newline at end of file + # @staticmethod + # def decrypt(self, data: bytes) -> bytes: + # return self.private_key.decrypt( + # data, + # padding.OAEP( + # mgf=padding.MGF1(algorithm=hashes.SHA256()), + # algorithm=hashes.SHA256(), + # label=None + # ) + # ) \ No newline at end of file diff --git a/lab_3/cryptosystem/hybrid_system.py b/lab_3/cryptosystem/hybrid_system.py index 45c68a502..a131ddffb 100644 --- a/lab_3/cryptosystem/hybrid_system.py +++ b/lab_3/cryptosystem/hybrid_system.py @@ -4,37 +4,39 @@ class HybridCryptoSystem: - asym = AsymmetricRSA() - sym = None - @classmethod - def generate_keys(cls, key_length): - """Generate both RSA and 3DES keys""" - cls.asym.generate_keys() - cls.sym = Symmetric3DES(key_length) - cls.sym.generate_key() + @staticmethod + def generate_keys(key_length: int, private_path: str, public_path: str, symmetric_path: str) -> None: + """ + Hybrid System Key Generation. + :param key_length: Key length for 3DES (64, 128, 192) + :param private_path: Path to file to save private key + :param public_path: Path to file to save public key + :param symmetric_path: Path to the file to save the encrypted symmetric key + :return: None + """ + private_key, public_key = AsymmetricRSA.generate_keys() + symmetric_key = Symmetric3DES.generate_key(key_length) - @classmethod - def save_keys(cls, private_path: str, public_path: str, symmetric_path: str): - """Save all generated keys to files""" - cls.asym.export_keys(private_path, public_path) - FileManager.save_bytes(symmetric_path, cls.sym.key) + AsymmetricRSA.export_keys(private_key, public_key, private_path, public_path) + c_symmetric_key = AsymmetricRSA.encrypt(symmetric_key, public_key) + FileManager.save_bytes(symmetric_path, c_symmetric_key) - @classmethod - def encrypt(cls, plaintext: bytes) -> dict: - """Encrypt data using hybrid approach""" - ct_message = cls.sym.encrypt(plaintext) - ct_key = cls.asym.encrypt(cls.sym.key) - return { - 'encrypted_key': ct_key, - 'encrypted_message': ct_message - } - - @classmethod - def decrypt(cls, encrypted_key: bytes, encrypted_message: bytes) -> bytes: - """Decrypt data using hybrid approach""" - key = cls.asym.decrypt(encrypted_key) - temp_sym = Symmetric3DES(len(key)*8) - temp_sym.key = key - plaintext = temp_sym.decrypt(encrypted_message) - return plaintext \ No newline at end of file + # @staticmethod + # def encrypt(plaintext: bytes) -> dict: + # """Encrypt data using hybrid approach""" + # ct_message = cls.sym.encrypt(plaintext) + # ct_key = cls.asym.encrypt(cls.sym.key) + # return { + # 'encrypted_key': ct_key, + # 'encrypted_message': ct_message + # } + # + # @staticmethod + # def decrypt(encrypted_key: bytes, encrypted_message: bytes) -> bytes: + # """Decrypt data using hybrid approach""" + # key = cls.asym.decrypt(encrypted_key) + # temp_sym = Symmetric3DES(len(key)*8) + # temp_sym.key = key + # plaintext = temp_sym.decrypt(encrypted_message) + # return plaintext \ No newline at end of file diff --git a/lab_3/cryptosystem/symmetric.py b/lab_3/cryptosystem/symmetric.py index 04cf286d4..84098b811 100644 --- a/lab_3/cryptosystem/symmetric.py +++ b/lab_3/cryptosystem/symmetric.py @@ -5,41 +5,43 @@ class Symmetric3DES: - def __init__(self, key_length_bits=192): - if key_length_bits not in (64, 128, 192): - raise ValueError("3DES key length must be 64, 128 or 192 bits") - self.key_length_bytes = key_length_bits // 8 - self.key = None - - def generate_key(self): - self.key = os.urandom(self.key_length_bytes) - - def encrypt(self, plaintext: bytes) -> bytes: - iv = os.urandom(8) # 3DES block size is 8 bytes - padder = sym_padding.PKCS7(64).padder() # 64 bits = 8 bytes block size - padded_data = padder.update(plaintext) + padder.finalize() - - cipher = Cipher( - algorithms.TripleDES(self.key), - modes.CBC(iv), - backend = default_backend() - ) - encryptor = cipher.encryptor() - ciphertext = encryptor.update(padded_data) + encryptor.finalize() - return iv + ciphertext - - def decrypt(self, ciphertext: bytes) -> bytes: - iv = ciphertext[:8] - ct = ciphertext[8:] - - cipher = Cipher( - algorithms.TripleDES(self.key), - modes.CBC(iv), - backend = default_backend() - ) - decryptor = cipher.decryptor() - padded_plaintext = decryptor.update(ct) + decryptor.finalize() - - unpadder = sym_padding.PKCS7(64).unpadder() - plaintext = unpadder.update(padded_plaintext) + unpadder.finalize() - return plaintext \ No newline at end of file + @staticmethod + def generate_key(key_length: int) -> bytes: + """ + Generate a 3DES key of the selected length + :param key_length: Key length (64, 128, 192) + :return: Unencrypted symmetric key + """ + return os.urandom(key_length // 8) + + # @staticmethod + # def encrypt(self, plaintext: bytes) -> bytes: + # iv = os.urandom(8) # 3DES block size is 8 bytes + # padder = sym_padding.PKCS7(64).padder() # 64 bits = 8 bytes block size + # padded_data = padder.update(plaintext) + padder.finalize() + # + # cipher = Cipher( + # algorithms.TripleDES(self.key), + # modes.CBC(iv), + # backend = default_backend() + # ) + # encryptor = cipher.encryptor() + # ciphertext = encryptor.update(padded_data) + encryptor.finalize() + # return iv + ciphertext + # + # @staticmethod + # def decrypt(self, ciphertext: bytes) -> bytes: + # iv = ciphertext[:8] + # ct = ciphertext[8:] + # + # cipher = Cipher( + # algorithms.TripleDES(self.key), + # modes.CBC(iv), + # backend = default_backend() + # ) + # decryptor = cipher.decryptor() + # padded_plaintext = decryptor.update(ct) + decryptor.finalize() + # + # unpadder = sym_padding.PKCS7(64).unpadder() + # plaintext = unpadder.update(padded_plaintext) + unpadder.finalize() + # return plaintext \ No newline at end of file diff --git a/lab_3/keys/private_key.pem b/lab_3/keys/private_key.pem index 042c789b2..8ab3c28fc 100644 --- a/lab_3/keys/private_key.pem +++ b/lab_3/keys/private_key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDSQzUH3kEHAnPf -DbgwOF7ElMy3RNytB0M/3+1FEEuJLm7eFdNp8lxfnq54ND67afBidotHlRYJHMme -dj3z1Rziu9nT7HSlSEkWP7B8hEQwQAhCW6rD6ukuWucTVj3I44IFw/7xVZEtkf2H -3YvyysyDILn3/19mc8BBzvg4sZiQF9hWfhSg5MnB397ziIS8eZDLDRwkD7MIiVdf -w9U8ufuNzwou4hODCacFr4gzCIzthET94KNY+Rl8BjsG7KlpLmoOuk1qpvi/qY4/ -piaEVy8lps/T4NlSzgLjg/vY8RFJc6cAuXqoobzmVn3jiqHz3D+kD80ALp7W0xqC -StCzdWNDAgMBAAECggEABRgZv2oNrnf+ixRP0EmqI7fsycsb6ZlE2NXtCRpSKi2u -altvA6C0LW2wkaFgz7Uxj/RW5YVIKZcn9cETOSzo0tl1EPxbZLglBSpf26ejG0qO -qKtRFNQRK2bwzqtToRVZ/7FcinsY1fJoIq2MbkJzKzSH+bX9mR0+0DL0GQBWHBxc -iQr/rsCTx+XkFN18/SHAydcsHHVeIxaQEZ2J3pKEGxfzPEUEHGjCDgocWSbfTyE5 -JyKYh8t1E72ZGMjiuwEFELphC7S14zW9MWaqXBfYvJhAmihEtHWOb19YbnWznaF5 -MQ9wicwK4CVk631wSOmIFZvt6oDdQprYcmvVrz2ZoQKBgQDwamYJ9EU/Ohs4kKeR -OdIoMQiHiXOqqfBVztzDYm98FhVbCHjXrBLVaRMhZ0V/TDxxG9/hw1bzW2LHNC8q -ReMtuwPj+3VSmNEt14uoA4Ftf0ze4FafNK3Cms9ZAUJhL1TsREu58LuADy9fKjqA -puPJLpK3I+POnk4T6aiM43fyMQKBgQDf5G4V757Xrr3p8swD0tOZKjpPVbg3YAAa -Zhx0ihkNaZe1Xs0BcDe4K4/9JfuJxrqcEmmLcfivbkZBfXwl3eimGhT+RIHo+l+2 -SX4j5iaHDWkxqtBqkApwDTcR7b/UnYHyRi2VcECL8QC0XQgxj328R+QGu19T3pnh -Z+3tzPH7swKBgQCeJP82MQ6UBr79OHphl21crtRzg8EoVF0ZtNeXVtsK/uPRXANR -q4lABLxmzq3yjM19gd6FfZ9muYiCjRsxbYOBA3INt813JbsDsrPVM2kiBAkm2t9g -HqDmUDtwytlFYIM2X76Ic4iDNnns2bReCGnyXsZ33g3uTkgB5UPQWZj/IQKBgHoz -OYqrgK0D6RAZvxSPK4K7s5u9k5BVy3idJwbMoSPa8DzEA2y3jRHuZOaspn/qgcvR -mN3NVQibTalNDke0uNh//9lQFv/MOBVMQ5bgdULdJP9A1gRznd7Ot7IHa95mIZjU -iOi5neFDpzjKVkCGqv/q1SB/gGZMZvzKNujGJYVVAoGBAIcrKhj3G6zpPkpRKxfw -YlttBN2+cX0GCZi301WICV/XI+PCR5PE0PmWkh3Ic3rWU5TD6bYk/E/DFcfbFCva -SV0fCj7OVz2N6CC90waYdJRcWi78srVIs1ej69gkKj8Idb73O2sE2AVHmxPQeM19 -gljPAnfjE2JxqS/7ZhrTuxHO +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqRA81cygbBkUu +kipVeVHcdF/xAnpBt6vm9XtQw/d0pGU1djf80yILYNlfXH2FBDMDSvVzADawEsK2 +Tde8vaHuImdqm0U4m4RuBAxHJiLtRK2ABWg3Ep/hXPdYhogoNMYi6PjP5AFC5xsZ +6123bC5M+BO3c47W7vtWsqqBCrtkOr//6uLyJ0E1BK/EnTMLLFhQ9BJV83KHFuvc +kJI6ds1BB1ZUtgPbAOtW0ayKtQi2sgJUTiL9LeeeqV21NxRCq6Nxaku5EvRTYOWd +1zZILqgkUqnQRZD1L0JXtRcH/y4Fob7gJgvbkmPhI2O6Mi8PJQjr8eMqzDstgAae +7cvblfazAgMBAAECggEAR8jK+rdy1LX3i/Nu6rtsAnyECJoJTlSwIn8jvwDn/uLi +ksAlSbAAPfjWnIhjmSWUllJPmm0gIWq/cdnu13HB6CLUJBOTgxK6KiIFxSd0eUFH +vt5IulNdWcf2tnl9xSm+0XAUmp1f1MOX3v0m9VKkUKoUsfcD5WU7TSmljiMmr1IP +F25hOnvNJVpPjuE2fwu2OLX6Dz7y+/Q7HMJNt8E9Nn35kEC1gTLjL906L7f6ZV9b +MY6kXwGeOLN2/8voIBNJVOYJgzY8QdugB18TOBQyilYJWgFoQV4og/GG0/K+ymY2 +e0B2F02t5VXv/GGmR79ezHkigwUAAvJV3uqdqCQAxQKBgQDhkkA2I/qzUp9g1qgc +zSapHpUhMm5JJ8JukHwj30yzH05IZWtkbAzlgrDz6tjlcxkWs5uwY8+7KGc6QX48 +1HVjVXw5M4qD2LW9q7fy1gYv6m5Pp+SO/tlNT2LbSK06QoHaz3uNEOgilyYUxyoU +kx92AlDh8mw92EnijDRj3h9H3wKBgQDBO+wqAGn1KBkAZ+Slpmygbcp4cJ6rxnen +lCPcw28/fI+f+pCLVpUR+Q4E4a2GGxQgntKIj4mkvlNM3o3uStkGjpw5nj2iD4S9 +P6gGbdUA7/cBeejdSKEgTegTYlId466jxlUazyuHiqu9ahnkGDF8SeO5Gou4flTe +0ZJvuV47rQKBgHyPAvAijARLooCZ5/kHe8q1fYn4TBgPYXkmRbaVTsg2iEbH4jZw +x+pQcaAvVZfWJ8t2YIlVhFcH54Cuu6OhejTg9pirklhd6XWUBh6M+puo60MHJdmk +dqAPLzqBdk6OfSAzpDjwVg8LwdaFaAI2f4/tlXY/JHA+KAZ2f1OKS2GnAoGAD7Wf +bYq7EoNABRhtLkppamGCpGgDflOURrt0bu40jSTDSG5Gcg2H8P4edacjRFPPPxeq +Zg/FUO9oNkehok3TdwUBDm4e9J3uXLRgJKWpO3pGyofuto7BCq9KvsivhF6ORCJL +qPJOx6YucCfAExskasZXDSVrVoRuwe6nyQ1468ECgYBCsicjla8vXI9ujPOpEBYB +qPldXWAjxz56ZHtabQ68ryWlYbKf3LHukPse9hsjRVG9T640qkQA22mfBEWpFwPK +jmi0hH33B4XYbHpIXMij0c+kPYJOkURlavQY4DCSWHGeAd5Mcw0w6Bp/PVo9HLL6 +4MfMMxC20NcHQ2AvQ7l23Q== -----END PRIVATE KEY----- diff --git a/lab_3/keys/public_key.pem b/lab_3/keys/public_key.pem index 3f1138434..e15e84aeb 100644 --- a/lab_3/keys/public_key.pem +++ b/lab_3/keys/public_key.pem @@ -1,9 +1,9 @@ -----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0kM1B95BBwJz3w24MDhe -xJTMt0TcrQdDP9/tRRBLiS5u3hXTafJcX56ueDQ+u2nwYnaLR5UWCRzJnnY989Uc -4rvZ0+x0pUhJFj+wfIREMEAIQluqw+rpLlrnE1Y9yOOCBcP+8VWRLZH9h92L8srM -gyC59/9fZnPAQc74OLGYkBfYVn4UoOTJwd/e84iEvHmQyw0cJA+zCIlXX8PVPLn7 -jc8KLuITgwmnBa+IMwiM7YRE/eCjWPkZfAY7BuypaS5qDrpNaqb4v6mOP6YmhFcv -JabP0+DZUs4C44P72PERSXOnALl6qKG85lZ944qh89w/pA/NAC6e1tMagkrQs3Vj -QwIDAQAB +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqkQPNXMoGwZFLpIqVXlR +3HRf8QJ6Qber5vV7UMP3dKRlNXY3/NMiC2DZX1x9hQQzA0r1cwA2sBLCtk3XvL2h +7iJnaptFOJuEbgQMRyYi7UStgAVoNxKf4Vz3WIaIKDTGIuj4z+QBQucbGetdt2wu +TPgTt3OO1u77VrKqgQq7ZDq//+ri8idBNQSvxJ0zCyxYUPQSVfNyhxbr3JCSOnbN +QQdWVLYD2wDrVtGsirUItrICVE4i/S3nnqldtTcUQqujcWpLuRL0U2Dlndc2SC6o +JFKp0EWQ9S9CV7UXB/8uBaG+4CYL25Jj4SNjujIvDyUI6/HjKsw7LYAGnu3L25X2 +swIDAQAB -----END PUBLIC KEY----- diff --git a/lab_3/keys/symmetric_key.txt b/lab_3/keys/symmetric_key.txt index 8f7d4d5f94e1c6728ea142fd7c39bc5153287e90..c64dd0ef894c9a7f8f4a0a4ee0fb39169f91c80d 100644 GIT binary patch literal 256 zcmV+b0ssD^43h#_THA)bx#yX3G65QA6j1Ras(n-V$^d($X7bUIpa6o&-qT{DWol?dOg2* z$52`dK0kvWt7&yq8^hUf00=+?o)9S)tPJj)-UkIrUw%%{Yt$Wp`Ep literal 8 PcmWHSdU@CQwW|aG5o`mq diff --git a/lab_3/main.py b/lab_3/main.py index 3286733cc..0ffd86b47 100644 --- a/lab_3/main.py +++ b/lab_3/main.py @@ -27,51 +27,56 @@ def parse_arguments() -> argparse.Namespace: return parser.parse_args() def main(): - args = parse_arguments() - settings = FileManager.load_json(args.settings) - - if args.generation: - HybridCryptoSystem.generate_keys(args.key_length) - HybridCryptoSystem.save_keys( - settings["private_key"], - settings["public_key"], - settings["symmetric_key"] - ) - print( - f"Keys generated and saved:\n" - f" - Private key: {settings['private_key']}\n" - f" - Public key: {settings['public_key']}\n" - f" - Symmetric key: {settings['symmetric_key']}" - ) - elif args.encryption: - HybridCryptoSystem.asym.load_public_key(settings["public_key"]) - HybridCryptoSystem.sym.generate_key() - - plaintext = FileManager.load_bytes(settings["initial_file"]) - - encrypted_data = HybridCryptoSystem.encrypt(plaintext) - - data_to_save = ( - len(encrypted_data['encrypted_key']).to_bytes(4, 'big') + - encrypted_data['encrypted_key'] + - encrypted_data['encrypted_message'] - ) - FileManager.save_bytes(settings["encrypted_file"], data_to_save) - - print(f"File encrypted and saved to {settings['encrypted_file']}") - elif args.decryption: - HybridCryptoSystem.asym.load_private_key(settings["private_key"]) - - data = FileManager.load_bytes(settings["encrypted_file"]) - key_len = int.from_bytes(data[:4], 'big') - encrypted_key = data[4:4 + key_len] - encrypted_message = data[4 + key_len:] - - plaintext = HybridCryptoSystem.decrypt(encrypted_key, encrypted_message) - - FileManager.save_bytes(settings["decrypted_file"], plaintext) - - print(f"File decrypted and saved to {settings['decrypted_file']}") + try: + args = parse_arguments() + if args.key_length not in (64, 128, 192): + raise ValueError("3DES key length must be 64, 128 or 192 bits") + settings = FileManager.load_json(args.settings) + + if args.generation: + HybridCryptoSystem.generate_keys( + args.key_length, + settings["private_key"], + settings["public_key"], + settings["symmetric_key"] + ) + print( + f"Keys generated and saved:\n" + f" - Private key: {settings['private_key']}\n" + f" - Public key: {settings['public_key']}\n" + f" - Symmetric key: {settings['symmetric_key']}" + ) + # elif args.encryption: + # HybridCryptoSystem.asym.load_public_key(settings["public_key"]) + # HybridCryptoSystem.sym.generate_key() + # + # plaintext = FileManager.load_bytes(settings["initial_file"]) + # + # encrypted_data = HybridCryptoSystem.encrypt(plaintext) + # + # data_to_save = ( + # len(encrypted_data['encrypted_key']).to_bytes(4, 'big') + + # encrypted_data['encrypted_key'] + + # encrypted_data['encrypted_message'] + # ) + # FileManager.save_bytes(settings["encrypted_file"], data_to_save) + # + # print(f"File encrypted and saved to {settings['encrypted_file']}") + # elif args.decryption: + # HybridCryptoSystem.asym.load_private_key(settings["private_key"]) + # + # data = FileManager.load_bytes(settings["encrypted_file"]) + # key_len = int.from_bytes(data[:4], 'big') + # encrypted_key = data[4:4 + key_len] + # encrypted_message = data[4 + key_len:] + # + # plaintext = HybridCryptoSystem.decrypt(encrypted_key, encrypted_message) + # + # FileManager.save_bytes(settings["decrypted_file"], plaintext) + # + # print(f"File decrypted and saved to {settings['decrypted_file']}") + except Exception as e: + print("Error:", e) if __name__ == '__main__': From 1f403681bfdb0a25caefca8abe752d0eb4294cb8 Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Mon, 9 Jun 2025 13:03:11 +0400 Subject: [PATCH 10/12] Rework: Data encryption --- lab_3/cryptosystem/asymmetric.py | 58 ++++++++++++++++++---------- lab_3/cryptosystem/hybrid_system.py | 21 +++++----- lab_3/cryptosystem/symmetric.py | 36 ++++++++++------- lab_3/file_manager.py | 33 +++++++++++++++- lab_3/main.py | 26 +++++-------- lab_3/texts/encrypted_file.txt | Bin 0 -> 1632 bytes 6 files changed, 111 insertions(+), 63 deletions(-) create mode 100644 lab_3/texts/encrypted_file.txt diff --git a/lab_3/cryptosystem/asymmetric.py b/lab_3/cryptosystem/asymmetric.py index 2c6b95e4c..89b32c907 100644 --- a/lab_3/cryptosystem/asymmetric.py +++ b/lab_3/cryptosystem/asymmetric.py @@ -1,6 +1,7 @@ from cryptography.hazmat.primitives.asymmetric import rsa, padding from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.backends import default_backend +from cryptography.exceptions import UnsupportedAlgorithm from file_manager import FileManager @@ -42,15 +43,26 @@ def export_keys(private_key: rsa.RSAPrivateKey, public_key: rsa.RSAPublicKey, FileManager.save_bytes(private_path, private_pem) FileManager.save_bytes(public_path, public_pem) - # @staticmethod - # def load_private_key(self, path): - # key_data = FileManager.load_bytes(path) - # self.private_key = serialization.load_pem_private_key( - # key_data, - # password=None, - # backend=default_backend() - # ) - # + @staticmethod + def load_private_key(path: str) -> rsa.RSAPrivateKey: + """ + Loads a private key from a file and deserializes it + :param path: Path to file to load private key + :return: private key + """ + try: + key_data = FileManager.load_bytes(path) + private_key = serialization.load_pem_private_key( + key_data, + password=None, + backend=default_backend() + ) + return private_key + except UnsupportedAlgorithm: + raise Exception("Unsupported key algorithm") + except ValueError: + raise Exception("Invalid key format") + # @staticmethod # def load_public_key(self, path): # key_data = FileManager.load_bytes(path) @@ -62,7 +74,7 @@ def export_keys(private_key: rsa.RSAPrivateKey, public_key: rsa.RSAPublicKey, @staticmethod def encrypt(data: bytes, public_key: rsa.RSAPublicKey) -> bytes: """ - Encrypting data with public rsa-key with using OAEP encrypting standard with SHA256 hash-algorithm + Encrypting data with public RSA key with using OAEP encrypting standard with SHA256 hash-algorithm :param data: Data for encryption :param public_key: Public key :return: Encrypted data @@ -76,13 +88,19 @@ def encrypt(data: bytes, public_key: rsa.RSAPublicKey) -> bytes: ) ) - # @staticmethod - # def decrypt(self, data: bytes) -> bytes: - # return self.private_key.decrypt( - # data, - # padding.OAEP( - # mgf=padding.MGF1(algorithm=hashes.SHA256()), - # algorithm=hashes.SHA256(), - # label=None - # ) - # ) \ No newline at end of file + @staticmethod + def decrypt(data: bytes, private_key: rsa.RSAPrivateKey) -> bytes: + """ + Decrypting data with public RSA key with using OAEP encrypting standard with SHA256 hash-algorithm + :param data: Data for decryption + :param private_key: Private key + :return: Decrypted data + """ + return private_key.decrypt( + data, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) + ) \ No newline at end of file diff --git a/lab_3/cryptosystem/hybrid_system.py b/lab_3/cryptosystem/hybrid_system.py index a131ddffb..5fe99fdee 100644 --- a/lab_3/cryptosystem/hybrid_system.py +++ b/lab_3/cryptosystem/hybrid_system.py @@ -22,16 +22,17 @@ def generate_keys(key_length: int, private_path: str, public_path: str, symmetri c_symmetric_key = AsymmetricRSA.encrypt(symmetric_key, public_key) FileManager.save_bytes(symmetric_path, c_symmetric_key) - # @staticmethod - # def encrypt(plaintext: bytes) -> dict: - # """Encrypt data using hybrid approach""" - # ct_message = cls.sym.encrypt(plaintext) - # ct_key = cls.asym.encrypt(cls.sym.key) - # return { - # 'encrypted_key': ct_key, - # 'encrypted_message': ct_message - # } - # + @staticmethod + def encrypt(file_path: str, private_path: str, symmetric_path: str, save_path: str) -> None: + """Encrypt data using hybrid approach""" + c_symmetric_key = FileManager.load_bytes(symmetric_path) + private_key = AsymmetricRSA.load_private_key(private_path) + text = FileManager.read_file(file_path) + + symmetric_key = AsymmetricRSA.decrypt(c_symmetric_key, private_key) + encrypted_text = Symmetric3DES.encrypt(text.encode('utf-8'), symmetric_key) + FileManager.save_bytes(save_path, encrypted_text) + # @staticmethod # def decrypt(encrypted_key: bytes, encrypted_message: bytes) -> bytes: # """Decrypt data using hybrid approach""" diff --git a/lab_3/cryptosystem/symmetric.py b/lab_3/cryptosystem/symmetric.py index 84098b811..6bd401384 100644 --- a/lab_3/cryptosystem/symmetric.py +++ b/lab_3/cryptosystem/symmetric.py @@ -14,21 +14,27 @@ def generate_key(key_length: int) -> bytes: """ return os.urandom(key_length // 8) - # @staticmethod - # def encrypt(self, plaintext: bytes) -> bytes: - # iv = os.urandom(8) # 3DES block size is 8 bytes - # padder = sym_padding.PKCS7(64).padder() # 64 bits = 8 bytes block size - # padded_data = padder.update(plaintext) + padder.finalize() - # - # cipher = Cipher( - # algorithms.TripleDES(self.key), - # modes.CBC(iv), - # backend = default_backend() - # ) - # encryptor = cipher.encryptor() - # ciphertext = encryptor.update(padded_data) + encryptor.finalize() - # return iv + ciphertext - # + @staticmethod + def encrypt(data: bytes, key: bytes) -> bytes: + """ + Encrypting data with 3DES algorythm in Cipher Block Chaining mode with random initialization vector + :param data: Data for encryption + :param key: Symmetric key + :return: Encrypted data + """ + iv = os.urandom(8) # 3DES block size + padder = sym_padding.PKCS7(64).padder() # 64 bits = 8 bytes block size + padded_data = padder.update(data) + padder.finalize() + + cipher = Cipher( + algorithms.TripleDES(key), + modes.CBC(iv), + backend = default_backend() + ) + encryptor = cipher.encryptor() + ciphertext = encryptor.update(padded_data) + encryptor.finalize() + return iv + ciphertext + # @staticmethod # def decrypt(self, ciphertext: bytes) -> bytes: # iv = ciphertext[:8] diff --git a/lab_3/file_manager.py b/lab_3/file_manager.py index 6db5b2e9d..111ba5eaf 100644 --- a/lab_3/file_manager.py +++ b/lab_3/file_manager.py @@ -47,4 +47,35 @@ def load_json(json_path: str) -> dict: except FileNotFoundError: raise FileNotFoundError(f"JSON file not found: {json_path}") except json.JSONDecodeError: - raise ValueError(f"Invalid JSON format in file: {json_path}") \ No newline at end of file + raise ValueError(f"Invalid JSON format in file: {json_path}") + + @staticmethod + def read_file(filename: str) -> str: + """ + Opens text file from given directory + :param filename: Directory to file + :return: String with file contents + """ + try: + with open(filename, "r", encoding = "utf-8") as file: + return file.read() + except FileNotFoundError as e: + print(f"File doesn't exist or the path specified is invalid: {e}") + except PermissionError as e: + print(f"Can't access this file: {e}") + except Exception as e: + print(f"Error reading file: {e}. Check for correct data") + + @staticmethod + def write_file(filename: str, data: str) -> None: + """ + Saves string to .txt file + :param filename: Path to .txt file + :param data: Contents for file + :return: None + """ + try: + with open(filename, "w", encoding = "utf-8") as file: + file.write(data) + except Exception as e: + print(f"Something went wrong: {e}") \ No newline at end of file diff --git a/lab_3/main.py b/lab_3/main.py index 0ffd86b47..7b7209a02 100644 --- a/lab_3/main.py +++ b/lab_3/main.py @@ -46,22 +46,14 @@ def main(): f" - Public key: {settings['public_key']}\n" f" - Symmetric key: {settings['symmetric_key']}" ) - # elif args.encryption: - # HybridCryptoSystem.asym.load_public_key(settings["public_key"]) - # HybridCryptoSystem.sym.generate_key() - # - # plaintext = FileManager.load_bytes(settings["initial_file"]) - # - # encrypted_data = HybridCryptoSystem.encrypt(plaintext) - # - # data_to_save = ( - # len(encrypted_data['encrypted_key']).to_bytes(4, 'big') + - # encrypted_data['encrypted_key'] + - # encrypted_data['encrypted_message'] - # ) - # FileManager.save_bytes(settings["encrypted_file"], data_to_save) - # - # print(f"File encrypted and saved to {settings['encrypted_file']}") + elif args.encryption: + HybridCryptoSystem.encrypt( + settings["initial_file"], + settings["private_key"], + settings["symmetric_key"], + settings["encrypted_file"] + ) + print(f"File encrypted and saved to {settings['encrypted_file']}") # elif args.decryption: # HybridCryptoSystem.asym.load_private_key(settings["private_key"]) # @@ -76,7 +68,7 @@ def main(): # # print(f"File decrypted and saved to {settings['decrypted_file']}") except Exception as e: - print("Error:", e) + print(f"Error: {e}") if __name__ == '__main__': diff --git a/lab_3/texts/encrypted_file.txt b/lab_3/texts/encrypted_file.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d1fc13f2a59d3ebcb2fa3d4b18fae8897108d42 GIT binary patch literal 1632 zcmV-m2A}zTR0d@mO)S(DrB6F>CeE5)02a@0Mb(P|*uMW;na%p0;}*Ic@cDoF`tOPt z+a2c>O6G{l_TaD4c*hKO1v@lG>~yS-Q=vII#35f$(w$&e@p#N;2cegzG!j(|O_l8L z*J_w{^UX(|la2930l8+MaILZX2g@Uh2w=of2&7@5po?hjO_t%~f!L1q0TjZjl40oQM9vdqOj2> zng;4j=QTHZ)6Y?LKH_tN6=^QlSoD`s<65L|)*)^Ugy0(KQRNH?qe?3Ulx>(WJT$rW zBt0+Fq*O^9Sp%S{G#Vc=XG{^jap`Hv%HPg~GFp=TY>No2w{ZTYVp14(hXYzU#G(SY zAFL@W@xk8IT)7U})s|OJ@-vF8IfOMaesoIybW5;?4G2|UqnEPta5W(>-YT6`>$RVS z@P4;;R1!KstB^)2kR$V<^e0?AdAX;x%QSKe6O1^_A`tz4f$pzpO)9ho9wCYcbW&_TM4CasXCjv$D=uqNkGj2gXYmGRWPsHQf-1xu4TGXtu72-uak7fj(S#ju_Gl(LTvaRH@U8!D}2yZA8$KRRaRQrrqtj7Rz>O z>r4;KR#TUbM}}>G3NlIn5cK)Y(K%@Ei(5D~oZ&W58zl(|dgs9v;9}EZQy;XxF*N*w zBdecjHBdgS9%qS)7<6Hu&2#Vwc;R!5S?6TBhRpX_Ukkwb>=dK@Q>jGWC@xTkPPdZh zuE#kE+QxPAU>xQj8iF}mDAYwpZ;!_5*@V8y32MfrBO;fgF+q56k4ukfhc%9M)jZUW zjR8K2-PMt%?CdFeZ1F9YxT{$MV##>x#)J}l4xL_=C-#z3b@;_Q#T{FE$|6BkjO~+~ zdeHIS0`OP|oFnA7JRa6wo+---QNyeHZ8J$K1zO`OYx}c7%tN;{*+z!5ShuNgf%W05 zG?d^0CF1SOGZV^6-yZlqa37E^shUp6Jw|@TMK+RMxbU4-j9le4NfBzh6>@-n2 zgYAKB%0BdwOj+cV+{;)Um4&I+t6~CIxl?xR&wLl z0Xcmt1yYq|?CTJZSFNxJTHOioUUQJzG4;DQGeu}ZxUv4ssUZGR)R!8;K*27!*k^eN zJL!{6lAVpV$n>KAqW+u!x}|6utu~t1Nj?*rRAhyDT1*WNlqb;l+w94tgJ(0cd+<@h zzQG(z=g{v2rWwtPDxigNlyP<^rc2Oo`5B|DA$K5p=uNC*Norv~t1Cn?mEa_A@-Z?? z<)Z6Oa5+$8p2gmhN7C=As@o!UbE^#JUY9a`oj#atf{!$)7~ zPo%ppznMl{IuTXdlZzw4&+|S?52?8Yy|@Ujiws&HaU;JJI;)uZP46R-p_bSE%1^2k eoIRXWMSc3M(~DMn>R1%Yd5{}+efk{pd(o-tbvJ Date: Mon, 9 Jun 2025 14:05:36 +0400 Subject: [PATCH 11/12] Rework: Data decryption --- lab_3/cryptosystem/asymmetric.py | 8 ------ lab_3/cryptosystem/hybrid_system.py | 35 ++++++++++++++++++------- lab_3/cryptosystem/symmetric.py | 40 +++++++++++++++++------------ lab_3/main.py | 23 +++++++---------- lab_3/texts/decrypted_file.txt | 11 ++++++++ 5 files changed, 69 insertions(+), 48 deletions(-) create mode 100644 lab_3/texts/decrypted_file.txt diff --git a/lab_3/cryptosystem/asymmetric.py b/lab_3/cryptosystem/asymmetric.py index 89b32c907..d4ba2493e 100644 --- a/lab_3/cryptosystem/asymmetric.py +++ b/lab_3/cryptosystem/asymmetric.py @@ -63,14 +63,6 @@ def load_private_key(path: str) -> rsa.RSAPrivateKey: except ValueError: raise Exception("Invalid key format") - # @staticmethod - # def load_public_key(self, path): - # key_data = FileManager.load_bytes(path) - # self.public_key = serialization.load_pem_public_key( - # key_data, - # backend=default_backend() - # ) - @staticmethod def encrypt(data: bytes, public_key: rsa.RSAPublicKey) -> bytes: """ diff --git a/lab_3/cryptosystem/hybrid_system.py b/lab_3/cryptosystem/hybrid_system.py index 5fe99fdee..85965290e 100644 --- a/lab_3/cryptosystem/hybrid_system.py +++ b/lab_3/cryptosystem/hybrid_system.py @@ -24,7 +24,14 @@ def generate_keys(key_length: int, private_path: str, public_path: str, symmetri @staticmethod def encrypt(file_path: str, private_path: str, symmetric_path: str, save_path: str) -> None: - """Encrypt data using hybrid approach""" + """ + Data encryption by hybrid system + :param file_path: Path to the file to encrypt + :param private_path: Path to file to load private key + :param symmetric_path: Path to the file to load the encrypted symmetric key + :param save_path: Path to file to save encrypted data + :return: + """ c_symmetric_key = FileManager.load_bytes(symmetric_path) private_key = AsymmetricRSA.load_private_key(private_path) text = FileManager.read_file(file_path) @@ -33,11 +40,21 @@ def encrypt(file_path: str, private_path: str, symmetric_path: str, save_path: s encrypted_text = Symmetric3DES.encrypt(text.encode('utf-8'), symmetric_key) FileManager.save_bytes(save_path, encrypted_text) - # @staticmethod - # def decrypt(encrypted_key: bytes, encrypted_message: bytes) -> bytes: - # """Decrypt data using hybrid approach""" - # key = cls.asym.decrypt(encrypted_key) - # temp_sym = Symmetric3DES(len(key)*8) - # temp_sym.key = key - # plaintext = temp_sym.decrypt(encrypted_message) - # return plaintext \ No newline at end of file + @staticmethod + def decrypt(file_path: str, private_path: str, symmetric_path: str, save_path: str) -> None: + """ + Data decryption by hybrid system + :param file_path: Path to the file to decrypt + :param private_path: Path to file to load private key + :param symmetric_path: Path to the file to load the encrypted symmetric key + :param save_path: Path to file to save decrypted data + :return: + """ + c_symmetric_key = FileManager.load_bytes(symmetric_path) + private_key = AsymmetricRSA.load_private_key(private_path) + text = FileManager.load_bytes(file_path) + + symmetric_key = AsymmetricRSA.decrypt(c_symmetric_key, private_key) + decrypted_text = Symmetric3DES.decrypt(text, symmetric_key) + FileManager.write_file(save_path, decrypted_text.decode('utf-8')) + diff --git a/lab_3/cryptosystem/symmetric.py b/lab_3/cryptosystem/symmetric.py index 6bd401384..0d8aee5d3 100644 --- a/lab_3/cryptosystem/symmetric.py +++ b/lab_3/cryptosystem/symmetric.py @@ -23,7 +23,7 @@ def encrypt(data: bytes, key: bytes) -> bytes: :return: Encrypted data """ iv = os.urandom(8) # 3DES block size - padder = sym_padding.PKCS7(64).padder() # 64 bits = 8 bytes block size + padder = sym_padding.PKCS7(algorithms.TripleDES.block_size).padder() # 64 bits = 8 bytes block size padded_data = padder.update(data) + padder.finalize() cipher = Cipher( @@ -35,19 +35,25 @@ def encrypt(data: bytes, key: bytes) -> bytes: ciphertext = encryptor.update(padded_data) + encryptor.finalize() return iv + ciphertext - # @staticmethod - # def decrypt(self, ciphertext: bytes) -> bytes: - # iv = ciphertext[:8] - # ct = ciphertext[8:] - # - # cipher = Cipher( - # algorithms.TripleDES(self.key), - # modes.CBC(iv), - # backend = default_backend() - # ) - # decryptor = cipher.decryptor() - # padded_plaintext = decryptor.update(ct) + decryptor.finalize() - # - # unpadder = sym_padding.PKCS7(64).unpadder() - # plaintext = unpadder.update(padded_plaintext) + unpadder.finalize() - # return plaintext \ No newline at end of file + @staticmethod + def decrypt(data: bytes, key: bytes) -> bytes: + """ + Decrypting data with 3DES algorythm in Cipher Block Chaining mode with random initialization vector + :param data: Data for decryption + :param key: Symmetric key + :return: Decrypted data + """ + iv = data[:8] + ct = data[8:] + + cipher = Cipher( + algorithms.TripleDES(key), + modes.CBC(iv), + backend = default_backend() + ) + decryptor = cipher.decryptor() + padded_data = decryptor.update(ct) + decryptor.finalize() + + unpadder = sym_padding.PKCS7(algorithms.TripleDES.block_size).unpadder() + data = unpadder.update(padded_data) + unpadder.finalize() + return data \ No newline at end of file diff --git a/lab_3/main.py b/lab_3/main.py index 7b7209a02..a2101e398 100644 --- a/lab_3/main.py +++ b/lab_3/main.py @@ -7,7 +7,7 @@ def parse_arguments() -> argparse.Namespace: """ Function parses arguments from cmd - :return: object with arguments + :return: Object with arguments """ parser = argparse.ArgumentParser( description = "Hybrid crypto system (RSA + 3DES)", @@ -54,19 +54,14 @@ def main(): settings["encrypted_file"] ) print(f"File encrypted and saved to {settings['encrypted_file']}") - # elif args.decryption: - # HybridCryptoSystem.asym.load_private_key(settings["private_key"]) - # - # data = FileManager.load_bytes(settings["encrypted_file"]) - # key_len = int.from_bytes(data[:4], 'big') - # encrypted_key = data[4:4 + key_len] - # encrypted_message = data[4 + key_len:] - # - # plaintext = HybridCryptoSystem.decrypt(encrypted_key, encrypted_message) - # - # FileManager.save_bytes(settings["decrypted_file"], plaintext) - # - # print(f"File decrypted and saved to {settings['decrypted_file']}") + elif args.decryption: + HybridCryptoSystem.decrypt( + settings["encrypted_file"], + settings["private_key"], + settings["symmetric_key"], + settings["decrypted_file"] + ) + print(f"File decrypted and saved to {settings['decrypted_file']}") except Exception as e: print(f"Error: {e}") diff --git a/lab_3/texts/decrypted_file.txt b/lab_3/texts/decrypted_file.txt new file mode 100644 index 000000000..6fdc249f0 --- /dev/null +++ b/lab_3/texts/decrypted_file.txt @@ -0,0 +1,11 @@ +== История разработки == +Впервые список реплик персонажа был составлен 26 мая в документе ''script_replics.doc''. К 28 мая список был переработан, и реплики в тот же день пошли на озвучку. +Первыми были озвучены монологи Торговца ('''trader_monolog1''' и '''trader_monolog2'''), позднее - все остальные реплики. +Реплики вошли в сборку [[Build 1842|'xrCore' build 1842, Jun 17 2004]], и их состав оставался без изменений вплоть до декабря 2004 года. + +3 декабря 2004 года в документе ''scenes_sound.doc'' был составлен новый список реплик для различных персонажей, в том числе и Сидоровича: в него вошли сценарные реплики и реплики про использование КПК. Позднее, 13 декабря, был составлен окончательный вариант, после чего список был отдан на озвучку. К 15 декабря реплики были озвучены, и они вошли в состав сборки [[Build 1994|'xrCore' build 1994, Dec 16 2004]]. Позже реплики были переозвучены, а их содержание переделано, и они вошли уже в состав сборки [[Build 2212|'xrCore' build 2212, Jan 22 2005]]. + + + + + From 68251e26fa314fbf63d0eea82e3677efac6547b2 Mon Sep 17 00:00:00 2001 From: RomaError5 Date: Mon, 9 Jun 2025 14:09:53 +0400 Subject: [PATCH 12/12] PEP-8 --- lab_3/cryptosystem/symmetric.py | 4 ++-- lab_3/file_manager.py | 4 ++-- lab_3/main.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lab_3/cryptosystem/symmetric.py b/lab_3/cryptosystem/symmetric.py index 0d8aee5d3..393358022 100644 --- a/lab_3/cryptosystem/symmetric.py +++ b/lab_3/cryptosystem/symmetric.py @@ -29,7 +29,7 @@ def encrypt(data: bytes, key: bytes) -> bytes: cipher = Cipher( algorithms.TripleDES(key), modes.CBC(iv), - backend = default_backend() + backend=default_backend() ) encryptor = cipher.encryptor() ciphertext = encryptor.update(padded_data) + encryptor.finalize() @@ -49,7 +49,7 @@ def decrypt(data: bytes, key: bytes) -> bytes: cipher = Cipher( algorithms.TripleDES(key), modes.CBC(iv), - backend = default_backend() + backend=default_backend() ) decryptor = cipher.decryptor() padded_data = decryptor.update(ct) + decryptor.finalize() diff --git a/lab_3/file_manager.py b/lab_3/file_manager.py index 111ba5eaf..f595e97ed 100644 --- a/lab_3/file_manager.py +++ b/lab_3/file_manager.py @@ -57,7 +57,7 @@ def read_file(filename: str) -> str: :return: String with file contents """ try: - with open(filename, "r", encoding = "utf-8") as file: + with open(filename, "r", encoding="utf-8") as file: return file.read() except FileNotFoundError as e: print(f"File doesn't exist or the path specified is invalid: {e}") @@ -75,7 +75,7 @@ def write_file(filename: str, data: str) -> None: :return: None """ try: - with open(filename, "w", encoding = "utf-8") as file: + with open(filename, "w", encoding="utf-8") as file: file.write(data) except Exception as e: print(f"Something went wrong: {e}") \ No newline at end of file diff --git a/lab_3/main.py b/lab_3/main.py index a2101e398..48fa71762 100644 --- a/lab_3/main.py +++ b/lab_3/main.py @@ -13,7 +13,7 @@ def parse_arguments() -> argparse.Namespace: description = "Hybrid crypto system (RSA + 3DES)", formatter_class = argparse.ArgumentDefaultsHelpFormatter ) - parser.add_argument('-s', '--settings', default = 'settings.json', + parser.add_argument('-s', '--settings', default='settings.json', help = 'Path to JSON file containing settings') parser.add_argument('-k', '--key_length', type = int, choices = [64, 128, 192], default = 192,