Peer-to-peer encrypted channel library for headless projects. Built for speed and zero-trust networking.
| Layer | Technology |
|---|---|
| Transport | TLS 1.2+ with self-signed RSA-4096 certs |
| Key Exchange | X25519 ephemeral ECDH |
| Session Keys | HKDF-SHA256 |
| Channel Cipher | mini-MTProto (AES-256-IGE + SHA-256 msg_key) |
| Password Derivation | PBKDF2-HMAC-SHA256 (390k iterations) |
| Auth Challenge | HMAC-SHA256 over random nonce |
| Cert Pinning | SHA-256 fingerprint verification |
pip install fognodefrom fognode import Server, MessageEvent, ConnectEvent, DisconnectEvent
server = Server(host="0.0.0.0", port=9443, password="secret")
@server.on_event(MessageEvent)
async def on_message(ctx):
if ctx.event.text:
await ctx.answer(f"echo: {ctx.event.text}")
@server.on_event(ConnectEvent)
async def on_connect(ctx):
print("+ peer connected")
@server.on_event(DisconnectEvent)
async def on_disconnect(ctx):
print("- peer disconnected")
if __name__ == "__main__":
server.run()from fognode import Client, MessageEvent, ClosedEvent, ErrorEvent
client = Client(connect_string="7sf9Tn:9443", password="secret")
@client.on_event(MessageEvent)
async def on_message(ctx):
print(f"msg: {ctx.event.text}")
@client.on_event(ClosedEvent)
async def on_closed(ctx):
print("connection closed")
@client.on_event(ErrorEvent)
async def on_error(ctx):
print(f"error: {ctx.event.exception}")
if __name__ == "__main__":
client.connect()from fognode import start_server, client_connect
ip, code, fp = start_server("0.0.0.0", 9443, "secret")
print(f"Server running at {code}:9443") # e.g. 7sf9Tn:9443| Event | Server | Client | Description |
|---|---|---|---|
StartEvent |
yes | yes | Server/client started |
ConnectEvent |
yes | yes | Peer connected |
DisconnectEvent |
yes | yes | Peer disconnected |
MessageEvent |
yes | yes | Message received (type, text, ts) |
ClosedEvent |
no | yes | Connection closed |
ErrorEvent |
no | yes | Error occurred (exception) |
# Specific event
@server.on_event(MessageEvent)
async def handler(ctx):
pass
# Aliases
@server.on_connect()
@server.on_disconnect()
@server.on_message()
@client.on_closed()
@client.on_error()Each message is encrypted independently using a simplified MTProto 2.0 scheme:
- Serialize JSON payload to bytes
- Pad to AES block size (16 bytes)
- Compute msg_key =
SHA-256(padded)[8:24](128 bits) - Derive AES key =
SHA-256(auth_key + msg_key) - Derive AES IV =
SHA-256(msg_key + auth_key) - Encrypt with AES-256-IGE
- Send
length(4 bytes) + msg_key(16 bytes) + ciphertext
Decryption reverses the process and verifies msg_key integrity.
# Run server
fognode server --host 0.0.0.0 --port 9443 --password secret
# Interactive client
fognode client 7sf9Tn:9443 --password secret
# Probe TLS fingerprint (no auth)
fognode probe 7sf9Tn:9443
# Server status via authenticated channel
fognode status 7sf9Tn:9443 --password secret
# Send one message and exit
fognode send 7sf9Tn:9443 --password secret --text "hello"
# Monitor messages only
fognode monitor 7sf9Tn:9443 --password secret
# Show certificate info
fognode cert --file fognode_cert.pemsrc/fognode/
├── app.py # Server, Client, Context
├── cipher.py # mini-MTProto AES-256-IGE encrypt/decrypt
├── cli/
│ └── entrypoint.py # argparse CLI
├── core/
│ ├── client.py # client_connect()
│ ├── events.py # Event classes
│ ├── probe.py # probe_server()
│ └── server.py # start_server()
├── crypto/
│ ├── cert.py # Self-signed cert generation
│ ├── channel.py # SecureChannel (mini-MTProto)
│ ├── kdf.py # Session key helpers
│ ├── kx.py # X25519 keypair + shared secret
│ ├── password.py # PBKDF2 password store
│ └── primitives.py # pbkdf2, hmac256, hkdf_expand
├── filters/ # BaseFilter, Command, Text
├── handlers/ # HandlerObject
├── types/ # constants, exceptions, protocol
├── utils/ # ipwords, ratelimit, net
└── wire/ # Length-prefixed JSON framing
MIT © reekeer