add custom handshake manager

This commit is contained in:
eyedeekay
2025-03-25 18:37:14 -04:00
parent d0b81d9ce9
commit d236f19f81
2 changed files with 204 additions and 0 deletions

View File

@ -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,

View 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
}