Алгоритм XSalsa20-Poly1305: принцип работы

XSalsa20-Poly1305 относится к классу схем Authenticated Encryption with Associated Data (AEAD), где одна конструкция одновременно обеспечивает:

  • конфиденциальность данных (шифрование)
  • целостность и подлинность (аутентификация)

В библиотеке NaCl и её JavaScript-реализациях (TweetNaCl.js, nacl.js) эта связка является базовым примитивом для симметричного шифрования сообщений.

Ключевая идея: XSalsa20 используется для шифрования поточным способом, Poly1305 — для вычисления кода аутентификации (MAC).


XSalsa20: расширение Salsa20 под длинные nonce

Базовая Salsa20

Salsa20 — это поточный шифр, который генерирует псевдослучайный поток байтов (keystream), зависящий от:

  • 256-битного секретного ключа
  • 64-битного nonce (в классической версии)
  • счётчика блоков

Шифрование выполняется операцией XOR:

ciphertext = plaintext ⊕ keystream

Проблема классического Salsa20 — ограниченный размер nonce (64 бита), что повышает риск повторов при больших объёмах данных.


XSalsa20 и расширенный nonce

XSalsa20 решает эту проблему, увеличивая nonce до 192 бит.

Это достигается через промежуточную функцию:

HSalsa20 (ключевое преобразование)

HSalsa20 не генерирует поток шифрования напрямую. Вместо этого она:

  • принимает 256-битный ключ
  • принимает 128 бит nonce (часть расширенного nonce)
  • вычисляет новый 256-битный subkey

Формально:

subkey = HSalsa20(key, nonce_part)

Далее:

  • XSalsa20 использует этот subkey
  • оставшиеся 64 бита nonce используются как обычный nonce Salsa20

Таким образом структура становится:

XSalsa20(key, nonce_192):
    subkey = HSalsa20(key, nonce[0..127])
    return Salsa20(subkey, nonce[128..191])

Итог архитектуры

  • расширенный nonce предотвращает повторное использование ключевого потока
  • сохраняется высокая скорость Salsa20
  • добавляется устойчивость к ошибкам управления nonce

Поточный режим шифрования

После генерации keystream алгоритм работает так:

Генерация блоков

Keystream формируется блоками по 64 байта. Каждый блок зависит от:

  • subkey
  • nonce
  • счётчика блока
keystream_block[i] = Salsa20_block(subkey, nonce, i)

XOR-операция

Шифрование:

C[i] = P[i] ⊕ KS[i]

Дешифрование идентично:

P[i] = C[i] ⊕ KS[i]

Ключевой момент: поточный шифр не модифицирует данные, он только накладывает поток.


Poly1305: аутентификация сообщений

Poly1305 — это высокоскоростной MAC-алгоритм, основанный на арифметике полиномов по модулю (2¹³⁰ − 5).

Основная идея

Сообщение интерпретируется как последовательность чисел и подставляется в полином:

P = m₁·rⁿ + m₂·rⁿ⁻¹ + ... + mₙ

Где:

  • r — часть одноразового ключа
  • вычисления происходят по модулю 2¹³⁰ − 5

Требование одноразовости ключа

Poly1305 критически зависит от:

один ключ = одно сообщение

Если использовать ключ повторно, безопасность полностью ломается.


Связка XSalsa20 + Poly1305

В XSalsa20-Poly1305 используется конструкция Encrypt-then-MAC, но с важной оптимизацией: ключ для Poly1305 не задаётся вручную.

Производный one-time key

Ключ для Poly1305 генерируется из XSalsa20:

otk = XSalsa20(key, nonce).first_32_bytes

Далее:

  • первые 32 байта keystream → ключ Poly1305
  • оставшийся keystream → шифрование сообщения

Полная схема работы

Шаг 1. Разделение nonce

Вход:

  • 256-битный ключ
  • 192-битный nonce
  • сообщение

Nonce делится:

  • nonce1 (16 байт) → HSalsa20
  • nonce2 (8 байт) → Salsa20

Шаг 2. Получение subkey

subkey = HSalsa20(key, nonce1)

Шаг 3. Генерация keystream

keystream = XSalsa20(subkey, nonce2)

Шаг 4. Извлечение Poly1305 ключа

otk = keystream[0..31]

Шаг 5. Шифрование сообщения

ciphertext = plaintext ⊕ keystream[32..]

Шаг 6. Вычисление MAC

tag = Poly1305(otk, ciphertext)

Итоговый пакет

output = nonce || ciphertext || tag

Почему конструкция безопасна

1. Разделение обязанностей

  • XSalsa20 отвечает за конфиденциальность
  • Poly1305 — за целостность

2. Защита от подмены

Любое изменение ciphertext приводит к:

  • неверному MAC
  • отказу в дешифрации

3. Защита от повторного nonce

XSalsa20 с 192-битным nonce практически исключает коллизии.


4. Связка через keystream

Ключ MAC не передаётся напрямую, он:

  • скрыт внутри шифрования
  • зависит от nonce и ключа

Особенности реализации в TweetNaCl.js

В JavaScript-реализации (TweetNaCl.js / nacl.js):

  • алгоритм реализован без зависимостей
  • используется только Uint8Array
  • отсутствуют динамические аллокации в критических местах

Типичный интерфейс:

nacl.secretbox(message, nonce, key)

Где:

  • key — 32 байта
  • nonce — 24 байта (XSalsa20)
  • message — произвольные данные

Результат включает:

  • ciphertext
  • Poly1305 tag

Устойчивость к атакам

Replay-атаки

Nonce должен быть уникальным. Повтор nonce = повтор keystream = компрометация.


Padding oracle

MAC проверяется до расшифровки, что исключает утечки через ошибки формата.


Bit-flipping атаки

Любое изменение ciphertext ломает MAC, поэтому модификация невозможна без ключа.


Криптографическая композиция

XSalsa20-Poly1305 можно рассматривать как:

AEAD(K, N, M) = (C, T)

Где:

  • K — ключ
  • N — nonce
  • M — сообщение
  • C — ciphertext
  • T — authentication tag

Свойства конструкции

  • линейная скорость шифрования (поточный режим)
  • отсутствие необходимости в padding
  • фиксированная стоимость MAC
  • минимальная поверхность атаки
  • высокая производительность в JavaScript

Роль в NaCl-экосистеме

В NaCl-подобных библиотеках эта схема используется как основной примитив:

  • secure messaging
  • session encryption
  • client-server протоколы
  • обмен ключами после Diffie-Hellman (box + secretbox)

Она считается одной из наиболее простых и при этом надёжных AEAD-конструкций, доступных для прикладной криптографии.