| |
|
|
| from cryptography.hazmat.primitives.asymmetric import rsa, ed25519 |
| from cryptography.hazmat.primitives import serialization, hashes |
| from cryptography.hazmat.primitives.kdf.scrypt import Scrypt |
| from cryptography.hazmat.primitives.ciphers.aead import AESGCM |
| from cryptography.hazmat.backends import default_backend |
| import os |
| import base64 |
|
|
| backend = default_backend() |
|
|
| |
|
|
| def generate_rsa_key_pair(key_size=2048): |
| private_key = rsa.generate_private_key( |
| public_exponent=65537, |
| key_size=key_size, |
| backend=backend |
| ) |
| public_key = private_key.public_key() |
| return private_key, public_key |
|
|
| |
|
|
| def generate_ed25519_key_pair(): |
| private_key = ed25519.Ed25519PrivateKey.generate() |
| public_key = private_key.public_key() |
| return private_key, public_key |
|
|
| |
|
|
| def serialize_private_key(private_key, password: str = None): |
| if password: |
| encryption_algorithm = serialization.BestAvailableEncryption(password.encode()) |
| else: |
| encryption_algorithm = serialization.NoEncryption() |
| |
| return private_key.private_bytes( |
| encoding=serialization.Encoding.PEM, |
| format=serialization.PrivateFormat.PKCS8, |
| encryption_algorithm=encryption_algorithm |
| ) |
|
|
| def serialize_public_key(public_key): |
| return public_key.public_bytes( |
| encoding=serialization.Encoding.PEM, |
| format=serialization.PublicFormat.SubjectPublicKeyInfo |
| ) |
|
|
| def load_private_key(pem_data, password: str = None): |
| return serialization.load_pem_private_key( |
| pem_data, |
| password=password.encode() if password else None, |
| backend=backend |
| ) |
|
|
| def load_public_key(pem_data): |
| return serialization.load_pem_public_key( |
| pem_data, |
| backend=backend |
| ) |
|
|
| def generate_keypair(method="rsa", password: bytes = None): |
| """ |
| Создаёт пару ключей (приватный, публичный) с заданным методом. |
| method: "rsa" или "ed25519" |
| password: если указан, приватный ключ будет зашифрован |
| Возвращает (private_key_pem: bytes, public_key_pem: bytes) |
| """ |
| if method == "rsa": |
| private_key = rsa.generate_private_key( |
| public_exponent=65537, key_size=2048, backend=default_backend() |
| ) |
| elif method == "ed25519": |
| private_key = ed25519.Ed25519PrivateKey.generate() |
| else: |
| raise ValueError("Unsupported key generation method") |
|
|
| encryption_algorithm = ( |
| serialization.BestAvailableEncryption(password) |
| if password |
| else serialization.NoEncryption() |
| ) |
|
|
| private_pem = private_key.private_bytes( |
| encoding=serialization.Encoding.PEM, |
| format=serialization.PrivateFormat.PKCS8, |
| encryption_algorithm=encryption_algorithm, |
| ) |
|
|
| public_pem = private_key.public_key().public_bytes( |
| encoding=serialization.Encoding.PEM, |
| format=serialization.PublicFormat.SubjectPublicKeyInfo, |
| ) |
|
|
| return private_pem, public_pem |
|
|
| |
|
|
| def derive_key(password: str, salt: bytes = None): |
| if not salt: |
| salt = os.urandom(16) |
| kdf = Scrypt( |
| salt=salt, |
| length=32, |
| n=2**14, |
| r=8, |
| p=1, |
| backend=backend |
| ) |
| key = kdf.derive(password.encode()) |
| return key, salt |
|
|
| def encrypt_data(data: bytes, password: str): |
| key, salt = derive_key(password) |
| aesgcm = AESGCM(key) |
| nonce = os.urandom(12) |
| encrypted = aesgcm.encrypt(nonce, data, None) |
| return { |
| 'ciphertext': base64.b64encode(encrypted).decode(), |
| 'salt': base64.b64encode(salt).decode(), |
| 'nonce': base64.b64encode(nonce).decode() |
| } |
|
|
| def decrypt_data(encrypted_data: dict, password: str): |
| ciphertext = base64.b64decode(encrypted_data['ciphertext']) |
| salt = base64.b64decode(encrypted_data['salt']) |
| nonce = base64.b64decode(encrypted_data['nonce']) |
| key, _ = derive_key(password, salt=salt) |
| aesgcm = AESGCM(key) |
| return aesgcm.decrypt(nonce, ciphertext, None) |
|
|
| |
|
|
| if __name__ == "__main__": |
| priv, pub = generate_ed25519_key_pair() |
| priv_pem = serialize_private_key(priv) |
| pub_pem = serialize_public_key(pub) |
|
|
| print("PRIVATE PEM:") |
| print(priv_pem.decode()) |
| print("PUBLIC PEM:") |
| print(pub_pem.decode()) |
|
|
| encrypted = encrypt_data(priv_pem, "secret-password") |
| decrypted = decrypt_data(encrypted, "secret-password") |
| assert decrypted == priv_pem |
| print("✅ Encryption/decryption OK") |
|
|