rfc(0015): Pluggable Transport Skins for DPI resistance
- RFC-0015: Complete specification for censorship-resistant L0 - Transport Skins: RAW, MIMIC_HTTPS, MIMIC_DNS, MIMIC_VIDEO, STEGO - Polymorphic Noise Generator (PNG): Per-session traffic shaping - Anti-fingerprinting: TLS JA3 parroting, ECH, DoH tunneling - Gherkin BDD: 50+ scenarios for TDD implementation Targets: GFW, RKN, Iran/Turkmenistan edge cases Kenya compliant: Embedded-only, no cloud calls Features: - transport_skins.feature: Skin selection, probing, defense - polymorphic_noise.feature: PNG determinism, distributions Next: Sprint 5 implementation (MIMIC_HTTPS + PNG core)
This commit is contained in:
parent
65f9af6b5d
commit
03c6389063
|
|
@ -0,0 +1,393 @@
|
|||
# RFC-0015: Pluggable Transport Skins (PTS)
|
||||
|
||||
**Status:** Draft
|
||||
**Author:** Frankie (Silicon Architect)
|
||||
**Date:** 2026-02-03
|
||||
**Target:** Janus SDK L0 Transport Layer
|
||||
**Classification:** CRYPTOGRAPHIC / CENSORSHIP-RESISTANT
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Transport Skins provide **pluggable censorship resistance** for Libertaria's L0 Transport layer. Each "skin" wraps the standard LWF (Lightweight Wire Format) frame to mimic benign traffic patterns, defeating state-level Deep Packet Inspection (DPI) as deployed by China's GFW, Russia's RKN, Iran's Filternet, and similar adversaries.
|
||||
|
||||
**Core Innovation:** Per-session **Polymorphic Noise Generator (PNG)** ensures no two sessions ever exhibit identical traffic patterns.
|
||||
|
||||
---
|
||||
|
||||
## Threat Model
|
||||
|
||||
### Adversary Capabilities (GFW-Class)
|
||||
| Technique | Capability | Our Counter |
|
||||
|-----------|------------|-------------|
|
||||
| Magic Byte Detection | Signature matching at line rate | Skins remove/replace magic bytes |
|
||||
| TLS Fingerprinting (JA3/JA4) | Statistical TLS handshake analysis | utls-style parroting (Chrome/Firefox mimicry) |
|
||||
| SNI Inspection | Cleartext server name identification | ECH (Encrypted Client Hello) + Domain Fronting |
|
||||
| Packet Size Analysis | Fixed MTU detection | Probabilistic size distributions |
|
||||
| Timing Correlation | Inter-packet timing patterns | Exponential/Gamma jitter |
|
||||
| Flow Correlation | Long-term traffic statistics | Epoch rotation (100-1000 packets) |
|
||||
| Active Probing | Sending test traffic to suspected relays | Honeytrap responses + IP blacklisting |
|
||||
| DNS Manipulation | Poisoning, blocking, inspection | DoH (DNS-over-HTTPS) tunneling |
|
||||
|
||||
### Non-Goals
|
||||
- **Traffic confirmation attacks** (end-to-end correlation): Out of scope; use L2 Membrane mixing
|
||||
- **Physical layer interception**: Out of scope; requires steganographic hardware
|
||||
- **Compromised endpoints**: Out of scope; requires TEE/SEV-SNP attestation
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ RFC-0015: TRANSPORT SKINS │
|
||||
│ "Submarine Camouflage" │
|
||||
├─────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ L3+ Application │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ LWF FRAME │ │
|
||||
│ │ • 1350 bytes (configurable) │ │
|
||||
│ │ • XChaCha20-Poly1305 encrypted │ │
|
||||
│ │ • Magic bytes: LWF\0 (internal only) │ │
|
||||
│ └─────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ POLYMORPHIC NOISE GENERATOR (PNG) │ │
|
||||
│ │ • ECDH-derived per-session seed │ │
|
||||
│ │ • Epoch-based profile rotation (100-1000 packets) │ │
|
||||
│ │ • Deterministic both ends (same seed = same noise) │ │
|
||||
│ └─────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ SKIN SELECTOR │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────┐ ┌─────────────┐ ┌───────────┐ ┌───────────┐ │ │
|
||||
│ │ │ RAW │ │MIMIC_HTTPS │ │MIMIC_DNS │ │MIMIC_VIDEO│ │ │
|
||||
│ │ │ UDP │ │WebSocket/TLS│ │DoH Tunnel │ │HLS chunks │ │ │
|
||||
│ │ └────┬────┘ └──────┬──────┘ └─────┬─────┘ └─────┬─────┘ │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ └──────────────┴───────────────┴──────────────┘ │ │
|
||||
│ │ │ │ │
|
||||
│ │ Auto-selection via probing │ │
|
||||
│ └─────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ NETWORK (ISP/GFW/RKN sees only the skin's traffic pattern) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Polymorphic Noise Generator (PNG)
|
||||
|
||||
### Design Principles
|
||||
1. **Per-session uniqueness:** ECDH handshake secret seeds ChaCha20 RNG
|
||||
2. **Deterministic:** Both peers derive identical noise from shared secret
|
||||
3. **Epoch rotation:** Profile changes every N packets (prevents long-term analysis)
|
||||
4. **Distribution matching:** Sample sizes/timing from real-world captures
|
||||
|
||||
### Noise Parameters (Per Epoch)
|
||||
```zig
|
||||
pub const EpochProfile = struct {
|
||||
// Packet size distribution
|
||||
size_distribution: enum { Normal, Pareto, Bimodal, LogNormal },
|
||||
size_mean: u16, // e.g., 1440 bytes
|
||||
size_stddev: u16, // e.g., 200 bytes
|
||||
|
||||
// Timing distribution
|
||||
timing_distribution: enum { Exponential, Gamma, Pareto },
|
||||
timing_lambda: f64, // For exponential: mean inter-packet time
|
||||
|
||||
// Dummy packet injection
|
||||
dummy_probability: f64, // 0.0-0.15 (0-15% fake packets)
|
||||
dummy_distribution: enum { Uniform, Bursty },
|
||||
|
||||
// Epoch boundaries
|
||||
epoch_packet_count: u32, // 100-1000 packets before rotation
|
||||
};
|
||||
```
|
||||
|
||||
### Seed Derivation
|
||||
```
|
||||
Session Secret (ECDH) → HKDF-SHA256 → 256-bit PNG Seed
|
||||
↓
|
||||
┌───────────────────────┐
|
||||
│ ChaCha20 RNG State │
|
||||
└───────────────────────┘
|
||||
↓
|
||||
┌───────────────────────┐
|
||||
│ Epoch Profile Chain │
|
||||
│ (deterministic) │
|
||||
└───────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Transport Skins
|
||||
|
||||
### Skin 0: RAW (Unrestricted Networks)
|
||||
**Use case:** Friendly jurisdictions, LAN, high-performance paths
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Protocol | UDP direct |
|
||||
| Port | 7844 (default) |
|
||||
| Overhead | 0% |
|
||||
| Latency | Minimal |
|
||||
| Kenya Viable | ✅ Yes |
|
||||
|
||||
**Wire format:**
|
||||
```
|
||||
[LWF Frame: 1350 bytes]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Skin 1: MIMIC_HTTPS (Standard Censorship Bypass)
|
||||
**Use case:** GFW, RKN, corporate firewalls (90% coverage)
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Protocol | WebSocket over TLS 1.3 |
|
||||
| Port | 443 |
|
||||
| SNI | Domain fronting capable (ECH preferred) |
|
||||
| Overhead | ~5% (TLS + WS framing) |
|
||||
| Latency | +50-100ms |
|
||||
| Kenya Viable | ✅ Yes |
|
||||
|
||||
**TLS Fingerprinting Defense:**
|
||||
- utls-style parroting (exact Chrome/Firefox JA3 signatures)
|
||||
- HTTP/2 settings matching browser defaults
|
||||
- ALPN: `h2, http/1.1`
|
||||
|
||||
**Wire format:**
|
||||
```
|
||||
TLS 1.3 Record Layer {
|
||||
Content Type: Application Data (23)
|
||||
TLS Ciphertext: {
|
||||
WebSocket Frame {
|
||||
FIN: 1
|
||||
Opcode: Binary (0x02)
|
||||
Masked: 0 (server→client) / 1 (client→server)
|
||||
Payload: [PNG Noise] + [LWF Frame]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**WebSocket Handshake (Cover):**
|
||||
```
|
||||
GET /api/v3/stream HTTP/1.1
|
||||
Host: cdn.cloudflare.com
|
||||
Upgrade: websocket
|
||||
Connection: Upgrade
|
||||
Sec-WebSocket-Key: <base64(random)>
|
||||
Sec-WebSocket-Version: 13
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Skin 2: MIMIC_DNS (Deep Censorship Bypass)
|
||||
**Use case:** UDP blocked, HTTPS throttled, Iran/Turkmenistan edge cases
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Protocol | DNS-over-HTTPS (DoH) |
|
||||
| Endpoint | 1.1.1.1, 8.8.8.8, 9.9.9.9 |
|
||||
| Overhead | ~300% (Base64url encoding) |
|
||||
| Latency | +200-500ms |
|
||||
| Kenya Viable | ⚠️ Marginal (bandwidth-heavy) |
|
||||
|
||||
**DNS Tunnel Defenses:**
|
||||
- **DoH not raw DNS:** Blends with real DoH traffic
|
||||
- **Query distribution:** Match real DoH query timing (not regular intervals)
|
||||
- **Label entropy:** Use dictionary words for subdomain labels (not base32)
|
||||
|
||||
**Wire format:**
|
||||
```
|
||||
POST /dns-query HTTP/2
|
||||
Host: cloudflare-dns.com
|
||||
Content-Type: application/dns-message
|
||||
Accept: application/dns-message
|
||||
|
||||
Body: DNS Message {
|
||||
Question: <LWF fragment encoded as DNS query name>
|
||||
QTYPE: TXT (or HTTPS for larger payloads)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Skin 3: MIMIC_VIDEO (High-Bandwidth Bypass)
|
||||
**Use case:** Video-streaming-whitelisted networks, QoS prioritization
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Protocol | HTTPS with HLS (HTTP Live Streaming) chunk framing |
|
||||
| Mimics | Netflix, YouTube, Twitch |
|
||||
| Overhead | ~10% (HLS `.ts` container) |
|
||||
| Latency | +100-200ms |
|
||||
| Kenya Viable | ✅ Yes |
|
||||
|
||||
**Wire format:**
|
||||
```
|
||||
HTTP/2 200 OK
|
||||
Content-Type: video/mp2t
|
||||
X-LWF-Sequence: <epoch_packet_num>
|
||||
|
||||
Body: [HLS MPEG-TS Container] {
|
||||
Adaptation Field: [PNG padding]
|
||||
Payload: [LWF Frame]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Skin 4: STEGO_IMAGE (Nuclear Option)
|
||||
**Use case:** Total lockdown, emergency fallback only
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Protocol | HTTPS POST to image hosting (Imgur, etc.) |
|
||||
| Stego Method | Generative steganography (StyleGAN encoding) |
|
||||
| Bandwidth | ~1 byte per image (extremely slow) |
|
||||
| Latency | Seconds to minutes |
|
||||
| Kenya Viable | ❌ Emergency only |
|
||||
|
||||
**Note:** Traditional LSB steganography is broken against ML detection. Use generative encoding only.
|
||||
|
||||
---
|
||||
|
||||
## Automatic Skin Selection
|
||||
|
||||
### Probe Sequence
|
||||
```zig
|
||||
pub const SkinProbe = struct {
|
||||
/// Attempt skin selection with timeouts
|
||||
pub async fn auto_select(relay: RelayEndpoint) !TransportSkin {
|
||||
// 1. RAW UDP (fastest, 100ms timeout)
|
||||
if (try probe_raw(relay, 100ms)) {
|
||||
return .raw;
|
||||
}
|
||||
|
||||
// 2. HTTPS WebSocket (500ms timeout)
|
||||
if (try probe_https(relay, 500ms)) {
|
||||
return .mimic_https(relay);
|
||||
}
|
||||
|
||||
// 3. DNS Tunnel (1s timeout)
|
||||
if (try probe_dns(relay, 1s)) {
|
||||
return .mimic_dns(relay);
|
||||
}
|
||||
|
||||
// 4. Nuclear option (no probe, async only)
|
||||
return .stego_async(relay);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Multi-Path Agility (MPTCP-Style)
|
||||
```zig
|
||||
pub const MultiSkinSession = struct {
|
||||
primary: TransportSkin, // 90% bandwidth (HTTPS)
|
||||
secondary: TransportSkin, // 10% bandwidth (DNS keepalive)
|
||||
|
||||
/// If primary throttled, signal via secondary
|
||||
pub fn adapt_to_throttling(self: *Self) void {
|
||||
if (self.primary.detect_throttling()) {
|
||||
self.secondary.signal_endpoint_switch();
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Active Probing Defenses
|
||||
|
||||
### Honeytrap Responses
|
||||
When probed without valid session state:
|
||||
1. **HTTPS Skin:** Respond as legitimate web server (nginx default page)
|
||||
2. **DNS Skin:** Return NXDOMAIN or valid A record (not relay IP)
|
||||
3. **Rate limit:** Exponential backoff on failed handshakes
|
||||
|
||||
### Reputation Tokens
|
||||
Prevent rapid relay scanning:
|
||||
```
|
||||
Client → Relay: ClientHello + PoW (Argon2, 100ms)
|
||||
Relay → Client: ServerHello (only if PoW valid)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Foundation (Sprint 5)
|
||||
- [ ] PNG core (ChaCha20 RNG, epoch rotation)
|
||||
- [ ] RAW skin (baseline)
|
||||
- [ ] MIMIC_HTTPS skin (WebSocket + TLS)
|
||||
- [ ] utls fingerprint parroting
|
||||
- [ ] Automatic probe selection
|
||||
|
||||
### Phase 2: Deep Bypass (Sprint 6)
|
||||
- [ ] MIMIC_DNS skin (DoH tunnel)
|
||||
- [ ] ECH support (Encrypted Client Hello)
|
||||
- [ ] Active probing defenses
|
||||
- [ ] Multi-path agility
|
||||
|
||||
### Phase 3: Advanced (Sprint 7)
|
||||
- [ ] MIMIC_VIDEO skin (HLS framing)
|
||||
- [ ] Distribution matching from real captures
|
||||
- [ ] Steganography (generative only)
|
||||
- [ ] Formal security audit
|
||||
|
||||
---
|
||||
|
||||
## Kenya Compliance Check
|
||||
|
||||
| Skin | RAM | Binary Size | Cloud Calls | Viable? |
|
||||
|------|-----|-------------|-------------|---------|
|
||||
| RAW | <1MB | +0KB | None | ✅ |
|
||||
| MIMIC_HTTPS | <2MB | +50KB (TLS) | None (embedded TLS) | ✅ |
|
||||
| MIMIC_DNS | <1MB | +10KB | DoH to public resolver | ✅ |
|
||||
| MIMIC_VIDEO | <2MB | +20KB (HLS) | None | ✅ |
|
||||
| STEGO | >100MB | +500MB (ML models) | Image host upload | ❌ |
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### TLS Fingerprinting (Critical)
|
||||
**Risk:** Rustls default JA3 signature is trivially blockable.
|
||||
**Mitigation:** Mandatory utls parroting; exact Chrome/Firefox match.
|
||||
|
||||
### DNS Tunnel Detectability (High)
|
||||
**Risk:** Base32 subdomains have high entropy (4.8 vs 2.5 bits/char).
|
||||
**Mitigation:** Use DoH to major providers; dictionary-word labels.
|
||||
|
||||
### Flow Correlation (Medium)
|
||||
**Risk:** Long-term traffic statistics identify protocol.
|
||||
**Mitigation:** PNG epoch rotation; per-session uniqueness.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
1. **utls:** [github.com/refraction-networking/utls](https://github.com/refraction-networking/utls) — TLS fingerprint parroting
|
||||
2. **Snowflake:** [Tor Project](https://snowflake.torproject.org/) — WebRTC pluggable transport
|
||||
3. **Conjure:** [refraction.network](https://refraction.network/) — Refraction networking
|
||||
4. **ECH:** RFC 9446 — Encrypted Client Hello
|
||||
5. **DoH:** RFC 8484 — DNS over HTTPS
|
||||
|
||||
---
|
||||
|
||||
*"The submarine wears chameleon skin. The hull remains the same."*
|
||||
⚡️
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
Feature: RFC-0015 Polymorphic Noise Generator (PNG)
|
||||
As a Libertaria protocol developer
|
||||
I want cryptographically secure per-session traffic shaping
|
||||
So that state-level DPI cannot fingerprint or correlate sessions
|
||||
|
||||
Background:
|
||||
Given the PNG is initialized with ChaCha20 RNG
|
||||
And the entropy source is the ECDH shared secret
|
||||
|
||||
# ============================================================================
|
||||
# Seed Derivation and Determinism
|
||||
# ============================================================================
|
||||
|
||||
Scenario: PNG seed derives from ECDH shared secret
|
||||
Given Alice and Bob perform X25519 ECDH
|
||||
And the shared secret is 32 bytes
|
||||
When Alice derives PNG seed via HKDF-SHA256
|
||||
And Bob derives PNG seed via HKDF-SHA256
|
||||
Then both seeds should be 256 bits
|
||||
And the seeds should be identical
|
||||
And the derivation should use "Libertaria-PNG-v1" as context
|
||||
|
||||
Scenario: Different sessions produce different seeds
|
||||
Given Alice and Bob perform ECDH for Session A
|
||||
And Alice and Bob perform ECDH for Session B
|
||||
When PNG seeds are derived for both sessions
|
||||
Then the seeds should be different
|
||||
And the Hamming distance should be ~128 bits
|
||||
|
||||
Scenario: PNG seed has sufficient entropy
|
||||
Given 1000 independent ECDH handshakes
|
||||
When PNG seeds are derived for all sessions
|
||||
Then no seed collisions should occur
|
||||
And the distribution should pass Chi-square randomness test
|
||||
|
||||
# ============================================================================
|
||||
# Epoch Profile Generation
|
||||
# ============================================================================
|
||||
|
||||
Scenario: Epoch profile contains all noise parameters
|
||||
Given a PNG with valid seed
|
||||
When the first epoch profile is generated
|
||||
Then it should contain size_distribution variant
|
||||
And size_mean and size_stddev parameters
|
||||
And timing_distribution variant
|
||||
And timing_lambda parameter
|
||||
And dummy_probability between 0.0 and 0.15
|
||||
And epoch_packet_count between 100 and 1000
|
||||
|
||||
Scenario: Sequential epochs are deterministic
|
||||
Given a PNG with seed S
|
||||
When epoch 0 profile is generated
|
||||
And epoch 1 profile is generated
|
||||
And a second PNG with same seed S
|
||||
When epoch 0 and 1 profiles are generated again
|
||||
Then all corresponding epochs should match exactly
|
||||
|
||||
Scenario: Different seeds produce uncorrelated epochs
|
||||
Given PNG A with seed S1
|
||||
And PNG B with seed S2
|
||||
When 10 epochs are generated for both
|
||||
Then size_mean of corresponding epochs should not correlate
|
||||
And timing_lambda values should not correlate
|
||||
And Kolmogorov-Smirnov test should show different distributions
|
||||
|
||||
# ============================================================================
|
||||
# Packet Size Noise
|
||||
# ============================================================================
|
||||
|
||||
Scenario Outline: Packet size distributions match theoretical models
|
||||
Given the epoch profile specifies <distribution> distribution
|
||||
And size_mean = <mean> bytes
|
||||
And size_stddev = <stddev> bytes
|
||||
When 10000 packet sizes are sampled
|
||||
Then the empirical distribution should match theoretical <distribution>
|
||||
And the Chi-square test p-value should be > 0.05
|
||||
|
||||
Examples:
|
||||
| distribution | mean | stddev |
|
||||
| Normal | 1440 | 200 |
|
||||
| Pareto | 1440 | 400 |
|
||||
| Bimodal | 1200 | 300 |
|
||||
| LogNormal | 1500 | 250 |
|
||||
|
||||
Scenario: Packet sizes stay within valid bounds
|
||||
Given any epoch profile
|
||||
When packet sizes are sampled
|
||||
Then all sizes should be >= 64 bytes
|
||||
And all sizes should be <= 1500 bytes (Ethernet MTU)
|
||||
And sizes should never exceed interface MTU
|
||||
|
||||
Scenario: Bimodal distribution matches video streaming
|
||||
Given video streaming capture data
|
||||
And epoch specifies Bimodal distribution
|
||||
When PNG samples packet sizes
|
||||
Then the two modes should be at ~600 bytes and ~1440 bytes
|
||||
And the ratio should be approximately 1:3
|
||||
And the distribution should match YouTube 1080p captures
|
||||
|
||||
# ============================================================================
|
||||
# Timing Noise (Inter-packet Jitter)
|
||||
# ============================================================================
|
||||
|
||||
Scenario Outline: Timing distributions match theoretical models
|
||||
Given the epoch profile specifies <distribution> timing
|
||||
And timing_lambda = <lambda>
|
||||
When 10000 inter-packet delays are sampled
|
||||
Then the empirical distribution should match theoretical <distribution>
|
||||
|
||||
Examples:
|
||||
| distribution | lambda |
|
||||
| Exponential | 0.01 |
|
||||
| Gamma | 0.005 |
|
||||
| Pareto | 0.001 |
|
||||
|
||||
Scenario: Timing jitter prevents clock skew attacks
|
||||
Given an adversary measures inter-packet timing
|
||||
When the PNG applies jitter with Exponential distribution
|
||||
Then the coefficient of variation should be high (>0.5)
|
||||
And timing side-channel attacks should fail
|
||||
|
||||
Scenario: Maximum latency bound enforcement
|
||||
Given real-time voice application requirements
|
||||
And maximum acceptable latency of 500ms
|
||||
When timing noise is applied
|
||||
Then no single packet should be delayed >500ms
|
||||
And 99th percentile latency should be <300ms
|
||||
|
||||
# ============================================================================
|
||||
# Dummy Packet Injection
|
||||
# ============================================================================
|
||||
|
||||
Scenario: Dummy injection rate follows probability
|
||||
Given dummy_probability = 0.10 (10%)
|
||||
When 10000 transmission opportunities occur
|
||||
Then approximately 1000 dummy packets should be injected
|
||||
And the binomial 95% confidence interval should contain the count
|
||||
|
||||
Scenario: Dummy packets are indistinguishable from real
|
||||
Given a mix of real and dummy packets
|
||||
When examined by adversary
|
||||
Then packet sizes should have same distribution
|
||||
And timing should follow same patterns
|
||||
And entropy analysis should not distinguish them
|
||||
|
||||
Scenario: Bursty dummy injection pattern
|
||||
Given dummy_distribution = Bursty
|
||||
And dummy_probability = 0.15
|
||||
When dummies are injected
|
||||
Then they should arrive in clusters (bursts)
|
||||
And inter-burst gaps should follow exponential distribution
|
||||
And intra-burst timing should be rapid
|
||||
|
||||
# ============================================================================
|
||||
# Epoch Rotation
|
||||
# ============================================================================
|
||||
|
||||
Scenario: Epoch rotates after packet count threshold
|
||||
Given epoch_packet_count = 500
|
||||
When 499 packets are transmitted
|
||||
Then the profile should remain unchanged
|
||||
When the 500th packet is transmitted
|
||||
Then epoch rotation should trigger
|
||||
And a new epoch profile should be generated
|
||||
|
||||
Scenario: Epoch rotation preserves session state
|
||||
Given an active encrypted session
|
||||
And epoch rotation triggers
|
||||
When the new epoch begins
|
||||
Then encryption keys should remain valid
|
||||
And sequence numbers should continue monotonically
|
||||
And no rekeying should be required
|
||||
|
||||
Scenario: Maximum epoch duration prevents indefinite exposure
|
||||
Given epoch_packet_count = 1000
|
||||
And a low-bandwidth application sends 1 packet/minute
|
||||
When 60 minutes elapse with only 60 packets
|
||||
Then the epoch should rotate anyway (time-based fallback)
|
||||
And the maximum epoch duration should be 10 minutes
|
||||
|
||||
# ============================================================================
|
||||
# Integration with Transport Skins
|
||||
# ============================================================================
|
||||
|
||||
Scenario: PNG noise applied before skin wrapping
|
||||
Given MIMIC_HTTPS skin is active
|
||||
And an LWF frame of 1350 bytes
|
||||
When PNG adds padding noise
|
||||
Then the total size should follow epoch's distribution
|
||||
And the padding should be added before TLS encryption
|
||||
And the WebSocket frame should contain padded payload
|
||||
|
||||
Scenario: PNG noise subtraction by receiving peer
|
||||
Given PNG adds 50 bytes of padding to a packet
|
||||
When the packet arrives at destination
|
||||
And the peer uses same PNG seed
|
||||
Then the padding should be identifiable
|
||||
And the original 1350-byte LWF frame should be recoverable
|
||||
|
||||
Scenario: Different skins use same PNG instance
|
||||
Given a session starts with RAW skin
|
||||
And PNG is seeded
|
||||
When skin switches to MIMIC_HTTPS
|
||||
Then the PNG should continue same epoch sequence
|
||||
And noise patterns should remain consistent
|
||||
|
||||
# ============================================================================
|
||||
# Statistical Security Tests
|
||||
# ============================================================================
|
||||
|
||||
Scenario: NIST SP 800-22 randomness tests
|
||||
Given 1MB of PNG output (ChaCha20 keystream)
|
||||
When subjected to NIST statistical test suite
|
||||
Then all 15 tests should pass
|
||||
Including Frequency, Runs, FFT, Template matching
|
||||
|
||||
Scenario: Dieharder randomness tests
|
||||
Given 10MB of PNG output
|
||||
When subjected to Dieharder test suite
|
||||
Then no tests should report "WEAK" or "FAILED"
|
||||
|
||||
Scenario: Avalanche effect on seed changes
|
||||
Given PNG seed S1 produces output stream O1
|
||||
When one bit is flipped in seed (S2 = S1 XOR 0x01)
|
||||
And output stream O2 is generated
|
||||
Then O1 and O2 should differ in ~50% of bits
|
||||
And the correlation coefficient should be ~0
|
||||
|
||||
# ============================================================================
|
||||
# Performance and Resource Usage
|
||||
# ============================================================================
|
||||
|
||||
Scenario: PNG generation is fast enough for line rate
|
||||
Given 1 Gbps network interface
|
||||
And 1500 byte packets
|
||||
When PNG generates noise for each packet
|
||||
Then generation time should be <1μs per packet
|
||||
And CPU usage should be <5% of one core
|
||||
|
||||
Scenario: PNG memory footprint is minimal
|
||||
Given the PNG is initialized
|
||||
When measuring memory usage
|
||||
Then ChaCha20 state should use ≤136 bytes
|
||||
And epoch profile should use ≤64 bytes
|
||||
And total PNG overhead should be <1KB per session
|
||||
|
||||
Scenario: PNG works on constrained devices
|
||||
Given a device with 10MB RAM (Kenya compliance)
|
||||
When 1000 concurrent sessions are active
|
||||
Then total PNG memory should be <10MB
|
||||
And each session PNG overhead should be <10KB
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
Feature: RFC-0015 Pluggable Transport Skins
|
||||
As a Libertaria node operator in a censored region
|
||||
I want to automatically select camouflaged transport protocols
|
||||
So that my traffic evades detection by state-level DPI (GFW, RKN, etc.)
|
||||
|
||||
Background:
|
||||
Given the L0 transport layer is initialized
|
||||
And the node has a valid relay endpoint configuration
|
||||
And the Polymorphic Noise Generator (PNG) is seeded with ECDH secret
|
||||
|
||||
# ============================================================================
|
||||
# Skin Selection and Probing
|
||||
# ============================================================================
|
||||
|
||||
Scenario: Automatic skin selection succeeds with RAW UDP
|
||||
Given the network allows outbound UDP to port 7844
|
||||
When the skin probe sequence starts
|
||||
And the RAW UDP probe completes within 100ms
|
||||
Then the transport skin should be "RAW"
|
||||
And the LWF frames should be sent unmodified over UDP
|
||||
|
||||
Scenario: Automatic skin selection falls back to HTTPS
|
||||
Given the network blocks UDP port 7844
|
||||
And HTTPS traffic to port 443 is allowed
|
||||
When the RAW UDP probe times out after 100ms
|
||||
And the HTTPS WebSocket probe completes within 500ms
|
||||
Then the transport skin should be "MIMIC_HTTPS"
|
||||
And the LWF frames should be wrapped in WebSocket frames over TLS 1.3
|
||||
|
||||
Scenario: Automatic skin selection falls back to DNS tunnel
|
||||
Given the network blocks all UDP except DNS
|
||||
And blocks HTTPS to non-whitelisted domains
|
||||
When the RAW UDP probe times out
|
||||
And the HTTPS probe times out after 500ms
|
||||
And the DNS DoH probe completes within 1s
|
||||
Then the transport skin should be "MIMIC_DNS"
|
||||
And the LWF frames should be encoded as DNS queries over HTTPS
|
||||
|
||||
Scenario: Automatic skin selection reaches nuclear option
|
||||
Given the network implements deep packet inspection on all protocols
|
||||
And all previous probes fail
|
||||
When the probe sequence reaches the steganography fallback
|
||||
Then the transport skin should be "STEGO_IMAGE"
|
||||
And the user should be warned of extreme latency
|
||||
|
||||
# ============================================================================
|
||||
# Polymorphic Noise Generator (PNG)
|
||||
# ============================================================================
|
||||
|
||||
Scenario: PNG generates per-session unique noise
|
||||
Given two independent sessions to the same relay
|
||||
And both sessions complete ECDH handshake
|
||||
When Session A derives PNG seed from shared secret
|
||||
And Session B derives PNG seed from its shared secret
|
||||
Then the PNG seeds should be different
|
||||
And the epoch profiles should be different
|
||||
And the packet size distributions should not correlate
|
||||
|
||||
Scenario: PNG generates deterministic noise for session peers
|
||||
Given a single session between Alice and Bob
|
||||
And they complete ECDH handshake
|
||||
When Alice derives PNG seed from shared secret
|
||||
And Bob derives PNG seed from same shared secret
|
||||
Then the PNG seeds should be identical
|
||||
And Alice's noise can be subtracted by Bob
|
||||
|
||||
Scenario: PNG epoch rotation prevents long-term analysis
|
||||
Given a session using MIMIC_HTTPS skin
|
||||
And the epoch length is set to 500 packets
|
||||
When 499 packets have been transmitted
|
||||
Then the packet size distribution should follow Profile A
|
||||
When the 500th packet is transmitted
|
||||
Then the epoch should rotate
|
||||
And the packet size distribution should follow Profile B
|
||||
And Profile B should be different from Profile A
|
||||
|
||||
Scenario: PNG matches real-world distributions
|
||||
Given MIMIC_HTTPS skin with Netflix emulation
|
||||
When the PNG samples packet sizes
|
||||
Then the distribution should be Pareto with mean 1440 bytes
|
||||
And the distribution should match Netflix video chunk captures
|
||||
|
||||
# ============================================================================
|
||||
# MIMIC_HTTPS Skin (WebSocket over TLS)
|
||||
# ============================================================================
|
||||
|
||||
Scenario: HTTPS skin mimics Chrome TLS fingerprint
|
||||
Given the transport skin is "MIMIC_HTTPS"
|
||||
When the TLS handshake initiates
|
||||
Then the ClientHello should match Chrome 120 JA3 signature
|
||||
And the cipher suites should match Chrome defaults
|
||||
And the extensions order should match Chrome
|
||||
And the ALPN should be "h2,http/1.1"
|
||||
|
||||
Scenario: HTTPS skin WebSocket handshake looks legitimate
|
||||
Given the transport skin is "MIMIC_HTTPS"
|
||||
When the WebSocket upgrade request is sent
|
||||
Then the HTTP headers should include legitimate User-Agent
|
||||
And the request path should look like a real API endpoint
|
||||
And the Origin header should be set appropriately
|
||||
|
||||
Scenario: HTTPS skin hides LWF magic bytes
|
||||
Given an LWF frame with magic bytes "LWF\0"
|
||||
When wrapped in MIMIC_HTTPS skin
|
||||
Then the wire format should be TLS ciphertext
|
||||
And the magic bytes should not appear in cleartext
|
||||
And DPI signature matching should fail
|
||||
|
||||
Scenario: HTTPS skin with domain fronting
|
||||
Given the relay supports domain fronting
|
||||
And the cover domain is "cdn.cloudflare.com"
|
||||
And the real endpoint is "relay.libertaria.network"
|
||||
When the TLS handshake initiates
|
||||
Then the SNI should be "cdn.cloudflare.com"
|
||||
And the HTTP Host header should be "relay.libertaria.network"
|
||||
|
||||
Scenario: HTTPS skin with ECH (Encrypted Client Hello)
|
||||
Given the relay supports ECH
|
||||
And the client has ECH config for the relay
|
||||
When the TLS handshake initiates
|
||||
Then the ClientHelloInner should contain real SNI
|
||||
And the ClientHelloOuter should have encrypted SNI
|
||||
And passive DPI should not see the real destination
|
||||
|
||||
# ============================================================================
|
||||
# MIMIC_DNS Skin (DoH Tunnel)
|
||||
# ============================================================================
|
||||
|
||||
Scenario: DNS skin uses DoH not raw DNS
|
||||
Given the transport skin is "MIMIC_DNS"
|
||||
When a DNS query is sent
|
||||
Then it should be an HTTPS POST to 1.1.1.1
|
||||
And the Content-Type should be "application/dns-message"
|
||||
And not use raw port 53 UDP
|
||||
|
||||
Scenario: DNS skin avoids high-entropy labels
|
||||
Given the transport skin is "MIMIC_DNS"
|
||||
When encoding LWF data as DNS queries
|
||||
Then subdomain labels should use dictionary words
|
||||
And the Shannon entropy should be < 3.5 bits/char
|
||||
And not use Base32/Base64 encoding
|
||||
|
||||
Scenario: DNS skin matches real DoH timing
|
||||
Given the transport skin is "MIMIC_DNS"
|
||||
When sending queries
|
||||
Then the inter-query timing should follow Gamma distribution
|
||||
And not be perfectly regular
|
||||
And should match Cloudflare DoH query patterns
|
||||
|
||||
# ============================================================================
|
||||
# Anti-Fingerprinting and Active Defense
|
||||
# ============================================================================
|
||||
|
||||
Scenario: Active probe receives honeytrap response
|
||||
Given an adversary sends probe traffic to relay
|
||||
And the probe has no valid session cookie
|
||||
When the relay receives the probe
|
||||
Then it should respond as nginx default server
|
||||
And return HTTP 200 with generic index.html
|
||||
And not reveal itself as Libertaria relay
|
||||
|
||||
Scenario: Rate limiting on failed handshakes
|
||||
Given an adversary attempts rapid handshake scanning
|
||||
When more than 10 failed handshakes occur from same IP in 1 minute
|
||||
Then subsequent connections should be rate limited
|
||||
And exponential backoff should apply
|
||||
|
||||
Scenario: PoW prevents relay enumeration
|
||||
Given the relay requires proof-of-work
|
||||
When a client connects without valid PoW
|
||||
Then the connection should be rejected
|
||||
When a client connects with valid Argon2 PoW (100ms compute)
|
||||
Then the connection should proceed to handshake
|
||||
|
||||
# ============================================================================
|
||||
# Multi-Path Agility
|
||||
# ============================================================================
|
||||
|
||||
Scenario: Primary skin throttling triggers fallback
|
||||
Given primary skin is MIMIC_HTTPS at 90% bandwidth
|
||||
And secondary skin is MIMIC_DNS at 10% bandwidth
|
||||
When GFW detects and throttles HTTPS traffic
|
||||
Then the secondary channel should signal endpoint switch
|
||||
And the primary should migrate to new relay IP
|
||||
|
||||
Scenario: Seamless skin switching without rekeying
|
||||
Given an active session with MIMIC_HTTPS
|
||||
When the skin switches to MIMIC_DNS due to blocking
|
||||
Then the LWF encryption keys should remain valid
|
||||
And no re-handshake should be required
|
||||
And in-flight packets should not be lost
|
||||
|
||||
# ============================================================================
|
||||
# Error Handling and Edge Cases
|
||||
# ============================================================================
|
||||
|
||||
Scenario: All probes fail raises alert
|
||||
Given all network paths are blocked
|
||||
When the skin probe sequence completes
|
||||
And no viable skin is found
|
||||
Then the user should receive "Network severely restricted" alert
|
||||
And manual configuration option should be offered
|
||||
|
||||
Scenario: Skin mid-session failure recovery
|
||||
Given a session is active with MIMIC_HTTPS
|
||||
When the TLS connection drops unexpectedly
|
||||
Then automatic reconnection should attempt same skin first
|
||||
And fallback to next skin after 3 retries
|
||||
|
||||
Scenario: Invalid skin configuration is rejected
|
||||
Given the configuration specifies unknown skin "MIMIC_UNKNOWN"
|
||||
When the transport initializes
|
||||
Then initialization should fail with "Invalid skin"
|
||||
And fallback to automatic selection should occur
|
||||
Loading…
Reference in New Issue