An educational VPN prototype built from first principles with virtual network interfaces, encrypted UDP tunnelling, X25519 key exchange, and AES-GCM packet encryption.
Status: research and learning prototype. This is not a production VPN, privacy product, or anonymity tool.
| Area | Details |
|---|---|
| Focus | VPN architecture, virtual interfaces, encrypted tunnels, routing, applied crypto |
| Client | Python client path with Wintun-oriented interface code and Tkinter UI |
| Server | Python server path with TUN/Wintun concepts and NAT/routing hooks |
| Session setup | TCP handshake with X25519 public keys, HKDF salt, timestamp, and encrypted confirmation |
| Packet transport | UDP tunnel carrying AES-256-GCM encrypted packets |
| Security stance | Educational prototype with explicit non-production boundary |
VPN From Scratch explores how a VPN works internally by implementing the core pieces directly in Python instead of wrapping an existing VPN framework. The project creates virtual network interfaces, performs session setup, derives encryption keys, encrypts tunnel packets, and transports them over UDP between a client and server.
The goal is to make VPN architecture understandable at the systems level: virtual interfaces, packet capture, key exchange, authenticated encryption, UDP transport, routing, and server identity verification.
Most VPNs hide the interesting engineering behind polished clients and production infrastructure. This project exposes the machinery: how packets enter a virtual interface, how a secure session is negotiated, how tunnel traffic is encrypted, and how the server receives and forwards traffic.
It is useful as a systems/security project because it connects networking, applied cryptography, OS interfaces, and routing into one working prototype.
- virtual network interface design using TUN/Wintun concepts
- encrypted packet tunnelling over UDP
- session establishment with asymmetric key agreement and derived symmetric keys
- server identity checks through public-key pinning
- practical boundary-setting between educational security code and production security software
| Layer | Current implementation |
|---|---|
| Client | Python client with Wintun-oriented interface code and a Tkinter UI |
| Server | Python server path with TUN/Wintun concepts and routing/NAT hooks |
| Handshake | TCP setup using protocol version, timestamp, X25519 public keys, HKDF salt, and encrypted confirmation |
| Tunnel | UDP transport for encrypted packet flow |
| Cryptography | X25519 key agreement, HKDF-derived session keys, AES-256-GCM packet encryption |
| Identity | Server public-key pinning by default, with explicit insecure local-test mode |
| Config | JSON example configs committed; runtime configs and private keys ignored |
| Testing | Crypto, handshake, tunnel-flow, and loopback-oriented test scripts |
flowchart LR
App[Application traffic] --> ClientTun[Client TUN / Wintun interface]
ClientTun --> Encrypt[AES-GCM packet encryption]
Encrypt --> UDP[Encrypted UDP tunnel]
UDP --> Decrypt[Server decrypts packets]
Decrypt --> ServerTun[Server TUN / Wintun interface]
ServerTun --> Routing[NAT / routing layer]
Routing --> Net[Network / internet]
The client captures packets from a virtual network interface, encrypts them, and sends them to the server over UDP. The server decrypts each packet and forwards it into its own virtual-interface and routing path.
See docs/ARCHITECTURE.md for the deeper module-level breakdown.
The project uses a TCP handshake before switching to UDP tunnel transport:
1. ClientHello
- protocol version
- Unix timestamp
- client X25519 public key
2. ServerHello
- server X25519 public key
- HKDF salt / nonce
3. ClientAck
- encrypted confirmation message
4. UDP tunnel starts
- both sides use derived directional session keys
Server public-key pinning is used so the client does not silently accept an unknown server identity.
| Component | Purpose |
|---|---|
| X25519 | Ephemeral key agreement |
| HKDF | Session-key derivation from the shared secret |
| AES-256-GCM | Authenticated packet encryption |
| Random 96-bit nonces | Per-packet encryption nonces |
| Directional keys | Separate client-to-server and server-to-client session keys |
This is an educational cryptographic structure and has not been externally audited. See docs/SECURITY.md for the security boundary and limitations.
Install dependencies:
pip install -r requirements.txtCopy example configs:
cp config/server.example.json config/server.json
cp config/servers.example.json config/servers.jsonOn Windows PowerShell:
Copy-Item config\server.example.json config\server.json
Copy-Item config\servers.example.json config\servers.jsonDownload Wintun for Windows from:
https://www.wintun.net/
Place the local DLL at:
wintun/wintun.dll
The DLL is not committed to this repository.
Run the server:
python vpn.py serverRun the client UI:
python vpn.py clientRun built-in tests:
python vpn.py testRun the loopback integration script:
python test_vpn_loopback.pyAdministrative privileges may be required for virtual interface creation, Wintun access, route changes, and NAT configuration.
The current project includes checks for:
- AES-GCM encryption and decryption
- X25519 key agreement
- Handshake behaviour
- Tunnel packet flow
- Local loopback behaviour
Syntax validation:
python -m compileall .vpn-project/
|-- client/
| |-- crypto.py # Key exchange, encryption helpers
| |-- handshake.py # Client/server handshake flow
| |-- tunnel.py # Encrypted tunnel transport logic
| `-- wintun.py # Wintun interface wrapper
|-- server/
| |-- main.py # Server entrypoint
| `-- nat.py # NAT/routing helpers
|-- ui/
| `-- main.py # Tkinter client UI
|-- config/
| |-- server.example.json
| `-- servers.example.json
|-- docs/
| |-- ARCHITECTURE.md
| `-- SECURITY.md
|-- wintun/
| `-- README.md
|-- vpn.py # Main command entrypoint
|-- test_tun.py
|-- test_vpn_loopback.py
`-- requirements.txt
This project is not production-ready. Known limitations include:
- no external security audit
- no formal UDP replay-protection window
- no production-grade kill switch
- no mature route-leak protection
- platform-dependent NAT and routing behaviour
- limited hostile-network error handling
- no mature multi-client session management
- no installer, service manager, or automatic update flow
- no throughput optimisation for high-volume traffic
For real-world VPN use, use a mature and reviewed implementation such as WireGuard, OpenVPN, or an operating-system maintained IPsec stack.
- Add a formal UDP replay window
- Improve route setup and teardown across Windows and Linux
- Add structured logging and diagnostics
- Add integration tests that avoid privileged interfaces where possible
- Improve multi-client server handling
- Add a stronger kill-switch design
- Add UI screenshots and packet-flow diagrams
- Add packet trace logging for controlled lab debugging
- Add a minimal Linux-first setup path once routing/NAT behaviour is stable
- Package the repo as a clean educational systems lab
VPN From Scratch is the public systems/networking repo. The next useful step is to keep hardening the lab infrastructure around the tunnel: replay-window design, structured packet tracing, safer route setup/teardown, and clearer Linux-first validation once the platform-specific networking behaviour is stable.
Apache License 2.0. See LICENSE.