pub mod frame;
pub mod handshake;
pub mod transport;
pub mod stealth;
pub mod sphincs_kem;
use crate::crypto::{symmetric, hash};
use self::sphincs_kem::{SphincsKem, HybridKem};
use crate::{QsslError, QsslResult};
use rand::RngCore;
use std::time::{SystemTime, UNIX_EPOCH};
pub const QNSP_VERSION: u16 = 0x0100;
pub const QUANTUM_FRAME_SIZE: usize = 768;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FrameType {
Noise = 0x00, Handshake = 0x01, Data = 0x02, Control = 0x03, Quantum = 0x04, }
pub struct QuantumConnection {
sequence: u64,
master_secret: Vec<u8>,
frame_key: symmetric::SymmetricKey,
channel_key: symmetric::SymmetricKey,
auth_key: Vec<u8>,
frame_stream: FrameStream,
stealth_config: StealthConfig,
}
#[derive(Debug, Clone)]
pub struct StealthConfig {
pub max_padding: bool,
pub dummy_traffic: bool,
pub timing_obfuscation: bool,
pub min_frame_rate: u32,
pub quantum_rng: bool,
}
impl Default for StealthConfig {
fn default() -> Self {
Self {
max_padding: true, dummy_traffic: true, timing_obfuscation: true, min_frame_rate: 10, quantum_rng: false, }
}
}
pub struct FrameStream {
incoming: Vec<QuantumFrame>,
outgoing: Vec<QuantumFrame>,
noise_generator: NoiseGenerator,
}
#[repr(C)]
pub struct QuantumFrame {
header: EncryptedHeader,
payload: [u8; 719],
mac: [u8; 32],
}
#[repr(C)]
struct EncryptedHeader {
sequence: [u8; 8], timestamp: [u8; 8], frame_type: u8, }
struct NoiseGenerator {
enabled: bool,
rate: u32, last_noise: SystemTime,
}
impl NoiseGenerator {
fn new(rate: u32) -> Self {
Self {
enabled: true,
rate,
last_noise: SystemTime::now(),
}
}
fn maybe_generate_noise(&mut self) -> Option<QuantumFrame> {
if !self.enabled {
return None;
}
let elapsed = self.last_noise.elapsed().unwrap_or_default();
let interval = std::time::Duration::from_millis(1000 / self.rate as u64);
if elapsed >= interval {
self.last_noise = SystemTime::now();
Some(self.generate_noise_frame())
} else {
None
}
}
fn generate_noise_frame(&self) -> QuantumFrame {
let mut frame = QuantumFrame {
header: EncryptedHeader {
sequence: [0; 8],
timestamp: [0; 8],
frame_type: FrameType::Noise as u8,
},
payload: [0; 719],
mac: [0; 32],
};
rand::thread_rng().fill_bytes(&mut frame.payload);
rand::thread_rng().fill_bytes(&mut frame.mac);
frame
}
}
impl QuantumConnection {
pub async fn new(stealth_config: StealthConfig) -> QsslResult<Self> {
let master_secret = {
let mut secret = vec![0u8; 48];
rand::thread_rng().fill_bytes(&mut secret);
secret
};
let frame_key = symmetric::SymmetricKey::generate(
crate::crypto::SymmetricCipher::ChaCha20Poly1305
);
let channel_key = symmetric::SymmetricKey::generate(
crate::crypto::SymmetricCipher::Aes256Gcm
);
let mut auth_key = vec![0u8; 32];
rand::thread_rng().fill_bytes(&mut auth_key);
Ok(Self {
sequence: 0,
master_secret,
frame_key,
channel_key,
auth_key,
frame_stream: FrameStream {
incoming: Vec::new(),
outgoing: Vec::new(),
noise_generator: NoiseGenerator::new(stealth_config.min_frame_rate),
},
stealth_config,
})
}
pub async fn handshake(&mut self, is_client: bool) -> QsslResult<()> {
if is_client {
self.client_handshake().await
} else {
self.server_handshake().await
}
}
async fn client_handshake(&mut self) -> QsslResult<()> {
let kem = SphincsKem::new()?;
use pqcrypto_traits::sign::PublicKey as _;
let pk_bytes = kem.identity_pk.as_bytes();
self.send_handshake_data(pk_bytes).await?;
let ciphertext_bytes = self.receive_handshake_data().await?;
let peer_pk = self.receive_handshake_data().await?;
let shared_secret = kem.decapsulate(&ciphertext_bytes, &peer_pk)?;
self.derive_session_keys(&shared_secret)?;
Ok(())
}
async fn server_handshake(&mut self) -> QsslResult<()> {
let kem = SphincsKem::new()?;
let peer_pk_bytes = self.receive_handshake_data().await?;
let (ciphertext, shared_secret) = kem.encapsulate(&peer_pk_bytes)?;
self.send_handshake_data(&ciphertext).await?;
use pqcrypto_traits::sign::PublicKey as _;
let our_pk = kem.identity_pk.as_bytes();
self.send_handshake_data(our_pk).await?;
self.derive_session_keys(&shared_secret)?;
Ok(())
}
async fn send_handshake_data(&mut self, data: &[u8]) -> QsslResult<()> {
let chunk_size = 64;
for chunk in data.chunks(chunk_size) {
for _ in 0..rand::random::<u8>() % 5 + 1 {
self.send_noise_frame().await?;
}
self.send_frame(FrameType::Handshake, chunk).await?;
for _ in 0..rand::random::<u8>() % 3 + 1 {
self.send_noise_frame().await?;
}
if self.stealth_config.timing_obfuscation {
let delay = std::time::Duration::from_micros(
rand::random::<u64>() % 10000
);
tokio::time::sleep(delay).await;
}
}
Ok(())
}
async fn receive_handshake_data(&mut self) -> QsslResult<Vec<u8>> {
let mut data = Vec::new();
let expected_size = 800;
while data.len() < expected_size {
let frame = self.receive_frame().await?;
if frame.header.frame_type == FrameType::Handshake as u8 {
let payload_len = u16::from_be_bytes([frame.payload[0], frame.payload[1]]);
let payload = &frame.payload[2..2 + payload_len as usize];
data.extend_from_slice(payload);
}
}
Ok(data)
}
async fn send_frame(&mut self, frame_type: FrameType, data: &[u8]) -> QsslResult<()> {
let mut frame = QuantumFrame {
header: EncryptedHeader {
sequence: self.sequence.to_be_bytes(),
timestamp: self.get_timestamp(),
frame_type: frame_type as u8,
},
payload: [0; 719],
mac: [0; 32],
};
let data_len = data.len().min(717); frame.payload[0..2].copy_from_slice(&(data_len as u16).to_be_bytes());
frame.payload[2..2 + data_len].copy_from_slice(&data[..data_len]);
rand::thread_rng().fill_bytes(&mut frame.payload[2 + data_len..]);
self.encrypt_header(&mut frame.header)?;
frame.mac = self.calculate_mac(&frame)?;
self.frame_stream.outgoing.push(frame);
self.sequence += 1;
Ok(())
}
async fn send_noise_frame(&mut self) -> QsslResult<()> {
let mut noise = vec![0u8; 717];
rand::thread_rng().fill_bytes(&mut noise);
self.send_frame(FrameType::Noise, &noise).await
}
async fn receive_frame(&mut self) -> QsslResult<QuantumFrame> {
Ok(self.frame_stream.noise_generator.generate_noise_frame())
}
fn derive_session_keys(&mut self, shared_secret: &[u8]) -> QsslResult<()> {
let kdf_output = hash::hkdf(
crate::crypto::HashAlgorithm::Sha3_512,
shared_secret,
Some(&self.master_secret),
b"quantum-native-session-keys",
96,
)?;
self.frame_key = symmetric::SymmetricKey::new(
crate::crypto::SymmetricCipher::ChaCha20Poly1305,
kdf_output[0..32].to_vec(),
)?;
self.channel_key = symmetric::SymmetricKey::new(
crate::crypto::SymmetricCipher::Aes256Gcm,
kdf_output[32..64].to_vec(),
)?;
self.auth_key = kdf_output[64..96].to_vec();
Ok(())
}
fn get_timestamp(&self) -> [u8; 8] {
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_micros() as u64;
timestamp.to_be_bytes()
}
fn encrypt_header(&self, header: &mut EncryptedHeader) -> QsslResult<()> {
for (i, byte) in header.sequence.iter_mut().enumerate() {
*byte ^= self.auth_key[i % self.auth_key.len()];
}
for (i, byte) in header.timestamp.iter_mut().enumerate() {
*byte ^= self.auth_key[(i + 8) % self.auth_key.len()];
}
header.frame_type ^= self.auth_key[16];
Ok(())
}
fn calculate_mac(&self, frame: &QuantumFrame) -> QsslResult<[u8; 32]> {
use hmac::{Hmac, Mac};
use sha2::Sha256;
let mut mac = Hmac::<Sha256>::new_from_slice(&self.auth_key)
.map_err(|e| QsslError::Crypto(format!("MAC error: {}", e)))?;
mac.update(&frame.header.sequence);
mac.update(&frame.header.timestamp);
mac.update(&[frame.header.frame_type]);
mac.update(&frame.payload);
let result = mac.finalize();
let mut mac_bytes = [0u8; 32];
mac_bytes.copy_from_slice(result.into_bytes().as_slice());
Ok(mac_bytes)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_frame_size() {
assert_eq!(std::mem::size_of::<QuantumFrame>(), QUANTUM_FRAME_SIZE);
}
#[tokio::test]
async fn test_quantum_connection() {
let config = StealthConfig::default();
let conn = QuantumConnection::new(config).await.unwrap();
assert_eq!(conn.sequence, 0);
}
}