/* mse.h - BitTorrent Message Stream Encryption (MSE/PE) transport. */ #ifndef NAUT_MSE_H #define NAUT_MSE_H #include "naut/common.h" #include "naut/peer.h" #include "naut/rc4.h" #include #define NAUT_MSE_DH_LEN 96 typedef struct { naut_rc4 send; naut_rc4 recv; bool active; } naut_mse_stream; /* ---- sans-IO handshake state machine ------------------------------------- * * The outgoing MSE/PE handshake as a pure state machine over byte buffers — no * sockets — so the same logic drives the blocking apps and the io_uring reactor * (where blocking in a handshake would stall a whole core's worth of peers). * * Drive it like a codec: pump NEED_WRITE bytes out, feed NEED_READ bytes in, * repeat until DONE or ERROR, then call _finish(). * * h = naut_mse_handshake_begin(info_hash, peer_id, reserved); * for (;;) switch (naut_mse_handshake_status(h)) { * case NAUT_MSE_HS_NEED_WRITE: pull bytes, write them to the peer; break; * case NAUT_MSE_HS_NEED_READ: read bytes from the peer, feed them; break; * case NAUT_MSE_HS_DONE: naut_mse_handshake_finish(h, ...); goto ok; * case NAUT_MSE_HS_ERROR: ... ; goto err; * } */ typedef enum { NAUT_MSE_HS_NEED_READ, NAUT_MSE_HS_NEED_WRITE, NAUT_MSE_HS_DONE, NAUT_MSE_HS_ERROR, } naut_mse_hs_status; typedef struct naut_mse_handshake naut_mse_handshake; naut_mse_handshake *naut_mse_handshake_begin( const uint8_t info_hash[20], const uint8_t peer_id[NAUT_PEERID_LEN], uint64_t reserved); void naut_mse_handshake_free(naut_mse_handshake *h); naut_mse_hs_status naut_mse_handshake_status(const naut_mse_handshake *h); /* Copy pending outgoing bytes into buf (up to cap); returns the count, 0 when * nothing is queued. Call repeatedly until it returns 0. */ size_t naut_mse_handshake_pull(naut_mse_handshake *h, uint8_t *buf, size_t cap); /* Feed received bytes; *consumed reports how many were absorbed (the rest, if * any, must be re-fed — after DONE that remainder is the start of the encrypted * payload stream). Returns the new status. */ naut_mse_hs_status naut_mse_handshake_feed(naut_mse_handshake *h, const uint8_t *data, size_t len, size_t *consumed); /* Valid once status is DONE: hand out the negotiated stream and the peer's * decrypted BitTorrent handshake. */ naut_err naut_mse_handshake_finish(naut_mse_handshake *h, naut_mse_stream *stream, uint8_t remote_handshake[NAUT_HANDSHAKE_LEN]); /* Blocking convenience wrapper over the state machine: perform the whole * outgoing handshake on a blocking socket, offering RC4 only. The BitTorrent * handshake is carried as IA; the peer's decrypted handshake is returned in * remote_handshake. */ naut_err naut_mse_client_handshake( int fd, const uint8_t info_hash[20], const uint8_t peer_id[NAUT_PEERID_LEN], uint64_t reserved, naut_mse_stream *stream, uint8_t remote_handshake[NAUT_HANDSHAKE_LEN]); /* Stream I/O after a successful handshake. Encryption/decryption is in-place * with connection-owned RC4 state. send_all preserves the caller's buffer. */ bool naut_mse_send_all(int fd, naut_mse_stream *stream, const void *data, size_t len); ssize_t naut_mse_recv(int fd, naut_mse_stream *stream, void *data, size_t len); #endif /* NAUT_MSE_H */