From a83d663404e030a8734fddc8827fb4afe309a1b9 Mon Sep 17 00:00:00 2001 From: eunhhu Date: Mon, 28 Sep 2026 19:30:44 +0100 Subject: Keep a run's keys as bytes: one AES-GCM context serves the listener Each run a listener knew held two OpenSSL contexts. With 16 KiB pages, what those allocations left behind when idle senders went kept 42 MB of free heap resident after 10,000 senders had come and gone (in use: 0.6 MB). A run now keeps its keys (16 bytes each way and the nonce bases), and the listener seals and opens with one context, giving it each packet's key: about 130 ns a packet on this Pi. Two runs a sender, not four; a sender's address as an IPv6 one (an IPv4 one fits). What idle senders held goes back to the system once 1,024 have gone, or 10 s after any went (malloc_trim). HKDF is fetched once, not at every derivation. --- serve/seal.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'serve/seal.h') diff --git a/serve/seal.h b/serve/seal.h index e802b46..18e3e5f 100644 --- a/serve/seal.h +++ b/serve/seal.h @@ -58,7 +58,10 @@ void pure_opener_free(PureOpener *); * private key and the other's public key: the same on both sides, and * never all zeros), keys from it (HKDF-SHA256 with the info given), and * AES-128-GCM under such a key with the nonce the caller gives (sealing may - * be in place: out may be plain). A context is used by one thread at a time. */ + * be in place: out may be plain). A context is used by one thread at a time; + * sealing or opening with a key given uses that key from then on, so one + * context serves many links (a key costs about as much as a small packet), + * and NULL keeps the key it has. */ typedef struct PureAead PureAead; enum { PURE_AEAD_KEY = 16, PURE_AEAD_NONCE = 12, PURE_AEAD_TAG = 16 }; bool pure_link_secret(const PureSealKey *own, const unsigned char peer[PURE_SEAL_KEY], unsigned char out[32]); @@ -66,10 +69,12 @@ bool pure_link_derive(const unsigned char secret[32], const unsigned char *info, size_t out_size); PureAead *pure_aead(const unsigned char key[PURE_AEAD_KEY]); /* size + PURE_AEAD_TAG bytes into out. */ -bool pure_aead_seal(PureAead *, const unsigned char nonce[PURE_AEAD_NONCE], const unsigned char *aad, size_t aad_size, - const unsigned char *plain, size_t size, unsigned char *out); +bool pure_aead_seal(PureAead *, const unsigned char *key, const unsigned char nonce[PURE_AEAD_NONCE], + const unsigned char *aad, size_t aad_size, const unsigned char *plain, size_t size, + unsigned char *out); /* size - PURE_AEAD_TAG bytes into plain; false when it does not open. */ -bool pure_aead_open(PureAead *, const unsigned char nonce[PURE_AEAD_NONCE], const unsigned char *aad, - size_t aad_size, const unsigned char *sealed, size_t size, unsigned char *plain); +bool pure_aead_open(PureAead *, const unsigned char *key, const unsigned char nonce[PURE_AEAD_NONCE], + const unsigned char *aad, size_t aad_size, const unsigned char *sealed, size_t size, + unsigned char *plain); void pure_aead_free(PureAead *); #endif -- cgit v1.2.3