Files
go-i2p/lib/transport/ntcp/handshake/handshake.go

123 lines
4.3 KiB
Go

package handshake
import (
"crypto/rand"
"net"
"time"
"github.com/go-i2p/common/router_info"
"github.com/go-i2p/crypto/curve25519"
"github.com/go-i2p/crypto/types"
"github.com/go-i2p/go-i2p/lib/transport/handshake"
"github.com/go-i2p/go-i2p/lib/transport/ntcp/messages"
"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 types.PrivateEncryptionKey
// remoteStaticKey is the remote router's long-term public key
RemoteStaticKey types.PublicKey
// localEphemeral is the temporary private key generated for this handshake
LocalEphemeral types.PrivateEncryptionKey
// remoteEphemeral is the temporary public key received from remote party
RemoteEphemeral types.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
// HandshakeHash is the cumulative hash of the handshake
HandshakeHash []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
// Message3Part1 is the first part of the message 3
Message3Part1 []byte
// Message3Part2 is the second part of the message 3
Message3Part2 []byte
// Message3Length is the length of message 3
Message3Length int
}
// GetHandshakeHash implements handshake.HandshakeState.
func (h *HandshakeState) GetHandshakeHash() []byte {
panic("unimplemented")
}
// MixHash implements handshake.HandshakeState.
func (h *HandshakeState) MixHash(data []byte) error {
panic("unimplemented")
}
// MixKey implements handshake.HandshakeState.
func (h *HandshakeState) MixKey(input []byte) ([]byte, error) {
panic("unimplemented")
}
// SetEphemeralTransformer implements handshake.HandshakeState.
func (h *HandshakeState) SetEphemeralTransformer(transformer handshake.KeyTransformer) {
panic("unimplemented")
}
// SetPrologue implements handshake.HandshakeState.
func (h *HandshakeState) SetPrologue(prologue []byte) error {
panic("unimplemented")
}
var _ handshake.HandshakeState = &HandshakeState{}
// NewHandshakeState creates a new handshake state for initiating a connection
func NewHandshakeState(localKey types.PrivateEncryptionKey, remoteKey types.PublicKey, ri *router_info.RouterInfo) (*HandshakeState, error) {
/*
NewHandshakeState creates and initializes a handshake state structure for NTCP2:
1. Initialize the state with local private key, remote public key, and router info
2. Set initiator flag to true (we're starting the connection)
3. Record current timestamp for handshake timing
4. Generate ephemeral Curve25519 keypair for this session
5. Generate random padding length (0-15 bytes) for message obfuscation
6. Return the initialized handshake state
*/
hs := &HandshakeState{
IsInitiator: true,
LocalStaticKey: localKey,
RemoteStaticKey: remoteKey,
RouterInfo: ri,
Timestamp: uint32(time.Now().Unix()),
}
// Generate ephemeral keypair
var err error
_, hs.LocalEphemeral, err = curve25519.GenerateKeyPair()
// 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
}
type HandshakeMessageProcessor interface {
CreateMessage(hs *HandshakeState) (messages.Message, error)
ReadMessage(conn net.Conn, hs *HandshakeState) (messages.Message, error)
ProcessMessage(message messages.Message, hs *HandshakeState) error
ObfuscateKey(msg messages.Message, hs *HandshakeState) ([]byte, error)
EncryptPayload(msg messages.Message, obfuscatedKey []byte, hs *HandshakeState) ([]byte, error)
GetPadding(msg messages.Message) []byte
MessageType() messages.MessageType
}