Skip to content

feat: add the Noise_IKpsk2_25519_AESGCM_BLAKE2s cipher suite - #250

Draft
thomaseizinger wants to merge 8 commits into
masterfrom
noise-aesgcm-cipher-suite
Draft

thomaseizinger wants to merge 8 commits into
masterfrom
noise-aesgcm-cipher-suite

Conversation

@thomaseizinger

@thomaseizinger thomaseizinger commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Adds a second Noise cipher suite, Noise_IKpsk2_25519_AESGCM_BLAKE2s, next to WireGuard's Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s. The suite is chosen per Tunn and defaults to ChaChaPoly, so existing users are unaffected.

The AESGCM suite derives its initial chaining key from its own protocol name and uses AES-256-GCM, with the Noise spec's big-endian nonce encoding, for both the handshake and transport data. Peers with mismatched suites therefore fail at the handshake rather than on the first data packet. MAC1, MAC2 and cookies are WireGuard-specific and stay unchanged.

AES-GCM has much tighter per-key usage limits than ChaCha20-Poly1305, so sessions of that suite rekey after 2^27 messages and refuse to encrypt past 2^28, following draft-irtf-cfrg-aead-limits. A helper reports whether the CPU runs AES-GCM in hardware, so callers only negotiate the suite where it is actually faster. On AES-NI hardware, Firezone's iperf3 benchmarks showed 25 to 30% more TCP throughput over direct connections.

Related: firezone/firezone#15505

On CPUs with hardware AES-GCM, AES-256-GCM is considerably faster than ChaCha20-Poly1305. `Tunn::set_cipher_suite` lets both peers opt into the AESGCM variant of WireGuard's Noise protocol, per peer. The default stays standard WireGuard.

The suite follows the Noise spec: the handshake is seeded from its own protocol name, so peers with mismatched suites fail at the handshake. Handshake messages and transport data are both sealed with AES-256-GCM, using the big-endian nonce encoding the spec mandates for AESGCM. WireGuard's prologue, MACs and cookies are unchanged.

AES-GCM's security degrades with the amount of data encrypted under one key. Following draft-irtf-cfrg-aead-limits, an AESGCM session schedules a new handshake after 2^27 messages and refuses to encrypt after 2^28, keeping the confidentiality advantage below 2^-57 for packets of up to 2 KiB.

`parse_handshake_anon` accepts initiations of either suite, so a peer can still be looked up by its static key before its suite is known.

The handshake and transport are checked for interoperability against `snow` for both suites.
A `Tunn`'s cipher suite must never change over its lifetime, so it is fixed at construction instead of being set afterwards. The deprecated `Tunn::new` uses the default suite.
Comment thread boringtun/src/noise/cipher_suite.rs Fixed
/// The Noise spec (section 12) prefixes the counter with 32 zero bits and encodes it
/// little-endian for ChaChaPoly but big-endian for AESGCM.
pub(crate) fn nonce(self, counter: u64) -> [u8; 12] {
let mut nonce = [0u8; 12];
…col name

Precomputed byte arrays obscure where the values come from. Deriving them from the protocol name and WireGuard's identifier makes the construction readable, and caching them once per suite keeps handshakes from rehashing.
The AESGCM suite is not WireGuard, so it should not identify itself as
WireGuard in its handshake transcript. The ChaChaPoly suite keeps
WireGuard's identifier and stays byte-for-byte compatible.
The message limits are a property of the session, so test them on a
`Session` directly instead of establishing a `Tunn` pair.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants