aboutsummaryrefslogtreecommitdiffstats
path: root/serve
diff options
context:
space:
mode:
Diffstat (limited to 'serve')
-rw-r--r--serve/crypto-openssl.c30
-rw-r--r--serve/crypto.c14
-rw-r--r--serve/crypto.h12
-rw-r--r--serve/link.c95
-rw-r--r--serve/seal.h15
5 files changed, 100 insertions, 66 deletions
diff --git a/serve/crypto-openssl.c b/serve/crypto-openssl.c
index 6ff1ad4..67ce5fd 100644
--- a/serve/crypto-openssl.c
+++ b/serve/crypto-openssl.c
@@ -207,10 +207,23 @@ static bool link_secret(const PureSealKey *own, const unsigned char peer[PURE_SE
return ok && any;
}
+/* HKDF, fetched once. */
+static EVP_KDF *hkdf(void) {
+ static EVP_KDF *kept;
+ EVP_KDF *kdf = __atomic_load_n(&kept, __ATOMIC_ACQUIRE), *none = NULL;
+ if (kdf) return kdf;
+ if ((kdf = EVP_KDF_fetch(NULL, "HKDF", NULL)) &&
+ !__atomic_compare_exchange_n(&kept, &none, kdf, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
+ EVP_KDF_free(kdf); /* another thread's is kept */
+ kdf = none;
+ }
+ return kdf;
+}
+
static bool link_derive(const unsigned char secret[32], const unsigned char *info, size_t info_size, unsigned char *out,
size_t out_size) {
static const char salt[] = "pure link 0";
- EVP_KDF *kdf = EVP_KDF_fetch(NULL, "HKDF", NULL);
+ EVP_KDF *kdf = hkdf();
EVP_KDF_CTX *context = kdf ? EVP_KDF_CTX_new(kdf) : NULL;
OSSL_PARAM params[] = {OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, (char *)"SHA256", 0),
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, (void *)secret, 32),
@@ -219,7 +232,6 @@ static bool link_derive(const unsigned char secret[32], const unsigned char *inf
OSSL_PARAM_construct_end()};
bool ok = context && EVP_KDF_derive(context, out, out_size, params) == 1;
EVP_KDF_CTX_free(context);
- EVP_KDF_free(kdf);
return ok;
}
@@ -243,22 +255,24 @@ static PureAead *aead(const unsigned char key[PURE_AEAD_KEY]) {
return a;
}
-static bool aead_seal(PureAead *a, 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) {
+static bool aead_seal(PureAead *a, 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) {
int n = 0, last = 0;
- return size <= INT_MAX && EVP_EncryptInit_ex(a->seal, NULL, NULL, NULL, nonce) == 1 &&
+ return size <= INT_MAX && EVP_EncryptInit_ex(a->seal, NULL, NULL, key, nonce) == 1 &&
(!aad_size || EVP_EncryptUpdate(a->seal, NULL, &n, aad, (int)aad_size) == 1) &&
(!size || EVP_EncryptUpdate(a->seal, out, &n, plain, (int)size) == 1) &&
EVP_EncryptFinal_ex(a->seal, out + size, &last) == 1 &&
EVP_CIPHER_CTX_ctrl(a->seal, EVP_CTRL_GCM_GET_TAG, PURE_AEAD_TAG, out + size) == 1;
}
-static bool aead_open(PureAead *a, 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) {
+static bool aead_open(PureAead *a, 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) {
int n = 0, last = 0;
if (size < PURE_AEAD_TAG || size - PURE_AEAD_TAG > INT_MAX) return false;
size_t body = size - PURE_AEAD_TAG;
- return EVP_DecryptInit_ex(a->open, NULL, NULL, NULL, nonce) == 1 &&
+ return EVP_DecryptInit_ex(a->open, NULL, NULL, key, nonce) == 1 &&
(!aad_size || EVP_DecryptUpdate(a->open, NULL, &n, aad, (int)aad_size) == 1) &&
(!body || EVP_DecryptUpdate(a->open, plain, &n, sealed, (int)body) == 1) &&
EVP_CIPHER_CTX_ctrl(a->open, EVP_CTRL_GCM_SET_TAG, PURE_AEAD_TAG, (void *)(sealed + body)) == 1 &&
diff --git a/serve/crypto.c b/serve/crypto.c
index d43de93..da63b37 100644
--- a/serve/crypto.c
+++ b/serve/crypto.c
@@ -152,14 +152,16 @@ PureAead *pure_aead(const unsigned char key[PURE_AEAD_KEY]) {
return c ? c->aead(key) : NULL;
}
-bool pure_aead_seal(PureAead *a, 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) {
- return crypto->aead_seal(a, nonce, aad, aad_size, plain, size, out);
+bool pure_aead_seal(PureAead *a, 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) {
+ return crypto->aead_seal(a, key, nonce, aad, aad_size, plain, size, out);
}
-bool pure_aead_open(PureAead *a, 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) {
- return crypto->aead_open(a, nonce, aad, aad_size, sealed, size, plain);
+bool pure_aead_open(PureAead *a, 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) {
+ return crypto->aead_open(a, key, nonce, aad, aad_size, sealed, size, plain);
}
void pure_aead_free(PureAead *a) { if (a) crypto->aead_free(a); }
diff --git a/serve/crypto.h b/serve/crypto.h
index b8a48fd..53e9c2c 100644
--- a/serve/crypto.h
+++ b/serve/crypto.h
@@ -8,7 +8,7 @@
* first time a server seals, opens a seal or connects to an https receiver
* (serve/crypto.c): one that does none of these maps no OpenSSL, 2.3 MiB
* less resident and 0.6 MiB less of its own. */
-enum { PURE_CRYPTO_VERSION = 3 };
+enum { PURE_CRYPTO_VERSION = 4 };
typedef struct {
unsigned version;
@@ -38,10 +38,12 @@ typedef struct {
bool (*link_derive)(const unsigned char secret[32], const unsigned char *info, size_t info_size, unsigned char *out,
size_t out_size);
PureAead *(*aead)(const unsigned char key[PURE_AEAD_KEY]);
- bool (*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 (*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 (*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);
+ bool (*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 (*aead_free)(PureAead *);
} PureCrypto;
#endif
diff --git a/serve/link.c b/serve/link.c
index f9e5c07..ed1b695 100644
--- a/serve/link.c
+++ b/serve/link.c
@@ -20,7 +20,7 @@
enum { VERSION = 0x70, HEADER = 21, DATAGRAM = 1200, BODY = DATAGRAM - HEADER - PURE_AEAD_TAG, PIECE = 1000 };
enum { F_STREAM = 1, F_RECORD = 2, F_ACK = 3, F_STORED = 4, F_PING = 5, STORED_GAP = 1 };
-enum { RANGES = 32, RUNS = 4, UNITS = 64, CREDIT = 1024, BATCH = 256, RECORD_HEAD = 19 };
+enum { RANGES = 32, RUNS = 2, UNITS = 64, CREDIT = 1024, BATCH = 256, RECORD_HEAD = 19 };
enum { WINDOW_FIRST = 10 * DATAGRAM, WINDOW_LEAST = 2 * DATAGRAM };
#define MS UINT64_C(1000000)
/* RFC 9002's values, but a first RTT of 100 ms (a LAN's, not the 333 ms of
@@ -75,19 +75,29 @@ static uint64_t random64(void) {
/* The key and nonce base of packets from `from` (in its run from_run) to
* `to`, answering to_run (0 for none). */
-static PureAead *derive(const unsigned char secret[32], const unsigned char from[PURE_SEAL_KEY],
- const unsigned char to[PURE_SEAL_KEY], uint64_t from_run, uint64_t to_run,
- unsigned char base[PURE_AEAD_NONCE]) {
+static bool derive(const unsigned char secret[32], const unsigned char from[PURE_SEAL_KEY],
+ const unsigned char to[PURE_SEAL_KEY], uint64_t from_run, uint64_t to_run,
+ unsigned char key[PURE_AEAD_KEY], unsigned char base[PURE_AEAD_NONCE]) {
unsigned char info[16 + 2 * PURE_SEAL_KEY + 16], out[PURE_AEAD_KEY + PURE_AEAD_NONCE];
memcpy(info, "pure link 0 keys", 16);
memcpy(info + 16, from, PURE_SEAL_KEY);
memcpy(info + 16 + PURE_SEAL_KEY, to, PURE_SEAL_KEY);
put64(info + 16 + 2 * PURE_SEAL_KEY, from_run);
put64(info + 24 + 2 * PURE_SEAL_KEY, to_run);
- if (!pure_link_derive(secret, info, sizeof(info), out, sizeof(out))) return NULL;
+ if (!pure_link_derive(secret, info, sizeof(info), out, sizeof(out))) return false;
+ memcpy(key, out, PURE_AEAD_KEY);
memcpy(base, out + PURE_AEAD_KEY, PURE_AEAD_NONCE);
- PureAead *aead = pure_aead(out);
explicit_bzero(out, sizeof(out));
+ return true;
+}
+
+/* The same as a context of its own, for a sender's one link. */
+static PureAead *aead_of(const unsigned char secret[32], const unsigned char from[PURE_SEAL_KEY],
+ const unsigned char to[PURE_SEAL_KEY], uint64_t from_run, uint64_t to_run,
+ unsigned char base[PURE_AEAD_NONCE]) {
+ unsigned char key[PURE_AEAD_KEY];
+ PureAead *aead = derive(secret, from, to, from_run, to_run, key, base) ? pure_aead(key) : NULL;
+ explicit_bzero(key, sizeof(key));
return aead;
}
@@ -96,16 +106,17 @@ static void nonce_of(unsigned char out[PURE_AEAD_NONCE], const unsigned char bas
for (int i = 0; i < 8; ++i) out[4 + i] ^= (unsigned char)(pn >> (56 - 8 * i));
}
-/* A packet: the header, then body sealed; its size, or 0. */
-static size_t seal_packet(PureAead *aead, const unsigned char base[PURE_AEAD_NONCE], uint32_t id, uint64_t run,
- uint64_t pn, const unsigned char *body, size_t size, unsigned char *out) {
+/* A packet: the header, then body sealed (with key, or the context's own
+ * when NULL); its size, or 0. */
+static size_t seal_packet(PureAead *aead, const unsigned char *key, const unsigned char base[PURE_AEAD_NONCE], uint32_t id,
+ uint64_t run, uint64_t pn, const unsigned char *body, size_t size, unsigned char *out) {
unsigned char nonce[PURE_AEAD_NONCE];
out[0] = VERSION;
put32(out + 1, id);
put64(out + 5, run);
put64(out + 13, pn);
nonce_of(nonce, base, pn);
- return pure_aead_seal(aead, nonce, out, HEADER, body, size, out + HEADER) ? HEADER + size + PURE_AEAD_TAG : 0;
+ return pure_aead_seal(aead, key, nonce, out, HEADER, body, size, out + HEADER) ? HEADER + size + PURE_AEAD_TAG : 0;
}
static size_t put_names(unsigned char *p, const char *source, const char *input) {
@@ -437,14 +448,14 @@ static void take_answers(PureLink *l, uint64_t now) {
uint64_t run = get64(packet + 5), pn = get64(packet + 13);
if (!l->in || l->in_run != run) {
pure_aead_free(l->in);
- l->in = derive(l->secret, l->peer, l->own_public, run, l->run, l->in_base);
+ l->in = aead_of(l->secret, l->peer, l->own_public, run, l->run, l->in_base);
l->in_run = run;
if (!l->in) continue;
}
unsigned char nonce[PURE_AEAD_NONCE];
nonce_of(nonce, l->in_base, pn);
size_t size = (size_t)n - HEADER - PURE_AEAD_TAG;
- if (!pure_aead_open(l->in, nonce, packet, HEADER, packet + HEADER, (size_t)n - HEADER, plain)) continue;
+ if (!pure_aead_open(l->in, NULL, nonce, packet, HEADER, packet + HEADER, (size_t)n - HEADER, plain)) continue;
++l->counts.received;
for (size_t at = 0; at < size;) {
unsigned type = plain[at++];
@@ -503,7 +514,7 @@ static size_t fill(PureLink *l, unsigned char *body, Flight *f) {
* refuses it (what it carried is then marked unsent again). */
static bool transmit(PureLink *l, Flight *f, const unsigned char *body, size_t size, uint64_t now) {
unsigned char packet[DATAGRAM];
- size_t total = seal_packet(l->out, l->out_base, l->own_id, l->run, f->pn, body, size, packet);
+ size_t total = seal_packet(l->out, NULL, l->out_base, l->own_id, l->run, f->pn, body, size, packet);
++l->next_pn;
bool sent = total && (send(l->fd, packet, total, 0) >= 0 || (errno != EAGAIN && errno != EWOULDBLOCK &&
errno != ENOBUFS && errno != EINTR));
@@ -657,7 +668,7 @@ bool pure_link_start(PureLink *l, void (*notify)(void *), void *context, char *e
l->threshold = UINT64_MAX;
l->credit = CREDIT;
ok = ok && pure_link_secret(l->own, l->peer, l->secret) &&
- (l->out = derive(l->secret, l->own_public, l->peer, l->run, 0, l->out_base)) &&
+ (l->out = aead_of(l->secret, l->own_public, l->peer, l->run, 0, l->out_base)) &&
(l->wake = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)) >= 0;
l->notify = notify;
l->context = context;
@@ -716,10 +727,9 @@ typedef struct {
Active *active;
uint64_t run, seen; /* the sender's run; when it last sent */
bool used, ack_due, due;
- PureAead *in, *out;
- unsigned char in_base[PURE_AEAD_NONCE], out_base[PURE_AEAD_NONCE];
+ unsigned char in_key[PURE_AEAD_KEY], out_key[PURE_AEAD_KEY], in_base[PURE_AEAD_NONCE], out_base[PURE_AEAD_NONCE];
uint64_t next_pn, largest_at;
- struct sockaddr_storage address;
+ struct sockaddr_in6 address; /* or an IPv4 one */
socklen_t address_size;
Range got[RANGES]; /* the numbers received, newest first */
unsigned got_count;
@@ -760,8 +770,10 @@ typedef struct { uint32_t name, next; } Allowed; /* name: where in names (u8 len
typedef struct { Stream *stream; uint64_t heard; bool stored, gap; } Done;
/* A peer quiet this long lets its active state go; the active are looked at
- * that often. */
-static const uint64_t IDLE_FIRST = 30000 * MS, SWEEP_EVERY = 250 * MS;
+ * that often; what they held goes back to the system once TRIM_AFTER have
+ * gone, or TRIM_WAIT after any went. */
+static const uint64_t IDLE_FIRST = 30000 * MS, SWEEP_EVERY = 250 * MS, TRIM_WAIT = 10000 * MS;
+enum { TRIM_AFTER = 1024 };
struct PureLinkListener {
const PureModule *module;
@@ -769,7 +781,8 @@ struct PureLinkListener {
unsigned char own_public[PURE_SEAL_KEY];
uint32_t own_id;
unsigned port;
- uint64_t run, idle, swept;
+ uint64_t run, idle, swept, trimmed, untrimmed;
+ PureAead *aead; /* keyed by each packet's run */
int fd, wake;
pthread_t thread;
bool started;
@@ -931,10 +944,6 @@ static Active *activate(PureLinkListener *s, Peer *peer, uint64_t now) {
}
static void let_go(PureLinkListener *s, Active *a) {
- for (unsigned i = 0; i < RUNS; ++i) {
- pure_aead_free(a->runs[i].in);
- pure_aead_free(a->runs[i].out);
- }
for (unsigned k = 0; k < a->stream_count; ++k) {
while (a->streams[k]->held_count) drop_held(a->streams[k], 0);
free(a->streams[k]->held);
@@ -944,7 +953,7 @@ static void let_go(PureLinkListener *s, Active *a) {
s->peers[a->peer].active = NULL;
s->actives[a->place] = s->actives[--s->active_count];
s->actives[a->place]->place = a->place;
- explicit_bzero(a->secret, sizeof(a->secret));
+ explicit_bzero(a, sizeof(*a));
free(a);
}
@@ -958,7 +967,7 @@ static bool busy(const Active *a) {
}
/* Let go the active state of peers quiet for the idle period; what idle
- * links held goes back to the system when there was much of it. */
+ * links held goes back to the system. */
static void sweep(PureLinkListener *s, uint64_t now) {
if (now - s->swept < SWEEP_EVERY) return;
s->swept = now;
@@ -969,7 +978,12 @@ static void sweep(PureLinkListener *s, uint64_t now) {
else let_go(s, a), ++freed;
}
s->counts.swept += freed;
- if (freed >= 1024) malloc_trim(0);
+ s->untrimmed += freed;
+ if (s->untrimmed >= TRIM_AFTER || (s->untrimmed && now - s->trimmed >= TRIM_WAIT)) {
+ malloc_trim(0);
+ s->untrimmed = 0;
+ s->trimmed = now;
+ }
}
static void mark_ready(PureLinkListener *s, Stream *st) {
@@ -1002,8 +1016,6 @@ static Run *install_run(Active *a, const Run *made) {
Run *r = &a->runs[i];
if (!r->used || (slot->used && r->seen < slot->seen)) slot = r;
}
- pure_aead_free(slot->in);
- pure_aead_free(slot->out);
bool due = slot->due; /* the answer list may hold the slot */
*slot = *made;
slot->due = due;
@@ -1150,17 +1162,14 @@ static bool take_from(PureLinkListener *s, Peer *peer, unsigned char *packet, si
bool woke = !a;
if (woke && !(a = activate(s, peer, now))) return false;
Run made = {.active = a, .run = run, .seen = now, .used = true};
- if (!r) {
- made.in = derive(a->secret, peer->key, s->own_public, run, 0, made.in_base);
- made.out = derive(a->secret, s->own_public, peer->key, s->run, run, made.out_base);
- }
+ bool keyed = r || (derive(a->secret, peer->key, s->own_public, run, 0, made.in_key, made.in_base) &&
+ derive(a->secret, s->own_public, peer->key, s->run, run, made.out_key, made.out_base));
unsigned char plain[DATAGRAM], nonce[PURE_AEAD_NONCE];
nonce_of(nonce, r ? r->in_base : made.in_base, pn);
size_t size = n - HEADER - PURE_AEAD_TAG;
- PureAead *in = r ? r->in : made.in;
- if (!in || (!r && !made.out) || !pure_aead_open(in, nonce, packet, HEADER, packet + HEADER, n - HEADER, plain)) {
- pure_aead_free(made.in);
- pure_aead_free(made.out);
+ if (!keyed || !pure_aead_open(s->aead, r ? r->in_key : made.in_key, nonce, packet, HEADER, packet + HEADER,
+ n - HEADER, plain)) {
+ explicit_bzero(&made, sizeof(made));
if (woke) let_go(s, a);
return false;
}
@@ -1168,8 +1177,8 @@ static bool take_from(PureLinkListener *s, Peer *peer, unsigned char *packet, si
if (!r) r = install_run(a, &made);
a->seen = r->seen = now;
note(r, pn, now);
- memcpy(&r->address, from, from_size); /* where it is now: answers go there */
- r->address_size = from_size;
+ r->address_size = from_size <= sizeof(r->address) ? from_size : sizeof(r->address);
+ memcpy(&r->address, from, r->address_size); /* where it is now: answers go there */
++s->counts.received;
Stream *st = NULL;
bool eliciting = false;
@@ -1267,7 +1276,7 @@ static void answer(PureLinkListener *s, uint64_t now) {
}
r->ack_due = false;
if (!at) continue;
- size_t total = seal_packet(r->out, r->out_base, s->own_id, s->run, r->next_pn++, body, at, packet);
+ size_t total = seal_packet(s->aead, r->out_key, r->out_base, s->own_id, s->run, r->next_pn++, body, at, packet);
if (total && sendto(s->fd, packet, total, 0, (const struct sockaddr *)&r->address, r->address_size) >= 0)
++s->counts.packets;
}
@@ -1360,9 +1369,10 @@ bool pure_link_serve(PureLinkListener *s, char *error, size_t size) {
setsockopt(s->fd, SOL_SOCKET, SO_RCVBUF, &buffer, sizeof(buffer));
setsockopt(s->fd, SOL_SOCKET, SO_SNDBUF, &buffer, sizeof(buffer));
s->run = random64();
- s->swept = now_ns();
+ s->swept = s->trimmed = now_ns();
s->wake = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
- if (s->wake < 0 || pthread_create(&s->thread, NULL, run_listener, s)) {
+ unsigned char key[PURE_AEAD_KEY] = {0}; /* each packet brings its run's */
+ if (s->wake < 0 || !(s->aead = pure_aead(key)) || pthread_create(&s->thread, NULL, run_listener, s)) {
snprintf(error, size, "--link-port %u: cannot start", s->port);
return false;
}
@@ -1398,6 +1408,7 @@ void pure_link_listener_close(PureLinkListener *s, PureLinkCounts *counts) {
counts->active = s->active_count;
}
while (s->active_count) let_go(s, s->actives[0]);
+ pure_aead_free(s->aead);
free(s->actives);
free(s->peers);
free(s->index);
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