EXPERIMENTAL SOFTWARE. Not audited. Use for learning and testing, not for high-stakes secrets.
A terminal chat between two PCs over the internet that works from anywhere
(behind NAT, CGNAT, mobile hotspots) with no central server, no port
forwarding, no account, no router configuration. The connection travels
through Tor hidden services (.onion addresses).
- PC A runs
hostand Tor generates an ephemeral.onionaddress for this session. No key is saved to disk. - A shares that address with B out of band (voice, phone, email).
There is no port to share: the service port inside Tor is always
80. - PC B runs
connect <address.onion>and both PCs establish an end-to-end encrypted session keyed by a passphrase agreed out of band.
Every session derives two one-way AES-256-GCM keys (one per direction) from a hybrid shared secret:
- X25519 (classic ECDH) — fast classical forward secrecy;
- ML-KEM-1024 (NIST post-quantum KEM), one encapsulation per direction — the quantum-resistant component;
- the three 32-byte secrets are XOR-mixed and fed to HKDF-SHA512 (salt derived from the shared passphrase via scrypt).
So what is encrypted with ML-KEM-1024: the session keys themselves. The message content is encrypted with AES-256-GCM, but the AES keys can only be reconstructed by whoever holds all three secrets: the X25519 result and both ML-KEM-1024 shared secrets. Even a future quantum computer that breaks X25519 alone cannot derive the session key (the ML-KEM-1024 components are quantum-resistant), which defeats "harvest now, decrypt later".
- Handshake: X25519 keys + ML-KEM keys + ciphertexts + a passphrase-bound verify token are exchanged over the Tor tunnel, then verified on both sides. A wrong passphrase is rejected by both PCs.
- Each message is a frame: 4-byte length + 12-byte random nonce + AES-GCM ciphertext. Session keys are fresh on every run and never reused.
- No central server — only the Tor network (distributed relays) is used; no server you own or operate.
- No port forwarding — connections are outbound only; nothing is exposed on your router.
- No real-IP sharing — the two PCs never learn each other's public IPs;
.onionidentity only. - Port shared out of band — not needed: the virtual port is fixed at
80inside Tor. - Temporary files — the Tor DataDirectory lives in the OS temp dir and is deleted on exit; hidden-service keys are ephemeral (generated in memory, never written to disk); nothing is logged to disk by the app.
- Session encryption — fresh hybrid keys per session, AES-256-GCM with per-message nonces.
- No chat history — the app never stores messages; nothing is persisted to disk by the app.
- Wrong-passphrase detection — on both sides.
- Works from home router + mobile hotspot — verified; this is exactly the case ordinary hole punching fails on.
- Tor is not bulletproof. A powerful adversary performing traffic analysis may infer that you are using Tor (they cannot read the content: the Tor layer is encrypted and the app layer is additionally PQ-encrypted).
- Local/endpoint security. Malware, keyloggers, a compromised Python environment, or someone with physical access to either PC can read what the user sees.
- A weak passphrase. The passphrase authenticates the peers and seeds key derivation; use a long, random one. An attacker who knows it can impersonate a peer.
- Metadata (message timing and approximate length) is visible to relay operators and a local observer, as in any onion service.
- Availability. Tor circuits and hidden services can be slow or flaky; first connection takes ~30–60 s.
- Anonymity guarantees comparable to a dedicated anonymity setup are out of scope. This is a secure-communication tool, not a full anonymity suite.
- Python 3
- Tor:
sudo apt install tor - Python deps:
python3 -m venv venv && venv/bin/pip install -r requirements.txt
PC A (host) — create the .onion service and wait:
venv/bin/python kemchatka.py host
It prints [+] YOUR .onion ADDRESS: <something>.onion. Send that address to
PC B out of band and enter the shared passphrase.
PC B (client) — connect:
venv/bin/python kemchatka.py connect <something>.onion
Enter the same passphrase. If it differs, both sides reject the connection.
/quit,/exit,/q— leave- Ctrl+C — interrupt
- The passphrase can also be provided via the environment variable
KEMCHATKA_PSK. - Tor is started as a separate, isolated instance (own temp DataDirectory, own ports); no changes to your system Tor or configuration are made.
MIT — see LICENSE.