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