Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/lab_2/task_1/
/lab_2/task_2/
98 changes: 98 additions & 0 deletions lab_3/cryptosystem/asymmetric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
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


class AsymmetricRSA:
@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=2048
)
public_key = private_key.public_key()
return private_key, public_key

@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 = 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)

@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 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()),
algorithm=hashes.SHA256(),
label=None
)
)

@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
)
)
60 changes: 60 additions & 0 deletions lab_3/cryptosystem/hybrid_system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from .asymmetric import AsymmetricRSA
from file_manager import FileManager
from .symmetric import Symmetric3DES


class HybridCryptoSystem:

@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)

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)

@staticmethod
def encrypt(file_path: str, private_path: str, symmetric_path: str, save_path: str) -> None:
"""
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)

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(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'))

59 changes: 59 additions & 0 deletions lab_3/cryptosystem/symmetric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
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:
@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(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(algorithms.TripleDES.block_size).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(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
81 changes: 81 additions & 0 deletions lab_3/file_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import json


class FileManager:

@staticmethod
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 FileNotFoundError:
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:
"""
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 FileNotFoundError:
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:
"""
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 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}")
28 changes: 28 additions & 0 deletions lab_3/keys/private_key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
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-----
9 changes: 9 additions & 0 deletions lab_3/keys/public_key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqkQPNXMoGwZFLpIqVXlR
3HRf8QJ6Qber5vV7UMP3dKRlNXY3/NMiC2DZX1x9hQQzA0r1cwA2sBLCtk3XvL2h
7iJnaptFOJuEbgQMRyYi7UStgAVoNxKf4Vz3WIaIKDTGIuj4z+QBQucbGetdt2wu
TPgTt3OO1u77VrKqgQq7ZDq//+ri8idBNQSvxJ0zCyxYUPQSVfNyhxbr3JCSOnbN
QQdWVLYD2wDrVtGsirUItrICVE4i/S3nnqldtTcUQqujcWpLuRL0U2Dlndc2SC6o
JFKp0EWQ9S9CV7UXB/8uBaG+4CYL25Jj4SNjujIvDyUI6/HjKsw7LYAGnu3L25X2
swIDAQAB
-----END PUBLIC KEY-----
Binary file added lab_3/keys/symmetric_key.txt
Binary file not shown.
Loading