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

> Explore Shadowsocks 2022 vs legacy Shadowsocks in Xray-core. Understand cipher differences, pre-shared keys, and MD5 derivation for enhanced security and compatibility.

- Repository: [Project X Community, Not Porn-jet X Hub/Xray-core](https://github.com/XTLS/Xray-core)
- Tags: deep-dive
- Published: 2026-04-21

---

**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`](https://github.com/XTLS/Xray-core/blob/main/proxy/shadowsocks/config.go), the legacy `Account` struct stores the password, cipher type enumeration, and IV checking flags:

```go
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`](https://github.com/XTLS/Xray-core/blob/main/proxy/shadowsocks_2022/config.go), the 2022 variant uses a simplified structure containing only the pre-shared key:

```go
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`](https://github.com/XTLS/Xray-core/blob/main/proxy/shadowsocks/config.go) (lines 13-27). The `passwordToCipherKey` function repeatedly hashes the password to generate the required key size:

```go
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`](https://github.com/XTLS/Xray-core/blob/main/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`:

```go
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`](https://github.com/XTLS/Xray-core/blob/main/proxy/shadowsocks/config.go) (lines 62-92). The `getCipher()` method maps `CipherType` enumerations to specific AEAD implementations:

```go
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`](https://github.com/XTLS/Xray-core/blob/main/proxy/shadowsocks_2022/outbound.go) (lines 58-61) exposes this through configuration flags:

```go
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

```json
{
  "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

```json
{
  "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`](https://github.com/XTLS/Xray-core/blob/main/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`](https://github.com/XTLS/Xray-core/blob/main/proxy/shadowsocks/client.go), while Shadowsocks 2022 places its outbound handling and UoT support in [`proxy/shadowsocks_2022/outbound.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/shadowsocks_2022/outbound.go). For testing reference, see [`testing/scenarios/shadowsocks_2022_test.go`](https://github.com/XTLS/Xray-core/blob/main/testing/scenarios/shadowsocks_2022_test.go) which demonstrates 2022-specific usage scenarios.