tiny anonymous chat for two people. no server, no accounts, nothing written to disk. you both type the same passphrase and from there everything is end to end encrypted. that's it.
honestly i just wanted to learn zig, and i didn't want to learn it on another todo app. so i picked something i actually find interesting: doing an authenticated key exchange properly.
here's the thing most "encrypted chat" demos get wrong. they do a plain diffie hellman and call it a day, which means anyone sitting in the middle can quietly swap the keys and read everything. or they stir the password into the key somewhere and a passive listener can just grab the traffic and brute force the password offline at their leisure. the actual hard problem is turning a short shared phrase into a real key without handing an attacker anything they can grind on later. that's what a pake is for, and cpace is the current cfrg one, so that's what vayu uses (over ristretto255). on top of that: fresh ephemeral keys each time so an old session stays safe even if the phrase leaks later, a key confirmation step bound to the whole handshake so a wrong phrase or a tampered exchange just dies before any real message exists, and separate keys per direction with a counter so nothing can be replayed or bounced back at you.
the zig part is the bit i was figuring out as i went. nice upside though: the std library already ships audited ristretto255, chacha20 poly1305, hkdf and hmac, so there are zero dependencies and it all compiles to one little static binary.
one side listens, the other dials. get the address to each other however you like.
VAYU_PASS="some strong shared phrase" vayu listen 0.0.0.0:9000
VAYU_PASS="some strong shared phrase" vayu dial 1.2.3.4:9000
don't set VAYU_PASS and it'll just ask, without echoing what you type. then type a line, hit enter, it pops up on the other side. ctrl d to bail.
the passphrase is the whole game. a recorded session can't be cracked offline, that's the entire point of a pake. but a weak phrase can still be guessed online, one shot per connection, so pick something real and share it somewhere you trust. get the phrase wrong and the handshake just aborts, nothing ever leaves your box.
needs zig 0.15.1.
zig build # binary shows up in zig-out/bin
zig build test # run the tests
- pake.zig cpace handshake, turns the passphrase into per direction keys
- transport.zig counter based chacha20 poly1305 channel
- frame.zig length prefixed framing with a hard size cap
- tty.zig reads the passphrase without echoing it
- chat.zig the two thread terminal loop
- main.zig the cli