diff options
| author | eunhhu <[email protected]> | 2026-09-27 19:17:02 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-27 19:17:02 +0100 |
| commit | 6d276be51ba89b04a60bb16b5179c015ad202c7c (patch) | |
| tree | 1d30ae7bbb2d1db9e9a1b627d0fb76dc26eaf074 /serve/seal.h | |
| parent | 313c4fa1720a0019c87083d3523b6643606c5aa6 (diff) | |
| download | pure-6d276be51ba89b04a60bb16b5179c015ad202c7c.tar.gz pure-6d276be51ba89b04a60bb16b5179c015ad202c7c.zip | |
Seal in one session a wire, authenticated by the sender's key (088)
A sealed request cost three X25519 operations (about 0.5 ms), so sealed
sends drained at half the plain rate. A wire now keeps one HPKE context,
encapsulated at its first seal, and seals each request as the context's
next number (a failed seal or a restart starts a new session); the
header carries the session's encapsulated key and the number, so a
receiver opens a session once per connection thread (16 remembered, the
least used replaced) and each seal by its number, also after it restarts,
unasked. A sender with a key of its own seals in HPKE auth mode and names
that key in the header; a receiver started with --sender NAME=KEY takes
deliveries only from the senders it names, each sealed with its key
(403 sender otherwise). The body is now the ciphertext and its tag.
Sealed sends, sender authenticated, drain at 461-464k a second against
462-470k plain and 207-234k sealed a request at a time (Raspberry Pi 5).
The check adds: a wire's requests share one session numbered from 0; a
changed number or sender key does not open; a receiver restarted naming
its sender opens the same session again; another node claiming that
sender's name with its own key is refused and applies nothing.
Diffstat (limited to 'serve/seal.h')
| -rw-r--r-- | serve/seal.h | 53 |
1 files changed, 37 insertions, 16 deletions
diff --git a/serve/seal.h b/serve/seal.h index 663d860..a020e0d 100644 --- a/serve/seal.h +++ b/serve/seal.h @@ -2,34 +2,55 @@ #define PURE_SEAL_H #include <stdbool.h> #include <stddef.h> +#include <stdint.h> -/* Sends sealed end to end (docs/research/086-sealed-sends.md): a receiving - * node's key opens what a sender sealed to its public key, and nothing - * between them (a relay, a proxy, a mailbox) can read or change it. HPKE - * (RFC 9180) base mode: X25519, HKDF-SHA256, and AES-128-GCM where the CPU - * has AES instructions, else ChaCha20-Poly1305. A private key lives in +/* Sends sealed end to end (docs/research/086-sealed-sends.md, 088): a + * receiving node's key opens what a sender sealed to its public key, and + * nothing between them (a relay, a proxy, a mailbox) can read or change it. + * HPKE (RFC 9180): X25519, HKDF-SHA256, and AES-128-GCM where the CPU has AES + * instructions, else ChaCha20-Poly1305; auth mode when the sender has a key + * of its own, so the receiver knows who sealed. A sender keeps one session + * (one encapsulation) and numbers its seals in it; a receiver opens a + * session once and then each seal by its number. A private key lives in * OpenSSL's secure heap: locked in memory, out of core dumps, cleared when * freed. OpenSSL comes with pure-crypto.so (serve/crypto.c), mapped the - * first time a key is read or a send sealed. */ -enum { PURE_SEAL_KEY = 32, PURE_SEAL_OVERHEAD = 32 + 16 }; /* the encapsulated key, then the tag */ + * first time a key is read or a session made. */ +enum { PURE_SEAL_KEY = 32, PURE_SEAL_OVERHEAD = 16 }; /* a public key; a seal's tag */ typedef struct PureSealKey PureSealKey; +typedef struct PureSealer PureSealer; /* a sender's session */ +typedef struct PureOpener PureOpener; /* a receiver's session */ + +/* Whether this machine can seal (pure-crypto.so maps), with why not in error. */ +bool pure_seal_ready(char *error, size_t size); /* A node's key: read from path, or made and written there (0600) when there * is none; its public half in hex. NULL with why in error. */ PureSealKey *pure_seal_key(const char *path, char public_hex[2 * PURE_SEAL_KEY + 1], char *error, size_t size); void pure_seal_key_free(PureSealKey *); -/* Whether this machine can seal (pure-crypto.so maps), with why not in error. */ -bool pure_seal_ready(char *error, size_t size); /* A public key from its hex. */ bool pure_seal_peer(const char *hex, unsigned char out[PURE_SEAL_KEY]); /* The suite this machine seals with, as the X-Pure-Seal header names it. */ const char *pure_seal_suite(void); -/* plain sealed to peer, bound to aad: size + PURE_SEAL_OVERHEAD bytes into out. */ -bool pure_seal(const unsigned char peer[PURE_SEAL_KEY], const char *aad, const unsigned char *plain, size_t size, - unsigned char *out); -/* Opened with key under suite (either this machine's or the other known one): - * size - PURE_SEAL_OVERHEAD bytes into plain; false when it does not open - * (another key, another aad, or changed on the way). */ -bool pure_unseal(const PureSealKey *, const char *suite, const char *aad, const unsigned char *sealed, size_t size, + +/* A session sealing to peer, authenticated by own when given: its + * encapsulated key into enc (what a receiver opens the session with). */ +PureSealer *pure_sealer(const unsigned char peer[PURE_SEAL_KEY], const PureSealKey *own, + unsigned char enc[PURE_SEAL_KEY]); +/* plain sealed as the session's next seal, bound to aad: size + + * PURE_SEAL_OVERHEAD bytes into out, and its number into n. */ +bool pure_seal(PureSealer *, const char *aad, const unsigned char *plain, size_t size, unsigned char *out, + uint64_t *n); +void pure_sealer_free(PureSealer *); + +/* A session a sender made to key's public half, in suite (this machine's or + * the other known one), from its enc; from is the sender's public key when + * it sealed with its own (NULL otherwise). NULL when it does not open. */ +PureOpener *pure_opener(const PureSealKey *key, const char *suite, const unsigned char enc[PURE_SEAL_KEY], + const unsigned char *from); +/* The session's seal number n: size - PURE_SEAL_OVERHEAD bytes into plain; + * false when it does not open (another session, another aad, or changed on + * the way). */ +bool pure_unseal(PureOpener *, uint64_t n, const char *aad, const unsigned char *sealed, size_t size, unsigned char *plain); +void pure_opener_free(PureOpener *); #endif |
