diff --git a/service/xboard/service.go b/service/xboard/service.go index 14e45b11..c82ef6c4 100644 --- a/service/xboard/service.go +++ b/service/xboard/service.go @@ -3,6 +3,8 @@ package xboard import ( "bytes" "context" + "crypto/sha256" + "encoding/base64" "encoding/json" "fmt" "io" @@ -23,6 +25,19 @@ import ( "github.com/sagernet/sing/service" ) +func fixSSKey(key string, length int) string { + if key == "" { + return "" + } + // Try to decode as-is first + if data, err := base64.StdEncoding.DecodeString(key); err == nil && len(data) == length { + return key + } + // Use SHA256 to derive a fixed-length key from the password + hash := sha256.Sum256([]byte(key)) + return base64.StdEncoding.EncodeToString(hash[:length]) +} + func RegisterService(registry *boxService.Registry) { boxService.Register[option.XBoardServiceOptions](registry, C.TypeXBoard, NewService) } @@ -303,13 +318,26 @@ func (s *Service) setupNode() error { } inboundOptions = &vmessOptions case "shadowsocks": + method := inner.Cipher + serverKey := inner.ServerKey + if method == "" { + method = "aes-256-gcm" + } + // Hardening for Shadowsocks 2022 + if len(method) >= 4 && method[:4] == "2022" { + keyLen := 32 + if len(method) >= 18 && method[13:16] == "128" { + keyLen = 16 + } + serverKey = fixSSKey(serverKey, keyLen) + } ssOptions := option.ShadowsocksInboundOptions{ ListenOptions: option.ListenOptions{ Listen: listenAddr, ListenPort: uint16(inner.Port), }, - Method: inner.Cipher, - Password: inner.ServerKey, + Method: method, + Password: serverKey, } inboundOptions = &ssOptions case "trojan":