Brownies is a lightweight, experimental cryptographic protocol and transport layer designed for secure client-server communication with strong resistance to passive traffic analysis and active probing.
It combines:
- ECDH key agreement (EC keys)
- BLAKE2s-derived session keys
- ChaCha20 stream cipher for payload encryption
- Deliberate per-byte random ±127 additive noise ("breaker")
- 16-byte random garbage prefix per packet
- Sequence-number-based RNG synchronization
The protocol deliberately makes packets look very different on every transmission - even for identical plaintext - and resists simple pattern matching & length-based analysis.
For now it's completely experimental
- Ephemeral EC key exchange (client → server public key in first packet)
- Session key derived via BLAKE2s + shared secret
- ChaCha20-based symmetric encryption of payload + type + sequence
- Breaker layer - random signed offset (-128..+127) to every byte after the garbage prefix
- Garbage prefix - 16 random bytes at the beginning of each packet
- Streaming receive buffer with incremental parsing
- Secure uniform random number generation in range (rejection sampling)
Bytes 0–15 : random garbage (16 bytes)
16–17 : length field (uint16 BE) < encrypted after this point (when in DATA state)
18 : packet type
19–22 : sequence number (uint32 BE)
23… : payload (variable)
All bytes from offset 18 onward are ChaCha20-encrypted (in DATA state).
Every byte from offset 16 onward receives an independent ±127 random offset (breaker layer).
- Payload confidentiality via ChaCha20
- Forward secrecy (ephemeral keys)
- Strong resistance to length-based traffic analysis (garbage + breaker)
- High entropy per-packet appearance (garbage prefix + per-byte noise)
- Sequence numbers prevent replay & allow synchronized RNG state
brownies_instance inst;
uint8_t static_key[32] = { ... your 32-byte static key ... };
brownies_setup(&inst, static_key, sizeof(static_key));
// Client side - generate handshake
brownies_packet_t hs_pkt;
brownies_generate_handshake_pkt(&inst, &hs_pkt);
// send encoded packet brownies_encode(&inst, &hs_pkt, buffer)
// Server side - receive ID packet
brownies_packet_t pkt;
brownies_decode(&inst, &pkt); // parses garbage + unbreaker + decrypt
brownies_handle_packet(&inst, &pkt); // processes handshake
// After handshake send encrypted DATA packets- OpenSSL (for EC key generation & ECDH)
- BLAKE2 implementation
meson setup --reconfigure build
meson compile -C build
meson test -C buildint brownies_setup(brownies_instance *inst, uint8_t *key, size_t key_size);
size_t brownies_encode(brownies_instance *inst, const brownies_packet_t *pkt, uint8_t *out);
int brownies_feed(brownies_instance *inst, const uint8_t *buf, size_t len);
int brownies_decode(brownies_instance *inst, brownies_packet_t *out);
int brownies_handle_packet(brownies_instance *inst, brownies_packet_t *pkt);
int brownies_generate_handshake_pkt(brownies_instance *inst, brownies_packet_t *out);Use at your own risk