CRYPTO Криптография и анатомия туннеля

Все VPN, от 1996 до 2026, построены на одной и той же триаде: обмен ключами → симметричное AEAD-шифрование → аутентификация. Понял триаду — все протоколы дальше укладываются за полчаса.

Что узнаешь
Вспомни из прошлого урока

В уроке 1 мы построили каркас: VPN = инкапсуляция (пакет в пакете) + шифрование внешнего канала + маскировка. В мини-лабе ты своими глазами видел открытый SNI в ClientHello — сегодня разберём этот handshake побайтово и поймём, ЧЕМ шифруется всё остальное. Если TLS для тебя пока туман — освежи «Сети с нуля», урок 7.

1. Симметрика vs асимметрика — самая базовая дихотомия

В криптографии есть ровно два типа шифров. Все системы — комбинация.

Симметричное vs асимметричное шифрование
① Симметричное (shared secret) Один и тот же ключ шифрует и расшифровывает. Быстро, ОЧЕНЬ быстро. Alice 🔑 = K шифрует ключом K «kHd9!@xQ» Bob 🔑 = K ⚠ Как Боб получил ключ K? Если по тому же каналу — взломают ② Асимметричное (public/private key) Два разных ключа: публичный шифрует, приватный расшифровывает. Медленнее в 100×. Alice 🔓 pub_Alice 🔐 priv_Alice шифрует pub_Bob «kHd9!@xQ» Bob 🔓 pub_Bob 🔐 priv_Bob ✓ Боб расшифровывает priv_Bob pub_Bob свободно раздаётся Решение: используем асимметрику ОДИН раз для обмена симметричным ключом, дальше шифруем симметрикой. Это и есть «гибридная» криптосистема. Так делают ВСЕ VPN.
Современные VPN — гибридные: асимметрика для key exchange, симметрика для трафика

Почему симметрика — быстро, асимметрика — медленно

AES-GCM на современном CPU с AES-NI шифрует 4-10 ГБ/с на одно ядро. ChaCha20-Poly1305 (ARM, мобильники) — 1-2 ГБ/с. RSA-2048 — ~1 МБ/с. X25519 (эллиптика) — единичные миллисекунды на handshake.

Поэтому ни один VPN не шифрует пакеты «асимметрикой» — это убило бы скорость. Асимметрика используется только в handshake (раз в час) — там нужно безопасно договориться.

2. AEAD — единственный правильный режим в 2026

Голое симметричное шифрование (AES в режиме CBC, ChaCha20 как stream-cipher) — недостаточно. Шифр только скрывает данные, но не защищает от подмены: атакующий может «перевернуть» бит, и расшифрованный текст изменится без обнаружения.

AEAD = Authenticated Encryption with Associated Data. Это режим, который к шифру добавляет MAC-тег (Message Authentication Code). При расшифровке проверяется тег — если данные подменили, тег не сойдётся и пакет отбрасывается.

AEAD: шифрование + аутентификация в одном
Plaintext «GET / HTTP/2» Ключ K 256 бит Nonce 96 бит, ↑ счётчик AEAD ChaCha20-Poly1305 или AES-GCM шифрование + MAC Ciphertext A3:4F:91:...:E2 Auth Tag (16 байт) «отпечаток» — проверка целостности Получатель: расшифровал → пересчитал tag → совпадает? Если нет — пакет ВЫБРАСЫВАЕТСЯ.
AEAD склеивает шифр и MAC в одну операцию — атомарно
Под капотом

Почему два AEAD-стандарта: AES-GCM и ChaCha20-Poly1305

AES-GCM — золотой стандарт. На современных x86 CPU есть аппаратная инструкция AES-NI (с 2010 года), которая делает AES в 5-10 раз быстрее обычного кода. На сервере AES-GCM выгоднее.

ChaCha20-Poly1305 — изобретён Daniel J. Bernstein. Не использует таблицы (атаки по таймингу невозможны), работает на чистых сложениях/XOR. На ARM-мобильниках без AES-NI в 3 раза быстрее AES. Поэтому Google пушит ChaCha для мобильного TLS.

WireGuard, Signal, modern OpenSSH — только ChaCha20-Poly1305. TLS 1.3 поддерживает оба, выбор по согласованию.

3. Diffie-Hellman: как договориться о ключе на виду у всех

Главная проблема: Алиса и Боб хотят общий симметричный ключ, но между ними враждебный канал (провайдер всё слышит). Как? Diffie-Hellman (1976) — алгоритм, который позволяет двоим договориться о секрете через открытый канал, и наблюдатель не сможет его вычислить.

Аналогия

Краски

Алиса и Боб публично договариваются о «жёлтой» базовой краске. Каждый дома берёт свою секретную краску (Алиса — синюю, Боб — красную) и смешивает с жёлтой. Алиса получает «зелёный» (жёлтый+синий), Боб — «оранжевый» (жёлтый+красный).

Они обмениваются полученным цветом по открытому каналу. Алиса добавляет свою синюю краску к «оранжевому» Боба — получает «коричневый» (жёлтый+красный+синий). Боб добавляет свою красную к «зелёному» Алисы — получает тот же коричневый.

Подслушивающий видит «жёлтый», «зелёный», «оранжевый». Чтобы получить коричневый — нужно знать «синий» или «красный» отдельно. Но разделить смешанную краску обратно — практически невозможно. Это и есть «one-way function» — основа DH.

В реальной криптографии «краска» — это операция возведения в степень в конечном поле или точка на эллиптической кривой. Восстановить «секретную краску» (дискретный логарифм) — задача, которая на классическом компьютере требует миллиардов лет. На квантовом — час. Поэтому ECDH скоро заменят на ML-KEM (см. урок 14).

X25519 Diffie-Hellman — handshake побайтово
Alice 1. Генерирует: priv_A = random(32B) pub_A = X25519(priv_A, G) 2. Получает pub_B 3. Вычисляет общий: shared = X25519(priv_A, pub_B) 4. shared → HKDF → ключ для ChaCha20-Poly1305 Bob 1. Генерирует: priv_B = random(32B) pub_B = X25519(priv_B, G) 2. Получает pub_A 3. Вычисляет общий: shared = X25519(priv_B, pub_A) 4. То же shared! математика гарантирует Открытый канал (провайдер слышит всё) pub_A: 32 байта pub_B: 32 байта подслушивающий видит pub_A и pub_B но не может вычислить shared
X25519 — ECDH на кривой Curve25519. Используется в WireGuard, TLS 1.3, Signal, SSH

PFS — Perfect Forward Secrecy

Защита

Что такое PFS и почему без неё нельзя

Если Алиса использует один и тот же priv_A годами — у атакующего есть шанс. Он может годами записывать твой трафик, а потом украсть приватный ключ (взлом, повестка, продажа провайдера) — и расшифровать ВСЁ накопленное.

PFS = на каждое соединение (или каждый час) генерируется НОВАЯ пара (priv_A, pub_A) — «ephemeral keys». После handshake ephemeral ключи уничтожаются. Даже если потом украдут постоянный ключ — старый трафик уже не расшифровать, его ключ удалён.

Без PFS: RSA-key-exchange в старом TLS, PPTP, IPsec без DH-PFS-режима. С PFS: TLS 1.3 (всегда), WireGuard, Signal, modern OpenVPN.

4. Noise Framework — как WireGuard и Reality строят handshake

Дизайнерам протоколов надоело каждый раз заново изобретать «как обменяться ключами безопасно». Trevor Perrin (соавтор Signal) формализовал процесс — Noise Protocol Framework (noiseprotocol.org). Это «конструктор» handshake'ов из стандартных блоков.

В Noise описывают последовательность операций сторон в виде паттерна. Самые популярные:

Буквы означают:

Например, Noise_IK — клиент анонимен (отсутствие первой буквы статика для I), но знает сервер заранее (K). Это и есть WireGuard: ты знаешь публичный ключ сервера, сервер не знает твой статический заранее.

Под капотом

Шаги Noise_IK (упрощённо)

  1. Клиент генерирует ephemeral e_i, вычисляет DH(e_i, S_r) — общий промежуточный ключ
  2. Шифрует этим ключом свой статический публичный ключ S_i и шлёт серверу
  3. Сервер расшифровывает S_i, вычисляет DH(S_r_priv, S_i) — второй ключ → миксует
  4. Сервер шлёт свой эфемер e_r, вычисляет DH(e_r, e_i) — третий ключ → миксует
  5. Итоговый chaining key от смешивания 3-4 DH → HKDF → симметричные ключи для ChaCha20

Главное — даже зная статические ключи обеих сторон, нельзя расшифровать прошлый handshake без эфемеров, которые уже стёрты. Это и есть PFS на уровне дизайна.

5. TLS 1.3 handshake — побайтово

Reality, Trojan, Hysteria, MASQUE — все маскируются под TLS 1.3. Без понимания, что внутри ClientHello — не понять, как Reality умудряется не иметь сертификата. Разберём.

TLS 1.3 — 1-RTT handshake
Client Server ① ClientHello внутри: • version: TLS 1.2 (legacy!) • random: 32 байта • cipher_suites: [AES-GCM, ChaCha20-Poly1305] • extensions: - SNI = "example.com" ← DPI ВИДИТ - supported_versions = [TLS 1.3] ② ServerHello + EncryptedExtensions + Certificate + Finished • version: TLS 1.2 (legacy) • random: 32 байта • cipher_suite: AES-GCM • key_share: pub_S (X25519) → дальше уже ЗАШИФРОВАНО ③ [Encrypted] Finished + Application Data
TLS 1.3: один round-trip и канал готов. SNI пока виден всем — это и блокирует ТСПУ
0000 16 03 01 02 00 TLS record: type=Handshake(22), legacy ver 0x0301 0005 01 00 01 fc Handshake: type=ClientHello(1), len=508 0009 03 03 legacy_version = TLS 1.2 (для обратной совместимости) 000B b3 9e 42 c1 ... [32 bytes] client_random (32 байта) 002B 20 [32 bytes] legacy_session_id (тоже 32 байта) 004C 00 08 13 02 13 03 13 01 00 ff cipher_suites: TLS_AES_256_GCM, ChaCha20-Poly1305... 0056 01 00 compression: null 0058 01 8b extensions_length = 395 005A 00 00 00 12 00 10 00 00 0d SNI extension (type 0) 0063 65 78 61 6d 70 6c 65 2e 63 6f 6d "example.com" ← ДПИ читает это в plaintext! 006E 00 0a 00 0e 00 0c ... supported_groups 00C5 00 33 00 24 00 1d 00 20 key_share extension, X25519, 32 байт pub_C
Атака

SNI в ClientHello — главная дыра TLS 1.3

В строке 0x005A-0x006D видно поле SNI = «example.com» в чистом виде. Это и есть то, что читает ТСПУ за наносекунды: «о, человек идёт на example.com — режем».

Это фундаментальная проблема TLS 1.3: чтобы сервер на shared IP отдал нужный сертификат, клиент должен сказать имя до handshake. Решение придумали — ECH (Encrypted Client Hello) — шифрование SNI публичным ключом провайдера хостинга. В 2025-2026 ECH медленно раскатывается. Подробно — в уроке 14.

Reality решает это иначе: подставляет SNI настоящего популярного сайта (apple.com) и реально проводит handshake с этим сайтом, а уже потом «угоняет» канал. ДПИ видит handshake с apple.com — пропускает. Подробно — в уроке 7.

6. MTU/MSS в туннеле — почему важно

Когда твой пакет заворачивается в внешний — оба занимают место в одном Ethernet-кадре. Если MTU кадра 1500 байт, а внешний header VPN съел 60 байт — внутреннему остаётся 1440. Если приложение это не знает и шлёт 1500-байтовые пакеты — будет фрагментация или drop.

ПротоколOverhead (примерно)Рекомендуемый inner MTU
WireGuard (UDP)32 (header) + 16 (auth tag) + 20 (IP) + 8 (UDP) = ~801420
OpenVPN (UDP)~50-701430-1450
OpenVPN (TCP)~70-901410
IPsec ESP (tunnel mode)~60-80 (зависит от шифра)1420
WireGuard через TCP-обёртку~1001400
Shadowsocks-AEAD-2022~30-501450
Под капотом

Path MTU Discovery и почему это ломается

Идеально — клиент послал бы 1500-байтовый пакет, и где-то посредине маршрутизатор сказал бы ICMP «Fragmentation Needed»: «уменьши до 1380». Это PMTUD. Проблема: половина роутеров режет ICMP — пакет молча теряется. Это и есть «чёрная дыра MTU».

Решение: MSS clamping. Маршрутизатор VPN-туннеля переписывает поле MSS в TCP-SYN на безопасное значение (обычно MTU − 40). Тогда TCP сам не отправит больше. В Linux: iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu.

7. Мини-лаба: попробуй прямо сейчас

Пощупай триаду руками — нужен только openssl (есть в Linux/macOS/Git Bash):

# 1. Симметрика: зашифруй и расшифруй файл AES-256-GCM... нет, GCM в CLI капризен —
#    возьмём проверенный AEAD-путь через ChaCha20 в составе TLS ниже, а тут — классика:
echo "секретный текст" > secret.txt
openssl enc -aes-256-cbc -pbkdf2 -in secret.txt -out secret.enc -k "пароль123"
openssl enc -d -aes-256-cbc -pbkdf2 -in secret.enc -k "пароль123"
# Один и тот же пароль шифрует и расшифровывает — это и есть «симметрично»

# 2. Асимметрика: сгенерируй пару X25519 — как делает WireGuard
openssl genpkey -algorithm X25519 -out priv.pem
openssl pkey -in priv.pem -pubout -out pub.pem
cat pub.pem   # публичный можно показывать кому угодно

# 3. Живой TLS 1.3: какой AEAD-шифр согласовался с реальным сервером
openssl s_client -connect example.com:443 -tls1_3 2>/dev/null | grep -E "Cipher|Protocol"

# 4. Тот самый MTU: пропингуй с запретом фрагментации и найди потолок
ping -M do -s 1472 example.com -c 2   # Linux: 1472+28 = ровно 1500
ping -M do -s 1473 example.com -c 2   # а это уже не влезет
Ожидаемый результат

В пункте 3 увидишь Protocol: TLSv1.3 и Cipher из «большой пятёрки» AEAD — обычно TLS_AES_256_GCM_SHA384: тот самый симметричный шифр, о котором был раздел 2, согласованный тем самым handshake из раздела 5. В пункте 4 первый ping пройдёт, второй скажет «Message too long / Frag needed» — ты нашёл MTU 1500 своего канала. Теперь представь, что туннель съел ещё 60 байт, и никто не сообщил об этом отправителю — вот источник «работает 80% сайтов» из раздела 6.

8. Задачи самопроверки — реши, потом раскрой ответ

Задача 1. Почему нельзя шифровать весь VPN-трафик асимметрично (RSA/X25519) — раз уж это «более безопасно», зачем вообще симметрика?

Асимметрика на порядки медленнее и дороже по CPU, а «безопаснее» она не в смысле стойкости трафика, а в смысле распределения ключей. Поэтому все системы гибридные: асимметрика решает единственную задачу — согласовать общий секрет через открытый канал (один раз, в handshake), а дальше гоняет данные быстрый симметричный AEAD (ChaCha20-Poly1305/AES-GCM), меняющий ключи по расписанию.

Задача 2. VPN-протокол шифрует данные, но не аутентифицирует их (шифрование без MAC/AEAD). Атакующий не может прочитать трафик. Что он всё-таки может и почему это фатально?

Он может ПОДМЕНЯТЬ шифротекст: переворачивать биты, переставлять и повторять блоки — не зная содержимого, но предсказуемо меняя расшифрованный результат (классические атаки на CBC без MAC, bit-flipping). Приёмник не заметит подделку. AEAD решает это тегом аутентичности: любое изменение шифротекста делает тег невалидным, пакет отбрасывается. Поэтому «шифрование без аутентификации» в 2026 — автоматический дисквал протокола.

Задача 3. Сервер годами использует один статический ключ для шифрования сессий. Спецслужба записывала весь трафик, а потом изъяла сервер с ключом. Что она расшифрует — и как PFS меняет ответ?

Без PFS — всё: архив трафика расшифровывается задним числом изъятым ключом. С PFS сессионные ключи выводятся из ЭФЕМЕРНОГО Диффи-Хеллмана: приватные половинки живут одно соединение и стираются. Статический ключ сервера подтверждает личность, но не участвует в выводе ключей трафика — записанный архив остаётся мусором. Поэтому WireGuard, TLS 1.3 и весь современный стек делают ephemeral обмен обязательным.

Задача 4. Через WireGuard-туннель (endpoint MTU 1500) «открывается 80% сайтов»: лёгкие страницы работают, тяжёлые висят. Посчитай правильный MTU туннеля и назови два способа лечения.

WireGuard добавляет ~60 байт оверхеда (внешний IP 20 + UDP 8 + заголовок и AEAD-тег WG ~32): внутренний MTU = 1500 − 60 = 1420 — именно его WireGuard ставит по умолчанию. Если оставить 1500, большие пакеты внутри туннеля не влезают во внешний канал и молча теряются (PMTUD часто сломан — ICMP порезан). Лечение: выставить MTU интерфейса туннеля 1420 (или ниже при двойной инкапсуляции) и/или MSS clamping на форвардящем узле, чтобы TCP сам не разгонялся выше проходимого.

Задача 5. В TLS 1.3 почти весь handshake зашифрован. Почему же DPI до сих пор видит, на какой сайт ты идёшь, и какие два механизма закрывают эту щель?

Шифрование handshake начинается ПОСЛЕ обмена ключами, а имя сервера нужно раньше — SNI едет в самом первом сообщении (ClientHello) открытым текстом, иначе сервер с сотней сайтов не знает, какой сертификат доставать. Закрывают щель: ECH (Encrypted Client Hello — настоящий SNI шифруется ключом из DNS-записи HTTPS) и подход Reality — показать DPI ЧУЖОЙ легитимный SNI, оставаясь неотличимым от реального сайта. Обоим посвящены следующие уроки.

9. Словарик урока

симметричное шифрование · symmetricодин ключ шифрует и расшифровывает; быстро — им гоняют весь трафик
асимметричное · asymmetric / public-keyпара ключей: публичный + приватный; решает задачу обмена ключами
AEADшифрование + тег аутентичности в одном примитиве (ChaCha20-Poly1305, AES-GCM)
nonceодноразовое число для AEAD; повтор nonce с тем же ключом — катастрофа
обмен Диффи-Хеллмана · DH / ECDH / X25519общий секрет через открытый канал; X25519 — современная кривая
эфемерный ключ · ephemeral keyживёт одно соединение; основа PFS
прямая секретность · PFSкража долгосрочного ключа не раскрывает прошлый трафик
Noise Frameworkконструктор handshake-паттернов (Noise_IK у WireGuard)
ClientHello / ServerHelloпервые сообщения TLS: версии, шифры, key_share, SNI
MTU / MSSмаксимальный пакет канала / полезные данные TCP; туннель съедает 30–90 байт
MSS clampingподрезка MSS в проходящих SYN — страховка от молчаливых потерь в туннеле

10. Резюме — что унести в следующие уроки

  1. Гибридная схема: асимметрика (Curve25519) для key exchange — раз в handshake; симметрика (ChaCha20-Poly1305 или AES-GCM) для трафика — постоянно.
  2. AEAD обязателен. Любой VPN в 2026 без AEAD — устаревший (PPTP, OpenVPN с BF-CBC). Без аутентификации шифр уязвим к подмене.
  3. PFS обязателен. Ephemeral keys на каждое соединение. Кража долгосрочного ключа не должна расшифровать прошлый трафик.
  4. Noise Framework — фундамент современных VPN (WireGuard). Понимаешь Noise_IK — понимаешь WireGuard.
  5. SNI в TLS 1.3 — главная щель. На этом построены все блокировки и большинство современных контрмер (Reality, ECH).
  6. MTU теряет 30-90 байт на туннеле. Всегда настраивай MSS clamping или явный inner MTU — иначе будут «работает 80% сайтов».

В следующем уроке — конкретные протоколы: OpenVPN, IPsec, L2TP, PPTP, SSTP. Каждый с побайтовой разборкой формата пакета, состояниями и анализом «как DPI его видит». После этого WireGuard (урок 04) ляжет за полчаса.