mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-07-11 17:56:52 -04:00
add custom handshake manager
This commit is contained in:
@ -3,6 +3,7 @@ package ntcp
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
)
|
||||
@ -21,6 +22,23 @@ const (
|
||||
MaxPayloadSize = math.MaxUint16 - 16 /*mac size*/ - uint16Size /*data len*/
|
||||
)
|
||||
|
||||
// Constants for NTCP2 handshake
|
||||
const (
|
||||
// Message 1 - SessionRequest
|
||||
NTCP2_MSG1_SIZE = 64
|
||||
NTCP2_MSG1_HEADER = 0x00
|
||||
|
||||
// Message 2 - SessionCreated
|
||||
NTCP2_MSG2_SIZE = 64
|
||||
NTCP2_MSG2_HEADER = 0x01
|
||||
|
||||
// Message 3 - SessionConfirmed
|
||||
NTCP2_MSG3_HEADER = 0x02
|
||||
|
||||
// Timeout for handshake operations
|
||||
NTCP2_HANDSHAKE_TIMEOUT = 15 * time.Second
|
||||
)
|
||||
|
||||
var ciphers = map[byte]noise.CipherFunc{
|
||||
NOISE_CIPHER_CHACHAPOLY: noise.CipherChaChaPoly,
|
||||
NOISE_CIPHER_AESGCM: noise.CipherAESGCM,
|
||||
|
186
lib/transport/ntcp/handshake.go
Normal file
186
lib/transport/ntcp/handshake.go
Normal file
@ -0,0 +1,186 @@
|
||||
package ntcp
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
"github.com/samber/oops"
|
||||
)
|
||||
|
||||
// HandshakeState maintains the state for an in-progress handshake
|
||||
type HandshakeState struct {
|
||||
// isInitiator indicates whether this side initiated the handshake
|
||||
isInitiator bool
|
||||
// localStaticKey is this router's long-term private key
|
||||
localStaticKey crypto.PrivateKey
|
||||
// remoteStaticKey is the remote router's long-term public key
|
||||
remoteStaticKey crypto.PublicKey
|
||||
// localEphemeral is the temporary private key generated for this handshake
|
||||
localEphemeral crypto.PrivateKey
|
||||
// remoteEphemeral is the temporary public key received from remote party
|
||||
remoteEphemeral crypto.PublicKey
|
||||
// localPaddingLen is the length of padding bytes we send
|
||||
localPaddingLen int
|
||||
// remotePaddingLen is the length of padding bytes we received
|
||||
remotePaddingLen int
|
||||
// chachaKey is the derived ChaCha20 symmetric key for the session
|
||||
chachaKey []byte
|
||||
// sharedSecret is the Diffie-Hellman shared secret computed during handshake
|
||||
sharedSecret []byte
|
||||
// timestamp is the Unix timestamp when handshake was initiated
|
||||
timestamp uint32
|
||||
// routerInfo contains the local router's information
|
||||
routerInfo *router_info.RouterInfo
|
||||
}
|
||||
|
||||
// NewHandshakeState creates a new handshake state for initiating a connection
|
||||
func NewHandshakeState(localKey crypto.PrivateKey, remoteKey crypto.PublicKey, ri *router_info.RouterInfo) (*HandshakeState, error) {
|
||||
hs := &HandshakeState{
|
||||
isInitiator: true,
|
||||
localStaticKey: localKey,
|
||||
remoteStaticKey: remoteKey,
|
||||
routerInfo: ri,
|
||||
timestamp: uint32(time.Now().Unix()),
|
||||
}
|
||||
|
||||
// Generate ephemeral keypair
|
||||
var err error
|
||||
hs.localEphemeral, err = crypto.GenerateX25519KeyPair()
|
||||
if err != nil {
|
||||
return nil, oops.Errorf("failed to generate ephemeral key: %v", err)
|
||||
}
|
||||
|
||||
// Calculate padding length (random 0-15 bytes)
|
||||
paddingBytes := make([]byte, 1)
|
||||
if _, err := rand.Read(paddingBytes); err != nil {
|
||||
return nil, oops.Errorf("failed to generate padding size: %v", err)
|
||||
}
|
||||
hs.localPaddingLen = int(paddingBytes[0] % 16)
|
||||
|
||||
return hs, nil
|
||||
}
|
||||
|
||||
// PerformOutboundHandshake initiates and completes a handshake as the initiator
|
||||
func PerformOutboundHandshake(conn net.Conn, hs *HandshakeState) error {
|
||||
// Set deadline for the entire handshake process
|
||||
if err := conn.SetDeadline(time.Now().Add(NTCP2_HANDSHAKE_TIMEOUT)); err != nil {
|
||||
return oops.Errorf("failed to set deadline: %v", err)
|
||||
}
|
||||
defer conn.SetDeadline(time.Time{}) // Clear deadline after handshake
|
||||
|
||||
// 1. Send SessionRequest
|
||||
if err := sendSessionRequest(conn, hs); err != nil {
|
||||
return oops.Errorf("failed to send session request: %v", err)
|
||||
}
|
||||
|
||||
// 2. Receive SessionCreated
|
||||
if err := receiveSessionCreated(conn, hs); err != nil {
|
||||
return oops.Errorf("failed to receive session created: %v", err)
|
||||
}
|
||||
|
||||
// 3. Send SessionConfirm
|
||||
if err := sendSessionConfirm(conn, hs); err != nil {
|
||||
return oops.Errorf("failed to send session confirm: %v", err)
|
||||
}
|
||||
|
||||
// Handshake complete, derive session keys
|
||||
return deriveSessionKeys(hs)
|
||||
}
|
||||
|
||||
// PerformInboundHandshake handles a handshake initiated by a remote peer
|
||||
func PerformInboundHandshake(conn net.Conn, localKey crypto.PrivateKey) (*HandshakeState, error) {
|
||||
// Set deadline for the entire handshake process
|
||||
if err := conn.SetDeadline(time.Now().Add(NTCP2_HANDSHAKE_TIMEOUT)); err != nil {
|
||||
return nil, oops.Errorf("failed to set deadline: %v", err)
|
||||
}
|
||||
defer conn.SetDeadline(time.Time{}) // Clear deadline after handshake
|
||||
|
||||
// Create handshake state for responder
|
||||
hs := &HandshakeState{
|
||||
isInitiator: false,
|
||||
localStaticKey: localKey,
|
||||
timestamp: uint32(time.Now().Unix()),
|
||||
}
|
||||
|
||||
// Generate ephemeral keypair
|
||||
var err error
|
||||
hs.localEphemeral, err = crypto.GenerateX25519KeyPair()
|
||||
if err != nil {
|
||||
return nil, oops.Errorf("failed to generate ephemeral key: %v", err)
|
||||
}
|
||||
|
||||
// 1. Receive SessionRequest
|
||||
if err := receiveSessionRequest(conn, hs); err != nil {
|
||||
return nil, oops.Errorf("failed to receive session request: %v", err)
|
||||
}
|
||||
|
||||
// 2. Send SessionCreated
|
||||
if err := sendSessionCreated(conn, hs); err != nil {
|
||||
return nil, oops.Errorf("failed to send session created: %v", err)
|
||||
}
|
||||
|
||||
// 3. Receive SessionConfirm
|
||||
if err := receiveSessionConfirm(conn, hs); err != nil {
|
||||
return nil, oops.Errorf("failed to receive session confirm: %v", err)
|
||||
}
|
||||
|
||||
// Handshake complete, derive session keys
|
||||
if err := deriveSessionKeys(hs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return hs, nil
|
||||
}
|
||||
|
||||
// sendSessionRequest sends Message 1 (SessionRequest) to the remote peer
|
||||
func sendSessionRequest(conn net.Conn, hs *HandshakeState) error {
|
||||
// Implement according to NTCP2 spec
|
||||
// 1. Create and send X (ephemeral key) | Padding
|
||||
// TODO: Implement detailed Message 1 construction
|
||||
return nil
|
||||
}
|
||||
|
||||
// receiveSessionRequest processes Message 1 (SessionRequest) from remote
|
||||
func receiveSessionRequest(conn net.Conn, hs *HandshakeState) error {
|
||||
// Implement according to NTCP2 spec
|
||||
// TODO: Implement Message 1 processing
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendSessionCreated sends Message 2 (SessionCreated) to the remote peer
|
||||
func sendSessionCreated(conn net.Conn, hs *HandshakeState) error {
|
||||
// Implement according to NTCP2 spec
|
||||
// TODO: Implement Message 2 construction and sending
|
||||
return nil
|
||||
}
|
||||
|
||||
// receiveSessionCreated processes Message 2 (SessionCreated) from remote
|
||||
func receiveSessionCreated(conn net.Conn, hs *HandshakeState) error {
|
||||
// Implement according to NTCP2 spec
|
||||
// TODO: Implement Message 2 processing
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendSessionConfirm sends Message 3 (SessionConfirm) to the remote peer
|
||||
func sendSessionConfirm(conn net.Conn, hs *HandshakeState) error {
|
||||
// Implement according to NTCP2 spec
|
||||
// TODO: Implement Message 3 construction and sending
|
||||
return nil
|
||||
}
|
||||
|
||||
// receiveSessionConfirm processes Message 3 (SessionConfirm) from remote
|
||||
func receiveSessionConfirm(conn net.Conn, hs *HandshakeState) error {
|
||||
// Implement according to NTCP2 spec
|
||||
// TODO: Implement Message 3 processing
|
||||
return nil
|
||||
}
|
||||
|
||||
// deriveSessionKeys computes the session keys from the completed handshake
|
||||
func deriveSessionKeys(hs *HandshakeState) error {
|
||||
// Use shared secrets to derive session keys
|
||||
// TODO: Implement key derivation according to NTCP2 spec
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user