More function deletions

This commit is contained in:
eyedeekay
2025-05-10 22:55:39 -04:00
parent c85822163b
commit 9fd3400585
2 changed files with 142 additions and 175 deletions

View File

@ -1,73 +1,16 @@
package ntcp
import (
"crypto/rand"
"io"
"math/big"
mrand "math/rand"
"net"
"time"
"github.com/go-i2p/go-i2p/lib/common/data"
"github.com/go-i2p/go-i2p/lib/crypto/curve25519"
"github.com/go-i2p/go-i2p/lib/transport/ntcp/handshake"
"github.com/go-i2p/go-i2p/lib/transport/ntcp/messages"
"github.com/samber/oops"
)
func (s *NTCP2Session) CreateSessionRequest() (*messages.SessionRequest, error) {
// Get our ephemeral key pair
ephemeralKey := make([]byte, 32)
if _, err := rand.Read(ephemeralKey); err != nil {
return nil, err
}
// Add random padding (implementation specific)
randomInt, err := rand.Int(rand.Reader, big.NewInt(16))
if err != nil {
return nil, err
}
padding := make([]byte, randomInt.Int64()) // Up to 16 bytes of padding
if err != nil {
return nil, err
}
netId, err := data.NewIntegerFromInt(2, 1)
if err != nil {
return nil, err
}
version, err := data.NewIntegerFromInt(2, 1)
if err != nil {
return nil, err
}
paddingLen, _, err := data.NewInteger([]byte{byte(len(padding))}, 1)
if err != nil {
return nil, err
}
//message3Part2Len, err := data.NewInteger()
//if err != nil {
// return nil, err
//}
timestamp, err := data.DateFromTime(s.GetCurrentTime())
if err != nil {
return nil, err
}
requestOptions := &messages.RequestOptions{
NetworkID: netId,
ProtocolVersion: version,
PaddingLength: paddingLen,
// Message3Part2Length: ,
Timestamp: timestamp,
}
return &messages.SessionRequest{
XContent: [32]byte(ephemeralKey),
Options: *requestOptions,
Padding: padding,
}, nil
}
// DecryptOptionsBlock decrypts the options block from a SessionRequest message
func (c *NTCP2Session) DecryptOptionsBlock(encryptedOptions []byte, obfuscatedX []byte, deobfuscatedX []byte) ([]byte, error) {
return c.PerformAEADOperation(
@ -79,6 +22,30 @@ func (c *NTCP2Session) DecryptOptionsBlock(encryptedOptions []byte, obfuscatedX
)
}
// addDelayForSecurity adds a small random delay to resist probing
func (c *NTCP2Session) addDelayForSecurity() {
// Sleep between 50-250ms to make timing attacks harder
// delay := time.Duration(50+mrand.Intn(200)) * time.Millisecond
delay := time.Duration(0)
time.Sleep(delay)
}
// validateTimestamp checks if the timestamp is within acceptable range
func (c *NTCP2Session) validateTimestamp(timestamp data.Date) error {
timestampTime := timestamp.Time()
now := c.GetCurrentTime()
diff := now.Sub(timestampTime)
// Allow ±60 seconds clock skew
if diff < -60*time.Second || diff > 60*time.Second {
log.Warnf("NTCP2: Rejecting SessionRequest - clock skew too large: %v", diff)
return oops.Errorf("clock skew too large: %v", diff)
}
return nil
}
// readEphemeralKey reads the ephemeral key (X) from the connection
func (c *NTCP2Session) readEphemeralKey(conn net.Conn) ([]byte, error) {
ephemeralKey := make([]byte, 32)
@ -113,113 +80,6 @@ func (c *NTCP2Session) processEphemeralKey(obfuscatedX []byte, hs *handshake.Han
return deobfuscatedX, nil
}
// readOptionsBlock reads the encrypted options block from the connection
func (c *NTCP2Session) readOptionsBlock(conn net.Conn) ([]byte, error) {
// Options block with auth tag is 16 bytes minimum
optionsBlock := make([]byte, 16)
if _, err := io.ReadFull(conn, optionsBlock); err != nil {
if err == io.ErrUnexpectedEOF {
return nil, oops.Errorf("incomplete options block: connection closed prematurely")
}
return nil, oops.Errorf("failed to read options block: %w", err)
}
return optionsBlock, nil
}
// processOptionsBlock decrypts and processes the options block
func (c *NTCP2Session) processOptionsBlock(
encryptedOptions []byte,
obfuscatedX []byte,
deobfuscatedX []byte,
hs *handshake.HandshakeState,
) (*messages.RequestOptions, error) {
// Decrypt options block
decryptedOptions, err := c.DecryptOptionsBlock(encryptedOptions, obfuscatedX, deobfuscatedX)
if err != nil {
c.addDelayForSecurity()
return nil, oops.Errorf("failed to decrypt options block: %w", err)
}
// Minimum size for valid options
if len(decryptedOptions) < 9 {
return nil, oops.Errorf("options block too small: %d bytes", len(decryptedOptions))
}
// Parse network ID
networkID, _, err := data.NewInteger([]byte{decryptedOptions[0]}, 1)
if err != nil {
return nil, oops.Errorf("failed to parse network ID: %w", err)
}
if networkID.Int() != 2 {
return nil, oops.Errorf("invalid network ID: %d", networkID.Int())
}
// Parse protocol version
protocolVersion, _, err := data.NewInteger([]byte{decryptedOptions[1]}, 1)
if err != nil {
return nil, oops.Errorf("failed to parse protocol version: %w", err)
}
if protocolVersion.Int() != 2 {
return nil, oops.Errorf("unsupported protocol version: %d", protocolVersion.Int())
}
// Parse padding length
paddingLength, _, err := data.NewInteger([]byte{decryptedOptions[2]}, 1)
if err != nil {
return nil, oops.Errorf("failed to parse padding length: %w", err)
}
// Parse message 3 part 2 length (2 bytes)
msg3p2Len, _, err := data.NewInteger(decryptedOptions[3:5], 2)
if err != nil {
return nil, oops.Errorf("failed to parse message 3 part 2 length: %w", err)
}
// Parse timestamp (4 bytes)
timestamp, _, err := data.NewDate(decryptedOptions[5:9])
if err != nil {
return nil, oops.Errorf("failed to parse timestamp: %w", err)
}
// Validate timestamp
if err := c.validateTimestamp(*timestamp); err != nil {
return nil, err
}
// Update handshake state
timestampVal := timestamp.Time()
hs.Timestamp = uint32(timestampVal.Unix())
// Construct the RequestOptions object
requestOptions := &messages.RequestOptions{
NetworkID: networkID,
ProtocolVersion: protocolVersion,
PaddingLength: paddingLength,
Message3Part2Length: msg3p2Len,
Timestamp: timestamp,
}
return requestOptions, nil
}
// validateTimestamp checks if the timestamp is within acceptable range
func (c *NTCP2Session) validateTimestamp(timestamp data.Date) error {
timestampTime := timestamp.Time()
now := c.GetCurrentTime()
diff := now.Sub(timestampTime)
// Allow ±60 seconds clock skew
if diff < -60*time.Second || diff > 60*time.Second {
log.Warnf("NTCP2: Rejecting SessionRequest - clock skew too large: %v", diff)
return oops.Errorf("clock skew too large: %v", diff)
}
return nil
}
// readAndValidatePadding reads the padding from the connection
func (c *NTCP2Session) readAndValidatePadding(conn net.Conn, paddingLen int) error {
// Check reasonable padding size to prevent DoS
@ -239,10 +99,3 @@ func (c *NTCP2Session) readAndValidatePadding(conn net.Conn, paddingLen int) err
// No need to validate padding content - it's random data
return nil
}
// addDelayForSecurity adds a small random delay to resist probing
func (c *NTCP2Session) addDelayForSecurity() {
// Sleep between 50-250ms to make timing attacks harder
delay := time.Duration(50+mrand.Intn(200)) * time.Millisecond
time.Sleep(delay)
}

View File

@ -2,6 +2,7 @@ package ntcp
import (
"crypto/rand"
"io"
"math/big"
"net"
@ -64,7 +65,42 @@ func (s *SessionRequestProcessor) MessageType() messages.MessageType {
// ProcessMessage implements handshake.HandshakeMessageProcessor.
func (s *SessionRequestProcessor) ProcessMessage(message messages.Message, hs *handshake.HandshakeState) error {
panic("unimplemented")
req, ok := message.(*messages.SessionRequest)
if !ok {
return oops.Errorf("expected SessionRequest message, got %T", message)
}
// Validate timestamp using existing method
if err := s.validateTimestamp(*req.Options.Timestamp); err != nil {
return err
}
// Store padding length for message 3 if provided
if req.Options.PaddingLength != nil {
paddingLen := req.Options.PaddingLength.Int()
hs.RemotePaddingLen = paddingLen
}
// Store message 3 part 2 length if provided
if req.Options.Message3Part2Length != nil {
hs.Message3Length = req.Options.Message3Part2Length.Int()
}
log.Debugf("NTCP2: Session request processed successfully")
return nil
}
// readOptionsBlock reads the encrypted options block from the connection
func (c *SessionRequestProcessor) readOptionsBlock(conn net.Conn) ([]byte, error) {
// Options block with auth tag is 16 bytes minimum
optionsBlock := make([]byte, 16)
if _, err := io.ReadFull(conn, optionsBlock); err != nil {
if err == io.ErrUnexpectedEOF {
return nil, oops.Errorf("incomplete options block: connection closed prematurely")
}
return nil, oops.Errorf("failed to read options block: %w", err)
}
return optionsBlock, nil
}
// ReadMessage reads a SessionRequest message from the connection
@ -76,19 +112,19 @@ func (p *SessionRequestProcessor) ReadMessage(conn net.Conn, hs *handshake.Hands
}
// 2. Process ephemeral key
deobfuscatedX, err := p.NTCP2Session.processEphemeralKey(obfuscatedX, hs)
deobfuscatedX, err := p.processEphemeralKey(obfuscatedX, hs)
if err != nil {
return nil, err
}
// 3. Read options block
encryptedOptions, err := p.NTCP2Session.readOptionsBlock(conn)
encryptedOptions, err := p.readOptionsBlock(conn)
if err != nil {
return nil, err
}
// 4. Process options block
options, err := p.NTCP2Session.processOptionsBlock(encryptedOptions, obfuscatedX, deobfuscatedX, hs)
options, err := p.processOptionsBlock(encryptedOptions, obfuscatedX, deobfuscatedX, hs)
if err != nil {
return nil, err
}
@ -186,4 +222,82 @@ func (p *SessionRequestProcessor) ObfuscateKey(message messages.Message, hs *han
return p.NTCP2Session.ObfuscateEphemeral(req.XContent[:])
}
// processOptionsBlock decrypts and processes the options block from the session request
func (p *SessionRequestProcessor) processOptionsBlock(
encryptedOptions []byte,
obfuscatedX []byte,
deobfuscatedX []byte,
hs *handshake.HandshakeState,
) (*messages.RequestOptions, error) {
// Decrypt options block
decryptedOptions, err := p.NTCP2Session.DecryptOptionsBlock(encryptedOptions, obfuscatedX, deobfuscatedX)
if err != nil {
p.addDelayForSecurity()
return nil, oops.Errorf("failed to decrypt options block: %w", err)
}
// Minimum size for valid options
if len(decryptedOptions) < 9 {
return nil, oops.Errorf("options block too small: %d bytes", len(decryptedOptions))
}
// Parse network ID
networkID, _, err := data.NewInteger([]byte{decryptedOptions[0]}, 1)
if err != nil {
return nil, oops.Errorf("failed to parse network ID: %w", err)
}
if networkID.Int() != 2 {
return nil, oops.Errorf("invalid network ID: %d", networkID.Int())
}
// Parse protocol version
protocolVersion, _, err := data.NewInteger([]byte{decryptedOptions[1]}, 1)
if err != nil {
return nil, oops.Errorf("failed to parse protocol version: %w", err)
}
if protocolVersion.Int() != 2 {
return nil, oops.Errorf("unsupported protocol version: %d", protocolVersion.Int())
}
// Parse padding length
paddingLength, _, err := data.NewInteger([]byte{decryptedOptions[2]}, 1)
if err != nil {
return nil, oops.Errorf("failed to parse padding length: %w", err)
}
// Parse message 3 part 2 length (2 bytes)
msg3p2Len, _, err := data.NewInteger(decryptedOptions[3:5], 2)
if err != nil {
return nil, oops.Errorf("failed to parse message 3 part 2 length: %w", err)
}
// Parse timestamp (4 bytes)
timestamp, _, err := data.NewDate(decryptedOptions[5:9])
if err != nil {
return nil, oops.Errorf("failed to parse timestamp: %w", err)
}
// Validate timestamp
if err := p.validateTimestamp(*timestamp); err != nil {
return nil, err
}
// Update handshake state
timestampVal := timestamp.Time()
hs.Timestamp = uint32(timestampVal.Unix())
// Construct the RequestOptions object
requestOptions := &messages.RequestOptions{
NetworkID: networkID,
ProtocolVersion: protocolVersion,
PaddingLength: paddingLength,
Message3Part2Length: msg3p2Len,
Timestamp: timestamp,
}
return requestOptions, nil
}
var _ handshake.HandshakeMessageProcessor = (*SessionRequestProcessor)(nil)