-
Notifications
You must be signed in to change notification settings - Fork 0
Cryptography
etr uses well-audited Rust crates for all cryptographic primitives (RustCrypto project). No custom crypto implementations.
| ID | KEM | AEAD | KDF | Notes |
|---|---|---|---|---|
| 1 | ML-KEM-1024 | AES-256-GCM | HKDF-SHA3-256 | Default — post-quantum |
| 2 | ML-KEM-768 | AES-256-GCM | HKDF-SHA-256 | Post-quantum, smaller keys |
| 3 | X25519 | AES-256-GCM | HKDF-SHA-256 | Classical |
| 4 | X25519 | ChaCha20-Poly1305 | HKDF-SHA-256 | Classical |
The client advertises all supported suites in preference order (1 first). The server picks the strongest mutual option. With default builds on both sides, ML-KEM-1024 is always negotiated.
Classical key exchange algorithms like X25519 are vulnerable to a future sufficiently powerful quantum computer via Shor's algorithm. While such computers don't exist today, traffic recorded now could be decrypted later ("harvest now, decrypt later"). ML-KEM (formerly Kyber, standardised as FIPS 203) is a post-quantum KEM that resists quantum attacks.
etr enables PQC by default because there is no meaningful performance cost on modern hardware — ML-KEM is fast. If you need a smaller binary or are targeting constrained environments, build with --no-default-features.
Each session generates a random 32-character passkey sent to the server via the SSH-encrypted bootstrap channel. This provides pre-authentication: only the holder of the passkey can complete the handshake.
Used to encrypt ServerHello before the session key is established:
hello_key = HKDF-SHA-256(ikm=passkey, salt=client_nonce, info="etr-hello-v1")
Derived after KEM exchange. Folds in both the passkey and the KEM shared secret:
session_key = KDF(
ikm = passkey ‖ kem_shared_secret,
salt = client_nonce ‖ server_nonce,
info = "etr-session-v1"
)
KDF is HKDF-SHA3-256 for suite 1, HKDF-SHA-256 for suites 2–4.
The session key provides forward secrecy: a new ephemeral KEM keypair is generated for every connection and every reconnect. Compromising the passkey alone is not enough to decrypt recorded traffic.
Both AES-256-GCM and ChaCha20-Poly1305 use a 12-byte nonce derived from the packet sequence number:
nonce = [0x00, 0x00, 0x00, 0x00] ‖ packet_seq (8 bytes, big-endian)
Sequence numbers are strictly monotonically increasing, guaranteeing nonce uniqueness for the lifetime of a session key. A new session key is derived on every reconnect.
| Primitive | Crate |
|---|---|
| AES-256-GCM | aes-gcm |
| ChaCha20-Poly1305 | chacha20poly1305 |
| X25519 | x25519-dalek |
| ML-KEM-768 / ML-KEM-1024 | ml-kem |
| HKDF | hkdf |
| SHA-256 | sha2 |
| SHA3-256 | sha3 |