feat: implement YAW/2.1 forward-secret signaling
Upgrades the signaling layer from static X25519 (2.0) to per-session ephemeral X25519 (2.1). Recorded signaling traffic cannot be decrypted even if long-term Ed25519 keys later leak, because esk is zeroed on session close. Protocol: - Each peer generates a fresh X25519 keypair (esk/epk) per session. - Peers exchange signed `ekey` messages sealed under static keys before the offer/answer. Offer/answer/candidate payloads are then sealed with ephemeral keys (crypto_box(·, peer_epk, my_esk)). - ekey sig binds both peer IDs and the epk to prevent replay to third parties. - Offerer waits up to 2 s for the peer's ekey; if none arrives it falls back to YAW/2.0 static-key sealing and logs "2.0 fallback offer". - 2.0 peers silently ignore the unknown `ekey` kind — full interop preserved. Implementation: - crypto.go: add EphemeralKey.PublicRaw/PrivateRaw/Wipe helpers. - proto.go: add SigEkey kind; EPK/V/EkeySig fields on SignalingPayload. - anchor/client.go: replace flat pcs map with peerSession struct tracking ephemeral keys, peerEPK, and fs flag; openBoxAuto tries ephemeral then static; sealAndSend chooses seal based on session state. - test-network.sh: pipe daemon stderr through tee to daemon.log; add YAW/2.1 FS verification section. - test-tui.sh: same daemon.log capture. - README.md: document 2.1 forward secrecy, file transfer IPC, updated roadmap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -159,15 +159,21 @@ const (
|
||||
SigAnswer SignalingKind = "answer"
|
||||
SigCandidate SignalingKind = "candidate"
|
||||
SigBye SignalingKind = "bye"
|
||||
SigEkey SignalingKind = "ekey" // YAW/2.1: ephemeral key exchange
|
||||
)
|
||||
|
||||
// SignalingPayload is the JSON plaintext sealed inside a crypto_box (YAW/2 §5).
|
||||
// SignalingPayload is the JSON plaintext sealed inside a crypto_box (YAW/2 §5 / §5.4′).
|
||||
type SignalingPayload struct {
|
||||
Kind SignalingKind `json:"kind"`
|
||||
SDP string `json:"sdp,omitempty"` // offer / answer
|
||||
Cand string `json:"cand,omitempty"` // trickle ICE candidate line
|
||||
Mid string `json:"mid,omitempty"` // media stream id for candidate
|
||||
MLine int `json:"mline,omitempty"` // media line index
|
||||
|
||||
// YAW/2.1 ekey fields (sealed under static keys)
|
||||
V string `json:"v,omitempty"` // "yaw/2.1"
|
||||
EPK string `json:"epk,omitempty"` // hex-encoded ephemeral X25519 pubkey (32 bytes)
|
||||
EkeySig string `json:"ekey_sig,omitempty"` // hex Ed25519 sig over ekey bind bytes
|
||||
}
|
||||
|
||||
// ── Anchor WebSocket wire types (YAW/2 §5) ────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user