3.3 KiB
streaming-aead-xchacha20
(no submodules)
Purpose
streaming-aead-xchacha20.ts is the XChaCha20-Poly1305 adapter that satisfies the StreamingAeadEngine contract used by encryptStreamAead / decryptStreamAead. XChaCha20-Poly1305 is preferred over AES-GCM when the deployment runs without hardware AES acceleration or when the 24-byte extended nonce makes random-nonce schemes safer (the 2^96 random-nonce birthday-bound is comfortable, where AES-GCM's 2^48 is not).
The engine declares a 20-byte caller-supplied base nonce; the per-chunk 24-byte nonce is baseNonce ‖ counter_be32. The high bit of the 32-bit counter carries the final-flag so terminator and data chunks at the same counter index produce different nonces. This is the default streaming engine — callers who do not pass engine: to encryptStreamAead / decryptStreamAead get this one.
Features
- Implements the
StreamingAeadEnginecontract — drop-in for the streaming generators. - 20-byte base nonce / 24-byte per-chunk nonce / 16-byte AEAD tag.
- Counter-discipline guard: rejects negative or
> 2^32 - 1counters withSTREAM_OUT_OF_ORDER. - Base-nonce length guard: rejects any base nonce whose length is not exactly 20 bytes with
STREAM_INVALID_NONCE_BASE. - Tag-mismatch promotion: open-side tag failures route to
STREAM_TAG_MISMATCH(with the originalDECRYPT_FAILEDas cause) so streaming callers see the streaming-shaped error.
Usage: Basic Example
import { xchacha20StreamingEngine } from "@suaveplan/crypto-cipher/streaming/streaming-aead-xchacha20";
import { encryptStreamAead } from "@suaveplan/crypto-cipher/streaming/streaming-aead";
const key = crypto.getRandomValues(new Uint8Array(32));
// xchacha20StreamingEngine is the default — passing it explicitly is optional.
for await (const chunk of encryptStreamAead(key, source(), {
engine: xchacha20StreamingEngine,
})) {
sink.write(chunk);
}
Usage: Advanced Example
import { xchacha20StreamingEngine } from "@suaveplan/crypto-cipher/streaming/streaming-aead-xchacha20";
// Use the engine directly without the framing layer to embed XChaCha20-Poly1305
// into a custom transport. The 20-byte base nonce gives plenty of headroom for
// random nonces if the caller derives one per-stream rather than per-chunk.
const baseNonce = crypto.getRandomValues(new Uint8Array(20));
const ct = await xchacha20StreamingEngine.seal({
key,
baseNonce,
counter: 0,
finalFlag: 0,
data: plaintext,
aad: contextBytes,
});
API Reference
xchacha20StreamingEngine: StreamingAeadEngine— frozen engine instance.BASE_NONCE_LENGTH: 20NONCE_LENGTH: 24TAG_LENGTH: 16
Errors: STREAM_INVALID_NONCE_BASE, STREAM_OUT_OF_ORDER, STREAM_TAG_MISMATCH.
Implementation Notes
XChaCha20-Poly1305 (libsodium specification, RFC draft) extends the ChaCha20 nonce from 12 to 24 bytes via HChaCha20 sub-key derivation. The 24-byte nonce makes random nonces safe (2^96 random nonces have a ~10^-19 collision probability), which is the basis for the streaming layer using a random base nonce plus a counter. Counter-overflow at 2^32 chunks short-circuits before reuse can occur. This adapter does not generate the base nonce — the streaming generator supplies it (random by default; deterministic via the baseNonce option for tests).