split codec and dynamic tcp sockers

This commit is contained in:
Трапезников Кирилл Иванович
2026-04-10 11:27:38 +10:00
parent 67be2d3056
commit 11d2b4e1d9
14 changed files with 368 additions and 667 deletions
+44 -32
View File
@@ -3,6 +3,7 @@ use chacha20poly1305::aead::generic_array::GenericArray;
use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, Key, KeyInit, Nonce};
use crate::crypto::aead::AeadPacker;
struct NonceState {
counter: u64,
base_iv: [u8; 12],
@@ -18,7 +19,6 @@ impl NonceState {
pub fn next_nonce(&mut self) -> Nonce {
let mut iv = self.base_iv;
let counter_bytes = self.counter.to_be_bytes();
for i in 0..8 {
@@ -30,43 +30,29 @@ impl NonceState {
}
}
pub struct ChaChaCipher {
encrypt_cipher: ChaCha20Poly1305,
decrypt_cipher: ChaCha20Poly1305,
encrypt_state: NonceState,
decrypt_state: NonceState,
// Универсальная структура для одного направления трафика (Tx или Rx)
pub struct ChaChaStream {
cipher: ChaCha20Poly1305,
state: NonceState,
}
impl ChaChaCipher {
pub fn new() -> Self {
let start_key = Key::from([0u8; 32]);
let encrypt_cipher = ChaCha20Poly1305::new(&start_key);
let decrypt_cipher = ChaCha20Poly1305::new(&start_key);
impl ChaChaStream {
pub fn new(key: &[u8; 32], iv: [u8; 12]) -> Self {
Self {
encrypt_state: NonceState::new([0u8; 12]),
decrypt_state: NonceState::new([0u8; 12]),
encrypt_cipher,
decrypt_cipher,
cipher: ChaCha20Poly1305::new(Key::from_slice(key)),
state: NonceState::new(iv),
}
}
pub fn set_keys(&mut self, w_key: [u8; 32], w_iv: [u8; 12], r_key: [u8; 32], r_iv: [u8; 12]) {
self.encrypt_cipher = ChaCha20Poly1305::new(Key::from_slice(&w_key));
self.decrypt_cipher = ChaCha20Poly1305::new(Key::from_slice(&r_key));
self.encrypt_state = NonceState::new(w_iv);
self.decrypt_state = NonceState::new(r_iv);
netrunner_logger::debug!("Cipher keys and IVs updated for both directions");
}
}
impl AeadPacker for ChaChaCipher {
// Реализуем трейт AeadPacker для однонаправленного потока
impl AeadPacker for ChaChaStream {
fn encrypt(&mut self, data: &mut BytesMut) -> Result<Bytes, chacha20poly1305::aead::Error> {
let current_counter = self.encrypt_state.counter;
let nonce = self.encrypt_state.next_nonce();
let current_counter = self.state.counter;
let nonce = self.state.next_nonce();
let data_len = data.len();
match self.encrypt_cipher.encrypt_in_place(&nonce, &nonce, data) {
match self.cipher.encrypt_in_place(&nonce, &nonce, data) {
Ok(_) => {
netrunner_logger::trace!(
counter = current_counter,
@@ -90,11 +76,11 @@ impl AeadPacker for ChaChaCipher {
}
fn decrypt(&mut self, data: &mut BytesMut) -> Result<Bytes, chacha20poly1305::aead::Error> {
let current_counter = self.decrypt_state.counter;
let nonce = self.decrypt_state.next_nonce();
let current_counter = self.state.counter;
let nonce = self.state.next_nonce();
let data_len = data.len();
match self.decrypt_cipher.decrypt_in_place(&nonce, &nonce, data) {
match self.cipher.decrypt_in_place(&nonce, &nonce, data) {
Ok(_) => {
netrunner_logger::trace!(
counter = current_counter,
@@ -123,3 +109,29 @@ impl AeadPacker for ChaChaCipher {
}
}
}
// Контейнер для двух потоков, который легко разделяется
pub struct ChaChaCipher {
pub tx: ChaChaStream,
pub rx: ChaChaStream,
}
impl ChaChaCipher {
pub fn new() -> Self {
Self {
tx: ChaChaStream::new(&[0u8; 32], [0u8; 12]),
rx: ChaChaStream::new(&[0u8; 32], [0u8; 12]),
}
}
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
pub fn split(self) -> (ChaChaStream, ChaChaStream) {
(self.rx, self.tx)
}
}
+2 -2
View File
@@ -5,5 +5,5 @@ mod hkdf;
mod session;
pub(crate) use aead::AeadPacker;
pub(crate) use chacha::ChaChaCipher;
pub(crate) use session::SessionKeys;
pub(crate) use chacha::{ChaChaStream, ChaChaCipher};
pub(crate) use session::{SessionKeys, SessionAuth};
+43 -17
View File
@@ -13,6 +13,10 @@ type HmacSha256 = Hmac<Sha256>;
use aead::{rand_core::RngCore, OsRng};
// ==========================================
// 1. HANDSHAKE (Генерация ключей)
// ==========================================
pub(crate) struct SaltPair {
local_salt: [u8; 32],
remote_salt: [u8; 32],
@@ -74,6 +78,10 @@ impl SessionKeys {
.expect("Keys not generated yet. Call update_keys first.")
}
pub fn get_auth_key(&self) -> [u8; 32] {
self.auth_key
}
pub(crate) fn update_keys(
&mut self,
salt: [u8; 32],
@@ -139,6 +147,7 @@ impl SessionKeys {
Err("No KeyShare extension found in handshake".into())
}
}
fn generate_keys(
&mut self,
public_key: &PublicKey,
@@ -168,7 +177,36 @@ impl SessionKeys {
Ok(keys)
}
fn compute_tag(secret: &[u8], step: u64) -> [u8; 16] {
pub(crate) fn local_salt(&self) -> [u8; 32] {
self.salt.get_local()
}
pub(crate) fn public_key_bytes(&self) -> [u8; 32] {
self.ecdh.public_key.to_bytes()
}
pub(crate) fn auth_key_fingerprint(&self) -> String {
hex::encode(&self.auth_key[..4])
}
}
// ==========================================
// 2. DATA PHASE (Авторизация Кодека)
// ==========================================
/// Легковесная структура, которая передается в RxCodec и TxCodec
/// после завершения Handshake.
#[derive(Clone, Copy)]
pub struct SessionAuth {
auth_key: [u8; 32],
}
impl SessionAuth {
pub fn new(auth_key: [u8; 32]) -> Self {
Self { auth_key }
}
pub fn compute_tag(secret: &[u8], step: u64) -> [u8; 16] {
let mut mac = HmacSha256::new_from_slice(secret).expect("HMAC error");
mac.update(&step.to_be_bytes());
let result = mac.finalize().into_bytes();
@@ -177,16 +215,16 @@ impl SessionKeys {
tag
}
pub(crate) fn generate_auth_tag(&self) -> [u8; 16] {
pub fn generate_current_tag(&self) -> [u8; 16] {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
Self::compute_tag(&self.auth_key, now / 60)
Self::compute_tag(&self.auth_key, now / AUTH_TIME_STEP)
}
pub(crate) fn verify_auth_tag(&self, received_tag: &[u8; 16]) -> bool {
pub fn verify_tag(&self, received_tag: &[u8; 16]) -> bool {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went backwards")
@@ -211,16 +249,4 @@ impl SessionKeys {
);
false
}
pub(crate) fn local_salt(&self) -> [u8; 32] {
self.salt.get_local()
}
pub(crate) fn public_key_bytes(&self) -> [u8; 32] {
self.ecdh.public_key.to_bytes()
}
pub(crate) fn auth_key_fingerprint(&self) -> String {
hex::encode(&self.auth_key[..4])
}
}
}