diff --git a/service/xboard/service.go b/service/xboard/service.go index fbcaf6c0..6386060e 100644 --- a/service/xboard/service.go +++ b/service/xboard/service.go @@ -3,8 +3,10 @@ package xboard import ( "bytes" "context" + "crypto/md5" "crypto/rand" "encoding/base64" + "encoding/hex" "encoding/json" "fmt" "io" @@ -27,17 +29,19 @@ import ( "github.com/sagernet/sing/service" ) -// ss2022UserKey prepares a user key for SS2022: -// Truncate UUID string to keyLen and encode as Base64 for sing-box. -func ss2022UserKey(identity string, keyLen int) string { - if len(identity) > keyLen { - identity = identity[:keyLen] - } else if len(identity) < keyLen { +// ss2022Key derives a secure 2022 key from a seed string (like UUID or ServerKey). +// Logic: base64(hex(md5(seed)))[:keyLen] -- this is a common panel pattern. +func ss2022Key(seed string, keyLen int) string { + h := md5.Sum([]byte(seed)) + hexStr := hex.EncodeToString(h[:]) // 32 characters + if len(hexStr) > keyLen { + hexStr = hexStr[:keyLen] + } else if len(hexStr) < keyLen { padded := make([]byte, keyLen) - copy(padded, []byte(identity)) - identity = string(padded) + copy(padded, []byte(hexStr)) + hexStr = string(padded) } - return base64.StdEncoding.EncodeToString([]byte(identity)) + return base64.StdEncoding.EncodeToString([]byte(hexStr)) } // ss2022KeyLength returns the required key length for a given SS2022 cipher. @@ -618,9 +622,11 @@ func (s *Service) setupNode() error { } if strings.Contains(method, "2022") { - // SS2022: server_key is used DIRECTLY as PSK (like V2bX) - ssOptions.Password = serverKey + // SS2022 key derivation for panel compatibility keyLen := ss2022KeyLength(method) + ssOptions.Password = ss2022Key(serverKey, keyLen) + + // Create a dummy user (will be replaced by syncUsers) // Create a dummy user (will be replaced by syncUsers) dummyKey := make([]byte, keyLen) @@ -892,13 +898,12 @@ func (s *Service) syncUsers() { } // V2bX/Xboard approach for SS2022 user key: - // Base64 encode the UUID string (clipped/padded to keyLen) if isSS2022 { originalKey := key - key = ss2022UserKey(key, ss2022KeyLen) + key = ss2022Key(key, ss2022KeyLen) if len(newUsers) == 0 { // Log first user's key derivation for debugging - s.logger.Info("SS2022 user key derivation: ID[:", ss2022KeyLen, "]=", originalKey[:min(ss2022KeyLen, len(originalKey))], " → b64_uPSK=", key) + s.logger.Info("SS2022 user key derivation: ID[:", ss2022KeyLen, "]=", originalKey, " → b64_PSK=", key) } }