← Назад к вопросам
Что такое асимметричная криптография?
2.0 Middle🔥 201 комментариев
#DevOps и инфраструктура#Django
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Асимметричная криптография (Public Key Cryptography)
Асимметричная криптография — это криптографический метод, использующий две разные ключа: открытый (public key) и закрытый (private key). Данные, зашифрованные одним ключом, можно расшифровать только другим. Это основа современной сетевой безопасности.
Основной принцип
Публичный ключ (Public Key):
- Можно делиться публично
- Используется для шифрования
- Используется для проверки подписей
Закрытый ключ (Private Key):
- Хранится в секрете
- Используется для расшифровки
- Используется для создания подписей
Как работает асимметричное шифрование?
1. Генерируем пару ключей (public, private)
2. Отправляем public ключ всем (или размещаем на сервере)
3. Другой человек шифрует сообщение public ключом
4. Отправляет зашифрованное сообщение
5. Мы расшифровываем private ключом (только у нас он есть)
┌─────────┐ ┌──────────┐
│ Отправитель │ │ Получатель │
└──────┬──────┘ └──────┬───────┘
│ │
│ Берёт public ключ получателя │
│ ─────────────────────────────→ │
│ │
│ Шифрует сообщение │
│ Сообщение public ключом │
│ ─────────────────────────────→ │
│ │
│ Расшифровывает
│ private ключом
│ (только у него)
Практический пример с RSA
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
# Шаг 1: Генерируем пару ключей
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048, # 2048 бит достаточно для большинства
backend=default_backend()
)
public_key = private_key.public_key()
# Шаг 2: Сохраняем ключи
pem_private = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
pem_public = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
with open('private_key.pem', 'wb') as f:
f.write(pem_private)
with open('public_key.pem', 'wb') as f:
f.write(pem_public)
# Шаг 3: Шифруем сообщение
message = b"Секретное сообщение"
encrypted = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(f"Зашифровано: {encrypted.hex()}")
# Шаг 4: Расшифровываем
decrypted = private_key.decrypt(
encrypted,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(f"Расшифровано: {decrypted.decode()}")
Цифровые подписи (Digital Signatures)
Обратный процесс: вместо шифрования сообщения используем для удостоверения подлинности.
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
# Создаём подпись (только с private ключом)
message = b"Я согласен с этим контрактом"
signature = private_key.sign(
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
print(f"Подпись: {signature.hex()}")
# Проверяем подпись (с public ключом)
try:
public_key.verify(
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
print("✓ Подпись действительна!")
except:
print("✗ Подпись поддельна!")
# Если изменить сообщение — проверка упадёт
message_tampered = b"Я не согласен с этим контрактом"
try:
public_key.verify(signature, message_tampered, ...)
except:
print("✗ Сообщение было изменено!")
SSL/TLS в браузере (реальный пример)
Когда ты переходишь на https://google.com:
1. Сервер отправляет свой сертификат
Сертификат содержит:
- Доменное имя (google.com)
- Public ключ Google
- Подпись Certificate Authority (CA)
2. Браузер проверяет подпись
- Использует public ключ известного CA
- Если подпись верна → Google это действительно Google
3. Браузер генерирует сессионный ключ (симметричный)
- Шифрует его public ключом Google
- Отправляет серверу
4. Сервер расшифровывает private ключом
- Теперь оба знают симметричный ключ
- Весь трафик шифруется этим ключом
Почему нужны оба?
- Асимметричное шифрование медленное
- Используем его только для обмена ключами
- Потом используем быстрое симметричное шифрование
Алгоритмы асимметричной криптографии
| Алгоритм | Размер ключа | Скорость | Использование |
|---|---|---|---|
| RSA | 2048-4096 бит | Медленный | SSL/TLS, подписи, шифрование |
| ECDSA | 256-521 бит | Быстрый | Крипто (Bitcoin), подписи |
| EdDSA | 256 бит | Очень быстрый | SSH ключи, подписи |
| Diffie-Hellman | 2048+ бит | Медленный | Согласование ключей |
Сравнение с симметричной криптографией
# СИММЕТРИЧНАЯ (AES, ChaCha20)
# Один ключ для шифрования и расшифровки
key = "secret_key_123" # Один ключ
encrypted = encrypt(message, key) # Шифруем
decrypted = decrypt(encrypted, key) # Расшифровываем
# АСИММЕТРИЧНАЯ (RSA, ECC)
# Два разных ключа
public_key, private_key = generate_keypair()
encrypted = encrypt(message, public_key) # Ключ для шифрования
decrypted = decrypt(encrypted, private_key) # Другой ключ для расшифровки
Асимметричное шифрование в веб-приложениях
from fastapi import FastAPI
from pydantic import BaseModel
import json
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
app = FastAPI()
# Загружаем ключи
with open('public_key.pem', 'rb') as f:
public_key = serialization.load_pem_public_key(f.read())
with open('private_key.pem', 'rb') as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
class EncryptedMessage(BaseModel):
encrypted_data: str # hex-строка
@app.post("/api/decrypt")
async def decrypt_message(data: EncryptedMessage):
"""Расшифровываем сообщение только на сервере."""
encrypted = bytes.fromhex(data.encrypted_data)
decrypted = private_key.decrypt(
encrypted,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return {"message": decrypted.decode()}
@app.get("/api/public-key")
async def get_public_key():
"""Клиент получает публичный ключ для шифрования."""
pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
).decode()
return {"public_key": pem}
SSH ключи (практический пример)
# Генерируем пару ключей
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa
# id_rsa — приватный ключ (держим в секрете)
# id_rsa.pub — публичный ключ (кладём на сервер)
# На сервере в ~/.ssh/authorized_keys:
cat id_rsa.pub >> ~/.ssh/authorized_keys
# Теперь при подключении:
# ssh user@host
# Сервер шифрует challenge приватным ключом
# Клиент проверяет с публичным ключом
# Если верно → вход разрешен
Уязвимости асимметричной криптографии
# ❌ Слабые параметры
weak_key = rsa.generate_private_key(
public_exponent=65537,
key_size=512, # ОПАСНО! Легко взламывается
backend=default_backend()
)
# ✓ Надёжные параметры
strong_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096, # Хорошо для критичных приложений
backend=default_backend()
)
# ❌ Утечка приватного ключа
# Если кто-то скопирует private_key.pem → вся безопасность скомпрометирована
# ✓ Защита ключа
# - Хранить с правильными permissions (chmod 600)
# - Хранить в защищённом хранилище (KeyVault, HSM)
# - Шифровать сам ключ при сохранении
pem_protected = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(b"password")
)
Ключевые моменты
- Асимметричное шифрование использует два разных ключа
- Public ключ для шифрования, private ключ для расшифровки
- Медленнее симметричного шифрования (AES)
- Основа SSL/TLS и безопасности в интернете
- RSA наиболее распространена, ECDSA быстрее
- Цифровые подписи доказывают подлинность и целостность
- Никогда не делись приватным ключом и храни его защищённо