feat(wire): E2E PAKE handshake with X25519 ECDH + AES-256-GCM - #103
Merged
Conversation
Adds forward-secret encrypted messaging between node and plugin:
- New e2e.go: X25519 keygen, ECDH, HKDF-SHA256 key derivation,
HMAC-SHA256 mutual auth proofs, AES-256-GCM encrypt/decrypt
- Handshake: hello(ecdh_pub) → hello_ack(ecdh_pub+salt) →
auth(proof, no token on wire) → auth_ok(server proof)
- Session key derived from ECDH shared secret + pairing token
(token never transmitted after initial pairing)
- Encrypted envelop: {type: enc, data: base64url(IV||ct||tag)}
- Dispatcher delegates to Client.WriteE2E/ReadE2E
- Backward compatible: legacy plaintext auth when server lacks ECDH
Signed-off-by: Blasius Patrick <blasius.patrick@gmail.com>
Add a full End-to-End Encryption section covering the handshake flow, security properties (forward secrecy, MITM resistance, token never on wire), encrypted vs plaintext message types, and backward compatibility. Update Architecture and Security sections to reference E2E encryption. Signed-off-by: Blasius Patrick <blasius.patrick@gmail.com>
blaspat
added a commit
that referenced
this pull request
Aug 4, 2026
The E2E refactor in #103 replaced dispatch.ReadOne's 90s deadline (DefaultPongTimeout + 30s) with readE2E's hardcoded 10s ReadMessage deadline. The server sends pings every ~30s, so connections died before the first ping. Add readTimeout/writeTimeout fields to Client (90s/10s defaults, matching the pre-E2E dispatch values) and wire them into readE2E and writeE2E. Signed-off-by: Blasius Patrick <blasius.patrick@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds forward-secret end-to-end encryption between the Go node client and the Python plugin server. The pairing token is never transmitted on the wire after initial pairing — only HMAC proofs are exchanged during the auth handshake.
Changes
internal/wire/e2e.go(new) — X25519 keygen, ECDH, HKDF-SHA256 key derivation, HMAC mutual auth proofs, AES-256-GCM encrypt/decryptinternal/wire/messages.go— AddE2E,ECDHPub,Proof,Saltfields to handshake message structs; addEncwire typeinternal/wire/client.go— E2E handshake inDial: ECDH exchange inhello/hello_ack, proof verification inauth/auth_ok, session key derivation.WriteE2E/ReadE2Ewrappers for all post-handshake messagesinternal/wire/dispatch.go— Delegate toWriteE2E/ReadE2Eafter handshake; legacy plaintext fallback for servers without E2EREADME.md— Document E2E encryption section with handshake flow, security properties, and backward compatibility.gitignore— Ignore built binaryHandshake
Security properties
authcarries only HMAC proofBackward compatibility
Client sends
e2e: trueinhello. Server without E2E support omitsecdh_pub→ client falls back to legacy plaintext auth.Closes #58