A small scp-style program in C that copies a file from one machine to
another over an encrypted channel. The point was to build the encrypted tunnel by
hand with OpenSSL's libcrypto, instead of leaning on SSH, and to see what an
authenticated-encryption pipeline actually involves end to end.
On each side the work is split across two threads that hand data to one another through a shared buffer. On the client, one thread reads the file and runs the crypto, the other handles the network. On the server the same split runs in reverse:
AES-256-CBC using a random IV, and computes an
HMAC-SHA256 over the payload.
The two ends share a pre-shared key. The IV is fresh per transfer and read from
/dev/urandom, and it travels alongside the ciphertext because the
receiver needs it to decrypt. The HMAC is keyed from the same shared secret and
covers the encrypted bytes, so the server can detect any tampering on the wire before
it ever touches the plaintext. The check is the important part: if a single bit of the
ciphertext is flipped in flight, HMAC validation fails and the file is rejected rather
than written.
The transport itself is deliberately dumb: the actual bytes move over
netcat. The client pipes its base64 payload into an ncat
process, and the server reads it back off ncat's output and parses it.
That is why everything is base64-encoded first, it keeps the encrypted blob safe to
pass through a plain text pipe. Pushing the raw socket work onto netcat let me keep the
program focused on the encryption and authentication rather than connection management.
The useful lesson was the discipline of verify-then-decrypt: the HMAC has to be
checked before the ciphertext is trusted, and the file must not be written if the
check fails. It is a hobby reimplementation of ideas that scp and TLS
give you for free, but building the IV handling, the keyed MAC, and the failure path
yourself makes it obvious why those pieces exist.