diff options
| author | eunhhu <[email protected]> | 2026-09-27 18:26:33 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-27 18:26:41 +0100 |
| commit | c635e41d8576f5587d47e51a98dfd4a8920315f0 (patch) | |
| tree | d83cf41008fb57c5bfe442dd85097758d83de2a1 /serve/seal.h | |
| parent | bd0476ff4a7bc638d4c97e03db2bf815f0389e9a (diff) | |
| download | pure-c635e41d8576f5587d47e51a98dfd4a8920315f0.tar.gz pure-c635e41d8576f5587d47e51a98dfd4a8920315f0.zip | |
Seal delivered sends to the receiver's key (086)
--seal OUTPUT=KEY seals each request's body whole to the receiving node's
public key with HPKE (RFC 9180, base mode: X25519, HKDF-SHA256, AES-128-GCM
where the CPU has AES, else ChaCha20-Poly1305), bound to the request's
source, first number and count; X-Pure-Seal names the suite. A receiver's
--key is a raw 32-byte file, made 0600 when missing, held in OpenSSL's
secure heap; it opens the body where it lies (400 seal when it does not
open) and zeroes the plain text when the request's ticket goes.
--sealed-only refuses unsealed deliveries (403 unsealed).
The check puts a recording relay between two apps: every order applies
once, no body shows an item or a field name, a flipped bit is refused, a
replayed request applies nothing twice, and a seal to another key does not
open. Its hosts choose their own ports (--port 0). Sealed sends drain at
233-235k a second against 469-470k plain (Raspberry Pi 5): three X25519
operations a request, 164 us each. The plain request path measured the
same as before.
Diffstat (limited to 'serve/seal.h')
| -rw-r--r-- | serve/seal.h | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/serve/seal.h b/serve/seal.h new file mode 100644 index 0000000..4ce3844 --- /dev/null +++ b/serve/seal.h @@ -0,0 +1,32 @@ +#ifndef PURE_SEAL_H +#define PURE_SEAL_H +#include <stdbool.h> +#include <stddef.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 + * OpenSSL's secure heap: locked in memory, out of core dumps, cleared when + * freed. */ +enum { PURE_SEAL_KEY = 32, PURE_SEAL_OVERHEAD = 32 + 16 }; /* the encapsulated key, then the tag */ + +typedef struct PureSealKey PureSealKey; +/* 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 *); +/* 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, + unsigned char *plain); +#endif |
