Shadowsocks 2022 vs Legacy Shadowsocks in Xray-core: Implementation Differences Explained

Shadowsocks 2022 delegates all cipher operations to the external sing-shadowsocks library and uses direct pre-shared keys without derivation, whereas the legacy implementation relies on built-in cipher suites with MD5-based password-to-key derivation and maintains compatibility with traditional Shadowsocks clients.

Xray-core from the XTLS repository maintains dual Shadowsocks implementations to balance backward compatibility with modern protocol requirements. While both proxy network traffic effectively, they differ significantly in architectural approach, key management, and supported cipher methods. Understanding these distinctions helps you choose between Shadowsocks 2022 and legacy Shadowsocks implementations based on your specific client ecosystem and security requirements.

Package Structure and Dependencies

The architectural split begins at the package level. Legacy Shadowsocks resides in proxy/shadowsocks and contains approximately 300 lines of cipher logic implemented directly in Xray-core. In contrast, Shadowsocks 2022 lives in proxy/shadowsocks_2022 and functions as a thin wrapper of roughly 160 lines that delegates encryption tasks to the external github.com/sagernet/sing-shadowsocks library.

This dependency difference means legacy implementations require modifying Xray-core source to add new cipher support, while Shadowsocks 2022 automatically inherits new AEAD methods when the external library updates.

Configuration Schema and Account Structure

The Account struct definitions in each package reveal fundamentally different approaches to credential management.

Legacy Account Definition

In proxy/shadowsocks/config.go, the legacy Account struct stores the password, cipher type enumeration, and IV checking flags:

type Account struct {
    Password   string      // user password
    CipherType CipherType  // enum (AES_128_GCM, CHACHA20_POLY1305, …)
    IvCheck    bool
}

Shadowsocks 2022 Account Definition

In proxy/shadowsocks_2022/config.go, the 2022 variant uses a simplified structure containing only the pre-shared key:

type Account struct {
    Key string // pre‑shared key (PSK) for the 2022 method
}

Legacy configurations require specifying both a password and cipher type (such as aes-128-gcm, chacha20-poly1305, or none), while Shadowsocks 2022 configurations reference the specific 2022 AEAD method (like 2022-blake3-aes-256-gcm) and provide the key directly.

Key Derivation and Cipher Implementation

The two implementations handle key material fundamentally differently, affecting how passwords transform into encryption keys.

Legacy MD5-Based Derivation

Legacy Shadowsocks converts user passwords to cipher keys using an MD5-based derivation function defined in proxy/shadowsocks/config.go (lines 13-27). The passwordToCipherKey function repeatedly hashes the password to generate the required key size:

func passwordToCipherKey(password []byte, keySize int32) []byte {
    md5Sum := md5.Sum(password)
    // repeat MD5 until keySize bytes are filled
}

This approach follows RFC 7465 style derivation with optional HKDF for AEAD ciphers.

Shadowsocks 2022 Direct Key Usage

The 2022 implementation in proxy/shadowsocks_2022/outbound.go (lines 46-55) bypasses custom derivation entirely. It passes the provided key directly to the external library via shadowaead_2022.NewWithPassword:

if C.Contains(shadowaead_2022.List, config.Method) {
    method, err := shadowaead_2022.NewWithPassword(config.Method, config.Key, nil)
    // …
}

This eliminates the MD5 derivation step and relies on the library's internal key handling for modern AEAD methods.

Cipher Selection and Method Validation

Legacy implementations select ciphers through an internal switch statement in proxy/shadowsocks/config.go (lines 62-92). The getCipher() method maps CipherType enumerations to specific AEAD implementations:

switch a.CipherType {
case CipherType_AES_128_GCM:
    return &AEADCipher{KeyBytes: 16, IVBytes: 16, AEADAuthCreator: createAesGcm}, nil
case CipherType_CHACHA20_POLY1305:
    return &AEADCipher{KeyBytes: 32, IVBytes: 32, AEADAuthCreator: createChaCha20Poly1305}, nil
// …
}

Shadowsocks 2022 validates methods against the shadowaead_2022.List constant from the sing-shadowsocks library. Available methods include 2022-specific variants like 2022-blake3-aes-256-gcm, with no support for legacy none or stream ciphers.

UDP-over-TCP Support

Only Shadowsocks 2022 includes built-in UDP-over-TCP (UoT) capabilities. The implementation in proxy/shadowsocks_2022/outbound.go (lines 58-61) exposes this through configuration flags:

if config.UdpOverTcp {
    o.uotClient = &uot.Client{Version: uint8(config.UdpOverTcpVersion)}
}

Legacy Shadowsocks lacks this feature, handling UDP traffic through standard means without TCP encapsulation options.

Practical Configuration Examples

Legacy Shadowsocks Server Configuration

{
  "inbounds": [
    {
      "port": 8388,
      "protocol": "shadowsocks",
      "settings": {
        "method": "aes-128-gcm",
        "password": "my‑legacy‑pwd",
        "udp": true,
        "network": "tcp,udp"
      }
    }
  ]
}

This configuration uses proxy/shadowsocks internals to derive the key from my‑legacy‑pwd using MD5-based derivation.

Shadowsocks 2022 Outbound Configuration

{
  "outbounds": [
    {
      "protocol": "shadowsocks-2022",
      "settings": {
        "servers": [
          {
            "address": "example.com",
            "port": 443,
            "method": "2022-blake3-aes-256-gcm",
            "key": "my‑psk‑2022"
          }
        ],
        "udpOverTcp": true,
        "udpOverTcpVersion": 1
      }
    }
  ]
}

The 2022 configuration passes my‑psk‑2022 directly to the sing-shadowsocks library without transformation.

Summary

  • Package Location: Legacy uses proxy/shadowsocks (~300 lines); 2022 uses proxy/shadowsocks_2022 (~160 lines).
  • Dependencies: Legacy implements ciphers internally; 2022 delegates to github.com/sagernet/sing-shadowsocks.
  • Key Derivation: Legacy applies MD5-based passwordToCipherKey derivation; 2022 uses direct PSK keys.
  • Configuration: Legacy requires Password and CipherType; 2022 requires Key and 2022-specific Method.
  • Cipher Support: Legacy supports AES-GCM, CHACHA20-POLY1305, XCHACHA20-POLY1305, and NONE; 2022 supports 2022-method AEAD ciphers only.
  • Features: Only Shadowsocks 2022 supports UDP-over-TCP via the UdpOverTcp flag.

Frequently Asked Questions

Can Shadowsocks 2022 clients connect to legacy Shadowsocks servers?

No, the two implementations are not interoperable. Shadowsocks 2022 requires the 2022 AEAD protocol methods implemented in the sing-shadowsocks library, while legacy servers use MD5-based key derivation and different cipher initialization. You must match the client and server implementations by protocol version.

Why does Shadowsocks 2022 eliminate MD5-based key derivation?

Shadowsocks 2022 removes the MD5 derivation step to align with modern cryptographic standards and simplify the key management process. By accepting the pre-shared key directly in the Key field of proxy/shadowsocks_2022/config.go, the protocol eliminates the weaknesses associated with MD5 hashing and reduces implementation complexity by delegating crypto operations to the specialized sing-shadowsocks library.

When should I choose legacy Shadowsocks over Shadowsocks 2022?

Choose legacy Shadowsocks when you need compatibility with older clients that do not support the 2022 protocol, or when you require specific cipher methods like none (unencrypted) for debugging. Opt for Shadowsocks 2022 when using modern clients that support the 2022 AEAD methods, or when you need UDP-over-TCP functionality for traversing restrictive networks.

Which source files define the outbound handlers for each implementation?

The legacy implementation defines its client logic in proxy/shadowsocks/client.go, while Shadowsocks 2022 places its outbound handling and UoT support in proxy/shadowsocks_2022/outbound.go. For testing reference, see testing/scenarios/shadowsocks_2022_test.go which demonstrates 2022-specific usage scenarios.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →