Documentation
¶
Index ¶
- Constants
- func ComputeFingerprintFromBase64Keys(pubKeys map[string]string) (string, error)
- func CreateRekeyRequest(ownKeys *kbc.OwnKeys, peerKeys *kbc.PeerKeys, epoch uint64, ...) (*bindings.RekeyRequest, []byte, error)
- func DialWithStableAddr(network, addr string, timeout time.Duration, logger *slog.Logger) (net.Conn, error)
- func ExchangePublicKeysLocal(session *Session, conn net.Conn, isInitiator bool) error
- func FinalizeInboundSession(session *Session, conn net.Conn, encSeeds map[string]string) error
- func PerformInboundHandshake(session *Session, conn net.Conn) error
- func PerformOutboundHandshake(session *Session, remoteAddr string) error
- func PerformOutboundHandshakeOnConn(session *Session, conn net.Conn) error
- func ProcessRekeyRequest(req *bindings.RekeyRequest, ownKeys *kbc.OwnKeys, peerKeys *kbc.PeerKeys, ...) (*bindings.RekeyResponse, []byte, error)
- func ProcessRekeyResponse(resp *bindings.RekeyResponse, ownKeys *kbc.OwnKeys, peerKeys *kbc.PeerKeys, ...) ([]byte, error)
- func StartListener(session *Session, port int) error
- type ConnectionHealth
- type HealthMonitor
- type PeerHandshakeMessage
- type ReconnectManager
- type ReconnectState
- type SecureConn
- func (s *SecureConn) Accept() (net.Conn, error)
- func (l *SecureConn) Addr() net.Addr
- func (s *SecureConn) Close() error
- func (s *SecureConn) GetEpoch() uint64
- func (s *SecureConn) GetStats() (bytesSent, bytesRecv, msgsSent, msgsRecv uint64)
- func (s *SecureConn) LocalAddr() net.Addr
- func (s *SecureConn) Read(p []byte) (int, error)
- func (s *SecureConn) ReadMessage() ([]byte, error)
- func (s *SecureConn) RemoteAddr() net.Addr
- func (s *SecureConn) ResetStats()
- func (s *SecureConn) SetDeadline(t time.Time) error
- func (s *SecureConn) SetReadDeadline(t time.Time) error
- func (s *SecureConn) SetWriteDeadline(t time.Time) error
- func (s *SecureConn) ShouldRekey() bool
- func (s *SecureConn) UpdateKey(newKek []byte)
- func (s *SecureConn) Write(p []byte) (int, error)
- func (s *SecureConn) WriteMessage(msg []byte) error
- type SecureReader
- type SecureWriter
- type Session
- func InitSession(logger *slog.Logger, defaultOutboundPort int, defaultInboundPort int) (*Session, error)
- func InitSessionWithKeys(logger *slog.Logger, keys *kbc.OwnKeys, defaultOutboundPort int, ...) (*Session, error)
- func NewSession(logger *slog.Logger, expectedFingerprint string, timeout time.Duration) *Session
- func (s *Session) GetFingerPrint() string
- func (s *Session) GetRekeyEpoch() uint64
- func (s *Session) HandleRekeyRequest(req *bindings.RekeyRequest) (*bindings.RekeyResponse, error)
- func (s *Session) HandleRekeyResponse(resp *bindings.RekeyResponse) error
- func (s *Session) IsExpired() bool
- func (s *Session) IsVerified() bool
- func (s *Session) MarkError(err error)
- func (s *Session) ReadyForEncryption() bool
- func (s *Session) ShouldRekey() bool
- func (s *Session) Transition(next SessionState) error
- func (s *Session) ValidateExpired()
- func (s *Session) ValidatePeer() error
- func (s *Session) ValidateReady() error
- type SessionSockets
- type SessionState
Constants ¶
const ( RekeyBytesThreshold = 1 << 30 // 1 GB RekeyMsgsThreshold = 1 << 20 // ~1M messages )
Re-keying thresholds for forward secrecy.
const ( NoncePrefixOutbound uint32 = 0x4F555442 // "OUTB" NoncePrefixInbound uint32 = 0x494E4244 // "INBD" )
Nonce prefixes for direction separation (prevents nonce reuse with same key).
Variables ¶
This section is empty.
Functions ¶
func CreateRekeyRequest ¶
func CreateRekeyRequest(ownKeys *kbc.OwnKeys, peerKeys *kbc.PeerKeys, epoch uint64, suite kbc.CipherSuite) (*bindings.RekeyRequest, []byte, error)
CreateRekeyRequest generates a RekeyRequest with new encapsulated seeds. Returns the request, the derived new key (for outbound), and any error.
func DialWithStableAddr ¶
func DialWithStableAddr(network, addr string, timeout time.Duration, logger *slog.Logger) (net.Conn, error)
dialWithStableAddr dials a remote address using a net.Dialer that binds to the machine's stable (non-temporary) IPv6 address. This prevents connections from breaking when macOS/Linux deprecates temporary privacy addresses (RFC 4941).
func ExchangePublicKeysLocal ¶
ExchangePublicKeysLocal performs a plaintext exchange of public keys over conn. In local mode, the relay is skipped, so both peers need each other's keys before the PQC handshake can run. The initiator (joiner) sends first, responder second.
func FinalizeInboundSession ¶
FinalizeInboundSession completes the inbound session setup after peer is verified. It decapsulates seeds, derives the SEKInbound, wraps the net.Conn in SecureConn, and finalizes state.
func PerformInboundHandshake ¶
PerformInboundHandshake handles the first plaintext connection from Bob to Alice.
func PerformOutboundHandshake ¶
PerformOutboundHandshake dials remoteAddr and sends the PQC handshake.
func PerformOutboundHandshakeOnConn ¶
PerformOutboundHandshakeOnConn sends the PQC handshake on an existing connection. Used by bridge mode where the connection is pre-established (with room token already sent).
func ProcessRekeyRequest ¶
func ProcessRekeyRequest(req *bindings.RekeyRequest, ownKeys *kbc.OwnKeys, peerKeys *kbc.PeerKeys, suite kbc.CipherSuite) (*bindings.RekeyResponse, []byte, error)
ProcessRekeyRequest handles an incoming RekeyRequest. Returns a RekeyResponse, the derived new inbound key, and any error.
func ProcessRekeyResponse ¶
func ProcessRekeyResponse(resp *bindings.RekeyResponse, ownKeys *kbc.OwnKeys, peerKeys *kbc.PeerKeys, suite kbc.CipherSuite) ([]byte, error)
ProcessRekeyResponse handles an incoming RekeyResponse. Returns the derived new outbound key (peer's response seeds).
func StartListener ¶
StartListener starts a TCP listener on the given port and waits for Bob. It will block until Bob connects and sends valid keys that match the expected fingerprint.
Types ¶
type ConnectionHealth ¶
type ConnectionHealth int32
ConnectionHealth represents the health state of the P2P connection.
const ( HealthUnknown ConnectionHealth = iota HealthHealthy // All heartbeats succeeding HealthDegraded // High latency or some failures HealthDisconnected // Connection lost, needs reconnection )
func (ConnectionHealth) String ¶
func (h ConnectionHealth) String() string
String returns a human-readable representation of the health state.
type HealthMonitor ¶
type HealthMonitor struct {
// Configuration
Interval time.Duration // heartbeat interval (default 5s)
Timeout time.Duration // per-heartbeat timeout (default 3s)
DegradedRTT time.Duration // RTT above this = degraded (default 500ms)
MaxFailures int // failures before disconnect (default 3)
// Callbacks
OnHealthChange func(old, new ConnectionHealth)
OnDisconnect func()
// contains filtered or unexported fields
}
HealthMonitor monitors the health of a P2P connection via periodic heartbeats. When enough consecutive heartbeats fail, it triggers the OnDisconnect callback.
func NewHealthMonitor ¶
func NewHealthMonitor(session *Session, client bindings.KeibiServiceClient, logger *slog.Logger) *HealthMonitor
NewHealthMonitor creates a new health monitor with default settings.
func (*HealthMonitor) AvgRTT ¶
func (m *HealthMonitor) AvgRTT() time.Duration
AvgRTT returns the exponential moving average of RTT.
func (*HealthMonitor) Health ¶
func (m *HealthMonitor) Health() ConnectionHealth
Health returns the current connection health state.
func (*HealthMonitor) LastRTT ¶
func (m *HealthMonitor) LastRTT() time.Duration
LastRTT returns the most recent round-trip time in nanoseconds.
func (*HealthMonitor) Start ¶
func (m *HealthMonitor) Start()
Start begins the heartbeat monitoring loop in a goroutine.
func (*HealthMonitor) Stop ¶
func (m *HealthMonitor) Stop()
Stop halts the health monitoring loop and waits for it to exit.
type PeerHandshakeMessage ¶
type PeerHandshakeMessage struct {
Fingerprint string `json:"fingerprint"`
PublicKeys map[string]string `json:"public_keys"` // base64 encoded
EncSeeds map[string]string `json:"enc_seeds"` // optional for key encapsulation
OutboundPort int `json:"port"`
SupportedCiphers []string `json:"supported_ciphers"` // cipher negotiation
Persistent bool `json:"persistent,omitempty"`
}
PeerHandshakeMessage defines the JSON payload sent during handshake.
type ReconnectManager ¶
type ReconnectManager struct {
// Configuration
Backoff []time.Duration // Exponential backoff delays
MaxAttempts int // Maximum reconnection attempts
// Connection details (cached from last successful connection)
CachedPeerIP string
CachedPeerPort int
// Bridge relay (for firewall traversal). If set, reconnect uses bridge instead of direct.
BridgeAddr string
DialBridge func() (net.Conn, error) // Dial bridge with room token
// Callbacks
OnReconnecting func() // Called when reconnection starts
OnReconnected func() // Called on successful reconnection
OnGaveUp func() // Called when all attempts exhausted
RelayRefresh func() error // Re-register with relay
RelayLookup func(fingerprint string) (ip string, port int, err error) // Lookup peer in relay
AcceptConn func(timeout time.Duration) (net.Conn, error) // Accept incoming connection
// contains filtered or unexported fields
}
ReconnectManager handles automatic reconnection when the P2P connection drops. It coordinates with the health monitor and uses a deterministic initiator selection to avoid race conditions.
func NewReconnectManager ¶
func NewReconnectManager(session *Session, logger *slog.Logger) *ReconnectManager
NewReconnectManager creates a new reconnection manager with default settings.
func (*ReconnectManager) Attempts ¶
func (r *ReconnectManager) Attempts() int
Attempts returns the number of reconnection attempts made.
func (*ReconnectManager) IsReconnectInitiator ¶
func (r *ReconnectManager) IsReconnectInitiator() bool
IsReconnectInitiator determines which peer should initiate reconnection. The peer with the lexicographically lower fingerprint is the initiator. This avoids race conditions where both peers try to connect simultaneously.
func (*ReconnectManager) OnDisconnect ¶
func (r *ReconnectManager) OnDisconnect()
OnDisconnect is called when the health monitor detects a connection loss. It starts the reconnection loop in a goroutine.
func (*ReconnectManager) Reset ¶
func (r *ReconnectManager) Reset()
Reset resets the manager to connected state (call after manual session restart).
func (*ReconnectManager) State ¶
func (r *ReconnectManager) State() ReconnectState
State returns the current reconnection state.
func (*ReconnectManager) Stop ¶
func (r *ReconnectManager) Stop()
Stop halts any ongoing reconnection attempts and prevents new ones.
type ReconnectState ¶
type ReconnectState int32
ReconnectState represents the current state of the reconnection manager.
const ( ReconnectStateConnected ReconnectState = iota // Connection is healthy ReconnectStateReconnecting // Actively trying to reconnect ReconnectStateWaitingPeer // Waiting for peer to come online ReconnectStateGaveUp // Exhausted all retry attempts )
func (ReconnectState) String ¶
func (s ReconnectState) String() string
String returns a human-readable representation of the reconnect state.
type SecureConn ¶
type SecureConn struct {
// contains filtered or unexported fields
}
SecureConn wraps a net.Conn with separate inbound/outbound encryption.
func NewSecureConn ¶
func NewSecureConn(conn net.Conn, kek []byte, suite kbc.CipherSuite) *SecureConn
func (*SecureConn) Addr ¶
func (l *SecureConn) Addr() net.Addr
func (*SecureConn) Close ¶
func (s *SecureConn) Close() error
Close closes the underlying connection.
func (*SecureConn) GetEpoch ¶
func (s *SecureConn) GetEpoch() uint64
GetEpoch returns the current key epoch.
func (*SecureConn) GetStats ¶
func (s *SecureConn) GetStats() (bytesSent, bytesRecv, msgsSent, msgsRecv uint64)
GetStats returns current byte/message counts for monitoring.
func (*SecureConn) LocalAddr ¶
func (s *SecureConn) LocalAddr() net.Addr
LocalAddr returns the local network address.
func (*SecureConn) ReadMessage ¶
func (s *SecureConn) ReadMessage() ([]byte, error)
ReadMessage reads and decrypts a full message.
func (*SecureConn) RemoteAddr ¶
func (s *SecureConn) RemoteAddr() net.Addr
RemoteAddr returns the remote network address.
func (*SecureConn) ResetStats ¶
func (s *SecureConn) ResetStats()
ResetStats resets the byte/message counters after a rekey.
func (*SecureConn) SetDeadline ¶
func (s *SecureConn) SetDeadline(t time.Time) error
func (*SecureConn) SetReadDeadline ¶
func (s *SecureConn) SetReadDeadline(t time.Time) error
func (*SecureConn) SetWriteDeadline ¶
func (s *SecureConn) SetWriteDeadline(t time.Time) error
func (*SecureConn) ShouldRekey ¶
func (s *SecureConn) ShouldRekey() bool
ShouldRekey returns true if key rotation is recommended.
func (*SecureConn) UpdateKey ¶
func (s *SecureConn) UpdateKey(newKek []byte)
UpdateKey atomically updates the encryption key (reuses negotiated cipher suite).
func (*SecureConn) WriteMessage ¶
func (s *SecureConn) WriteMessage(msg []byte) error
WriteMessage encrypts and writes a full message.
type SecureReader ¶
type SecureReader struct {
// contains filtered or unexported fields
}
SecureReader reads encrypted messages and decrypts them. Caches the AEAD cipher and reuses a header buffer.
func NewSecureReader ¶
func NewSecureReader(r io.Reader, kek []byte, suite kbc.CipherSuite) *SecureReader
func (*SecureReader) Read ¶
func (s *SecureReader) Read() ([]byte, error)
type SecureWriter ¶
type SecureWriter struct {
// contains filtered or unexported fields
}
SecureWriter encrypts messages and writes them to an underlying writer. Uses a cached AEAD cipher and single combined write for performance.
func NewSecureWriter ¶
func NewSecureWriter(w io.Writer, kek []byte, suite kbc.CipherSuite) *SecureWriter
func NewSecureWriterWithPrefix ¶
func NewSecureWriterWithPrefix(w io.Writer, kek []byte, suite kbc.CipherSuite, prefix uint32) *SecureWriter
NewSecureWriterWithPrefix creates a writer with a custom nonce prefix.
type Session ¶
type Session struct {
// Known fingerprint of the expected peer, shared out-of-band.
ExpectedPeerFingerprint string
OwnKeys *kbc.OwnKeys
OwnFingerprint string
// Populated after receiving peer keys.
PeerPubKeys *kbc.PeerKeys // "x25519", "mlkem"
// Symmetric session key.
SEKInbound []byte
SEKOutbound []byte
// Negotiated cipher suite for this session.
CipherMu sync.Mutex
CipherSuite kbc.CipherSuite
// Peer-to-peer TCP connections.
Session *SessionSockets
PeerPort int
DefaultOutboundPort int
DefaultInboundPort int
GRPCListener net.Listener
GRPCClient bindings.KeibiServiceClient
// Session state and lifecycle
State SessionState
Established time.Time
Err error
// Persistent identity flags (learned during handshake).
OwnIsPersistent bool
PeerIsPersistent bool
// Internal timeout deadline
Deadline time.Time
// Re-keying state for forward secrecy.
RekeyMu sync.Mutex
LastRekeyAt time.Time
CurrentEpoch uint64
RekeyPending bool
PendingNewKey []byte // awaiting ACK
// contains filtered or unexported fields
}
Session represents the state of a P2P connection between Alice and Bob.
func InitSession ¶
func InitSessionWithKeys ¶ added in v0.2.0
func InitSessionWithKeys(logger *slog.Logger, keys *kbc.OwnKeys, defaultOutboundPort int, defaultInboundPort int) (*Session, error)
InitSessionWithKeys creates a session using pre-existing keys (for persistent identity). Same as InitSession but skips key generation.
func NewSession ¶
NewSession initializes a new session with a timeout deadline.
func (*Session) GetFingerPrint ¶
func (*Session) GetRekeyEpoch ¶
GetRekeyEpoch returns the current key epoch.
func (*Session) HandleRekeyRequest ¶
func (s *Session) HandleRekeyRequest(req *bindings.RekeyRequest) (*bindings.RekeyResponse, error)
HandleRekeyRequest processes an incoming RekeyRequest from peer. Updates inbound key and returns response for peer.
func (*Session) HandleRekeyResponse ¶
func (s *Session) HandleRekeyResponse(resp *bindings.RekeyResponse) error
HandleRekeyResponse processes an incoming RekeyResponse from peer. Updates outbound key after peer acknowledged our rekey request.
func (*Session) IsVerified ¶
IsVerified returns true if the fingerprint matched and session is accepted.
func (*Session) ReadyForEncryption ¶
ReadyForEncryption returns true when both connections and SEKs are set.
func (*Session) ShouldRekey ¶
ShouldRekey returns true if either connection has exceeded the rekey threshold.
func (*Session) Transition ¶
func (s *Session) Transition(next SessionState) error
Transition safely updates the session state, if allowed.
func (*Session) ValidateExpired ¶
func (s *Session) ValidateExpired()
ValidateExpired moves session to 'expired' state if deadline passed.
func (*Session) ValidatePeer ¶
ValidatePeer ensures peer handshake and verification are complete.
func (*Session) ValidateReady ¶
ValidateReady ensures session is fully ready for encryption and data transfer.
type SessionSockets ¶
type SessionSockets struct {
Inbound *SecureConn // Bob -> Alice
Outbound *SecureConn // Alice -> Bob
}
SessionSockets holds a duplex connection for peer communication.
func NewSessionSockets ¶
func NewSessionSockets(connIn, connOut net.Conn, sekIn, sekOut []byte, suite kbc.CipherSuite) *SessionSockets
type SessionState ¶
type SessionState string
const ( SessionInit SessionState = "init" SessionStatePending SessionState = "pending" SessionStateVerified SessionState = "verified" SessionStateConnected SessionState = "connected" SessionStateError SessionState = "error" SessionStateExpired SessionState = "expired" )