Skip to main content

Module sealer

Module sealer 

Source
Expand description

An AEAD that chooses its own nonces.

Every Aead takes a nonce from its caller, and under AES-GCM or ChaCha20-Poly1305 a nonce used twice under one key is catastrophic: GCM leaks its authentication subkey, ChaCha20 XORs the two plaintexts. The rule is easy to state and easy to break, because nothing in seal_detached’s signature tells you that the bytes you pass it are the dangerous ones.

Sealer takes the nonce out of the caller’s hands. It builds each one as SP 800-38D section 8.2.1’s deterministic construction does: a 4-byte fixed field naming the sender, then a 64-bit invocation counter, big-endian. It returns the nonce it used, so the receiver can be sent it. It refuses rather than wrap when the counter runs out.

Opener is the receiving side. It accepts only the sender’s fixed field and only counters it has not passed, so a replayed or reordered message is refused before the AEAD runs.

use ic_cipher::{Aes256Gcm, sealer::{Opener, Sealer}};

// A key for this session only: from a key exchange and a KDF, not a constant.
let key = [0x2a; 32];
let mut tx = Sealer::<Aes256Gcm>::new(&key, *b"c->s")?;
let mut rx = Opener::<Aes256Gcm>::new(&key, *b"c->s")?;

let mut msg = *b"ship it";
let mut tag = [0u8; 16];
let nonce = tx.seal(b"header", &mut msg, &mut tag)?;
rx.open(&nonce, b"header", &mut msg, &tag)?;
assert_eq!(&msg, b"ship it");

// The same message again is a replay, and is refused.
assert!(rx.open(&nonce, b"header", &mut msg, &tag).is_err());

§What the counter cannot know

A counter is unique only within the object that holds it. Two Sealers on the same key and fixed field both start at zero and reuse every nonce, and a process that restarts and builds a new one does the same. So:

  • Use a key that lives no longer than its Sealer: one derived for the session, as TLS 1.3 and HPKE do. A long-lived key needs the counter persisted and restored with Sealer::resume, or a nonce-misuse-resistant AEAD such as AES-256-GCM-SIV.
  • Give every sender under one key its own fixed field, such as one per direction. Better still, give each direction its own key.

The 12-byte nonce is required: it is the length every AEAD here takes and the one SP 800-38D’s construction is defined for.

Structs§

Opener
Opens messages from one Sealer, refusing replays and reordering.
Sealer
Seals messages under nonces it builds itself, each used once.

Constants§

FIXED_LEN
The fixed field’s length.
NONCE_LEN
The nonce length a sealer builds: a 4-byte fixed field and an 8-byte counter.