docs [AI]

This commit is contained in:
2026-06-30 18:51:09 +07:00
parent 18cad76e38
commit f7a76353ea
67 changed files with 2104 additions and 1417 deletions
+41
View File
@@ -1,11 +1,31 @@
//! Потоковое AEAD-шифрование ChaCha20-Poly1305.
//!
//! Это «горячий путь» крипто-блока: через него проходит каждый кадр данных.
//! Ключевые свойства:
//!
//! - **Раздельные направления.** [`ChaChaCipher`] держит два независимых потока —
//! `tx` (исходящий) и `rx` (входящий), у каждого свой ключ, IV и счётчик nonce.
//! - **Детерминированный nonce.** Nonce не передаётся по сети: обе стороны
//! синхронно считают `nonce = base_iv XOR counter` (см. [`NonceState`]).
//! Счётчики растут строго в ногу, поэтому любой пропуск/повтор кадра ломает
//! расшифровку — это и есть встроенная защита целостности потока.
//! - **In-place.** Шифр работает прямо в [`BytesMut`] без копий и аллокаций.
use bytes::BytesMut;
use chacha20poly1305::aead::generic_array::GenericArray;
use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, Key, KeyInit, Nonce};
use crate::crypto::aead::AeadPacker;
/// Генератор nonce для одного направления.
///
/// Nonce строится как `base_iv XOR big_endian(counter)` по младшим 8 байтам IV.
/// `counter` монотонно растёт на каждый кадр, гарантируя уникальность nonce в
/// пределах ключа (повтор nonce при одном ключе фатален для ChaCha20-Poly1305).
struct NonceState {
/// Счётчик кадров. Должен совпадать у отправителя и получателя по направлению.
counter: u64,
/// Базовый IV (12 байт), полученный из HKDF; неизменен на всю сессию.
base_iv: [u8; 12],
}
@@ -17,6 +37,11 @@ impl NonceState {
}
}
/// Возвращает nonce для текущего кадра и инкрементирует счётчик.
///
/// XOR накладывается на байты `iv[4..12]` (младшие 8 байт 12-байтового IV),
/// старшие 4 байта остаются «солью» из IV. После вызова `counter`
/// увеличивается, поэтому следующий кадр получит другой nonce.
pub fn next_nonce(&mut self) -> Nonce {
let mut iv = self.base_iv;
let counter_bytes = self.counter.to_be_bytes();
@@ -30,6 +55,9 @@ impl NonceState {
}
}
/// Однонаправленный шифр: одна пара (ключ, IV) + её счётчик nonce.
///
/// Реализует [`AeadPacker`]. Используется парами внутри [`ChaChaCipher`].
pub struct ChaChaStream {
cipher: ChaCha20Poly1305,
state: NonceState,
@@ -119,12 +147,19 @@ impl AeadPacker for ChaChaStream {
}
}
/// Двунаправленный шифр сессии: исходящий (`tx`) и входящий (`rx`) потоки.
///
/// Создаётся «пустым» (нулевые ключи) до завершения хендшейка, затем
/// [`set_keys`](ChaChaCipher::set_keys) заряжает реальные ключи из HKDF.
pub struct ChaChaCipher {
/// Исходящее направление (шифрование того, что отправляем).
pub tx: ChaChaStream,
/// Входящее направление (расшифровка того, что приняли).
pub rx: ChaChaStream,
}
impl ChaChaCipher {
/// Создаёт шифр с нулевыми ключами-заглушками (до хендшейка).
pub fn new() -> Self {
Self {
tx: ChaChaStream::new(&[0u8; 32], [0u8; 12]),
@@ -132,12 +167,18 @@ impl ChaChaCipher {
}
}
/// Заряжает реальные ключи/IV после хендшейка: `w_*` — на запись (tx),
/// `r_*` — на чтение (rx). Сбрасывает счётчики nonce в 0 для обоих направлений.
pub fn set_keys(&mut self, w_key: [u8; 32], w_iv: [u8; 12], r_key: [u8; 32], r_iv: [u8; 12]) {
self.tx = ChaChaStream::new(&w_key, w_iv);
self.rx = ChaChaStream::new(&r_key, r_iv);
netrunner_logger::debug!("Cipher keys and IVs updated for both directions");
}
/// Разбирает шифр на два независимых потока `(rx, tx)`.
///
/// Нужно, чтобы отдать чтение и запись в разные задачи tokio (reader/writer),
/// не деля шифр под мьютексом — каждое направление владеет своим потоком.
pub fn split(self) -> (ChaChaStream, ChaChaStream) {
(self.rx, self.tx)
}