This commit is contained in:
stirelshka8_BigARM 2025-03-02 17:58:27 +03:00
commit 510c5f779c
6 changed files with 456 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/.venv/
/keys/
*.pem
/output.txt

158
README.md Normal file
View File

@ -0,0 +1,158 @@
***
# Шифрование/дешифрование с использованием RSA ключей (закрытый и открытый ключи).
## Описание модулей:
### **1. Генерация и сохранение ключей**
Класс RSAKeyPair предназначен для генерации и сохранения пары ключей RSA (приватного и публичного). Вот подробное описание его работы и принципа функционирования:
▎Описание класса RSAKeyPair
1. Инициализация:
• Конструктор класса (__init__) принимает два параметра: имена файлов для сохранения приватного и публичного ключей.
• Он инициализирует атрибуты для хранения ключей и имен файлов.
2. Генерация приватного ключа:
• Метод generate_private_key создает приватный ключ RSA с использованием алгоритма RSA с длиной ключа 2048 бит и публичным экспонентом 65537.
• Этот метод использует библиотеку cryptography для генерации ключа.
3. Генерация публичного ключа:
• Метод generate_public_key извлекает публичный ключ из ранее сгенерированного приватного ключа.
• Если приватный ключ еще не был сгенерирован, метод вызывает исключение ValueError.
4. Сохранение приватного ключа:
• Метод save_private_key сохраняет приватный ключ в указанный файл в формате PEM без шифрования.
• Если приватный ключ не был сгенерирован, метод вызывает исключение ValueError.
5. Сохранение публичного ключа:
• Метод save_public_key сохраняет публичный ключ в указанный файл в формате PEM.
• Если публичный ключ не был сгенерирован, метод вызывает исключение ValueError.
6. Генерация и сохранение ключей:
• Метод generate_and_save_keys проверяет, существуют ли файлы для приватного и публичного ключей. Если оба файла отсутствуют, он генерирует приватный ключ, сохраняет его, затем генерирует публичный ключ и также сохраняет его.
• Если файлы уже существуют, метод просто выводит сообщение в консоль и не вызывает исключения.
▎Принцип работы
1. Создание экземпляра класса: Пользователь создает экземпляр класса RSAKeyPair, указывая файлы для сохранения ключей.
2. Генерация ключей: Пользователь вызывает метод generate_and_save_keys, который проверяет наличие файлов. Если они не существуют, вызываются методы для генерации и сохранения ключей.
3. Работа с файлами: Приватный и публичный ключи сохраняются в файлы в формате PEM, что позволяет легко использовать их в других приложениях или библиотеках.
4. Обработка ошибок: Класс обрабатывает случаи, когда попытка сохранить ключи осуществляется до их генерации, или когда файлы уже существуют, что делает его удобным для использования в различных сценариях.
Таким образом, класс RSAKeyPair предоставляет простой интерфейс для работы с RSA-ключами, включая их генерацию и сохранение в файлы.
### **2. Шифрование**
Класс RSAEncryptor предназначен для шифрования сообщений с использованием открытого ключа RSA. Он загружает открытый ключ из файла и предоставляет метод для шифрования сообщений. Шифрование выполняется с использованием схемы OAEP (Optimal Asymmetric Encryption Padding) с хешированием SHA-256.
▎Принцип работы
1. Инициализация:
• Класс RSAEncryptor инициализируется с именем файла, содержащим открытый ключ.
В методе init вызывается функция load_public_key, которая загружает открытый ключ из указанного файла.
2. Загрузка открытого ключа:
• Метод load_public_key открывает файл с открытым ключом, считывает его содержимое и десериализует его в объект открытого ключа RSA с помощью функции serialization.load_pem_public_key.
3. Шифрование сообщения:
• Метод encrypt_message принимает строку (сообщение) в качестве параметра.
• Сообщение кодируется в байты и затем шифруется с использованием открытого ключа и схемы OAEP.
• OAEP использует MGF1 (Mask Generation Function) с алгоритмом SHA-256 для обеспечения безопасности шифрования.
• Защищенное сообщение затем кодируется в Base64 для удобства передачи и хранения.
4. Возврат зашифрованного сообщения:
• Метод возвращает зашифрованное сообщение в виде строки, закодированной в Base64.
▎Пример использования
~~~ python
# Создание экземпляра RSAEncryptor
encryptor = RSAEncryptor('path/to/public_key.pem')
# Шифрование сообщения
encrypted_message = encryptor.encrypt_message('Hello, World!')
print(encrypted_message)
~~~
▎Замечания
• Для работы данного класса необходимо, чтобы файл с открытым ключом был доступен и содержал корректный PEM-формат.
• RSA обычно используется для шифрования небольших объемов данных, поэтому для больших сообщений может потребоваться использование симметричного шифрования (например, AES) в сочетании с RSA для безопасной передачи симметричного ключа.
### **3. Расшифрование**
Класс RSADecryptor предназначен для расшифровки сообщений, зашифрованных с использованием алгоритма RSA. Он загружает закрытый ключ из файла и предоставляет метод для расшифровки сообщений, которые были зашифрованы с использованием схемы OAEP (Optimal Asymmetric Encryption Padding) с хешированием SHA-256.
▎Принцип работы
1. Инициализация:
• Класс RSADecryptor инициализируется с именем файла, содержащим закрытый ключ.
В методе init вызывается функция load_private_key, которая загружает закрытый ключ из указанного файла.
2. Загрузка закрытого ключа:
• Метод load_private_key открывает файл с закрытым ключом, считывает его содержимое и десериализует его в объект закрытого ключа RSA с помощью функции serialization.load_pem_private_key.
• Важно, чтобы файл содержал закрытый ключ в формате PEM.
3. Расшифровка сообщения:
• Метод decrypt_message принимает строку (зашифрованное сообщение) в качестве параметра.
• Зашифрованное сообщение декодируется из Base64 в байты.
• Затем сообщение расшифровывается с использованием закрытого ключа и схемы OAEP.
• OAEP использует MGF1 (Mask Generation Function) с алгоритмом SHA-256 для обеспечения безопасности расшифровки.
• Расшифрованное сообщение возвращается в виде строки.
4. Возврат расшифрованного сообщения:
• Метод возвращает расшифрованное сообщение как строку.
▎Пример использования
~~~ python
# Создание экземпляра RSADecryptor
decryptor = RSADecryptor('path/to/private_key.pem')
# Расшифровка сообщения
decrypted_message = decryptor.decrypt_message(encrypted_message)
print(decrypted_message)
~~~
▎Замечания
• Для работы данного класса необходимо, чтобы файл с закрытым ключом был доступен и содержал корректный PEM-формат.
• При использовании закрытого ключа важно обеспечить его безопасность, чтобы предотвратить несанкционированный доступ к данным.
• RSA обычно используется для расшифровки небольших объемов данных, поэтому для больших сообщений может потребоваться использование симметричного шифрования (например, AES) в сочетании с RSA для безопасной передачи симметричного ключа.

86
RSA_Crypto/decrypt.py Normal file
View File

@ -0,0 +1,86 @@
"""
Decrypts messages encrypted with RSA.
"""
import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
class RSADecryptor:
"""
Module for decrypting messages encrypted with RSA.
Provides
--------
* :class:`RSADecryptor` - class for decrypting messages.
"""
def __init__(self, private_key_file):
"""
Initialize an RSADecryptor with a file containing a private RSA key.
Parameters
----------
private_key_file : str
The path to the private key file, which should be in PEM format.
Attributes
----------
private_key_file : str
The path to the private key file, which should be in PEM format.
private_key : cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey
The loaded private key.
"""
self.private_key_file = private_key_file
self.private_key = self.load_private_key()
def load_private_key(self):
"""
Load a private key from a file.
The file should be in PEM format and contain the private key.
Returns
-------
private_key : cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey
The loaded private key.
"""
with open(self.private_key_file, 'rb') as f:
private_key_data = f.read()
private_key = serialization.load_pem_private_key(
private_key_data,
password=None,
backend=default_backend()
)
return private_key
def decrypt_message(self, encrypted_message):
"""
Decrypt an encrypted message.
Parameters
----------
encrypted_message : str
The encrypted message as a base64 encoded string.
Returns
-------
decrypted_message : str
The decrypted message as a string.
"""
encrypted_bytes = base64.b64decode(encrypted_message)
try:
decrypted = self.private_key.decrypt(
encrypted_bytes,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return decrypted.decode()
except ValueError:
return None

69
RSA_Crypto/encrypt.py Normal file
View File

@ -0,0 +1,69 @@
"""
Encrypt messages encrypted with RSA.
"""
import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
class RSAEncryptor:
"""
Module for encrypting messages encrypted with RSA.
Provides
--------
* :class:`RSAEncryptor` - class for encrypting messages.
"""
def __init__(self, public_key_file):
self.public_key_file = public_key_file
self.public_key = self.load_public_key()
def load_public_key(self):
"""
Loads a public key from a file.
Parameters
----------
self : `RSAEncryptor`
The object itself.
Returns
-------
`cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`
The loaded key.
"""
with open(self.public_key_file, 'rb') as f:
public_key_data = f.read()
public_key = serialization.load_pem_public_key(
public_key_data,
backend=default_backend()
)
return public_key
def encrypt_message(self, message):
"""
Encrypts a message using RSA public key encryption.
Parameters
----------
message : str
The message to be encrypted.
Returns
-------
str
The encrypted message encoded in Base64.
"""
encrypted = self.public_key.encrypt(
message.encode(),
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return base64.b64encode(encrypted).decode('utf-8')

104
RSA_Crypto/generate_save.py Normal file
View File

@ -0,0 +1,104 @@
"""
Generate and save RSA key pair
"""
import os
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
class RSAKeyPair:
"""
Class for generating and saving RSA key pair
"""
def __init__(self, private_key_file, public_key_file):
self.private_key_file = private_key_file
self.public_key_file = public_key_file
self.private_key = None
self.public_key = None
def generate_private_key(self):
"""
Generate RSA private key.
The generated key has a 2048 bit length and a public exponent of 65537.
"""
self.private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
def generate_public_key(self):
"""
Generate the public key from the private key.
Raises:
ValueError: Private key must be generated first.
"""
if self.private_key is None:
raise ValueError("Private key must be generated first.")
self.public_key = self.private_key.public_key()
def save_private_key(self):
"""
Save the generated private key to a file.
The private key is saved in PEM format with the Traditional OpenSSL
format and no encryption. If the private key has not been generated yet,
a ValueError is raised.
Raises:
ValueError: Private key must be generated before saving.
"""
if self.private_key is None:
raise ValueError("Private key must be generated before saving.")
with open(self.private_key_file, 'wb') as f:
f.write(self.private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
))
def save_public_key(self):
"""
Save the generated public key to a file.
The public key is saved in PEM format with the SubjectPublicKeyInfo
format. If the public key has not been generated yet, a ValueError is
raised.
Raises:
ValueError: Public key must be generated before saving.
"""
if self.public_key is None:
raise ValueError("Public key must be generated before saving.")
with open(self.public_key_file, 'wb') as f:
f.write(self.public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
))
def generate_and_save_keys(self):
"""
Generate and save the private and public keys to the specified files.
This method first checks if the key files already exist. If not, it
generates the private key and saves it to the private key file, and
generates the public key based on the private key and saves it to the
public key file. If the files already exist, it simply prints a message
to the console.
This method does not raise any exceptions if the files already exist.
"""
if not os.path.exists(self.private_key_file) and not os.path.exists(self.public_key_file):
try:
self.generate_private_key()
self.save_private_key()
self.generate_public_key()
self.save_public_key()
except ValueError as e:
print(e)

35
main.py Normal file
View File

@ -0,0 +1,35 @@
import os
import json
from RSA_Crypto.encrypt import RSAEncryptor
from RSA_Crypto.decrypt import RSADecryptor
from RSA_Crypto.generate_save import RSAKeyPair
KEYS_DIR = 'keys'
PRIVATE_KEY_FILE = f'{KEYS_DIR}/private-key.pem'
PUBLIC_KEY_FILE = f'{KEYS_DIR}/public-key.pem'
if not os.path.isdir(KEYS_DIR):
os.makedirs(KEYS_DIR, exist_ok=True)
key_pair = RSAKeyPair(PRIVATE_KEY_FILE, PUBLIC_KEY_FILE)
key_pair.generate_and_save_keys()
message = '{"organization": "ООО Рога, Копыта & Ко", "license_expiration_date": "2024-01-01", "license_number": "1234567890", "count_licenses": 100}'
rsa_encryptor = RSAEncryptor(PUBLIC_KEY_FILE)
encrypted_message = rsa_encryptor.encrypt_message(message)
with open('output.txt', 'w') as f:
f.write(encrypted_message)
rsa_decryptor = RSADecryptor(PRIVATE_KEY_FILE)
with open('output.txt', 'r') as f:
encrypted_message_from_file = f.read()
decrypted_message = rsa_decryptor.decrypt_message(encrypted_message_from_file)
try:
decrypted_message_dict = json.loads(decrypted_message)
print(decrypted_message_dict['organization'])
except json.JSONDecodeError:
print("Ошибка: Не удалось декодировать сообщение как JSON.")