# How the Xray REALITY Protocol Works: TLS Fingerprint Stealing Explained

> Discover how Xray REALITY protocol achieves TLS fingerprint stealing to make traffic indistinguishable from HTTPS. Learn about its obfuscation and peer authentication.

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

---

**REALITY is a TLS 1.3 obfuscation layer in Xray-core that copies genuine browser fingerprints via the uTLS library while secretly authenticating peers by encrypting metadata inside the TLS Session ID using a pre-shared X25519 public key—making traffic indistinguishable from standard HTTPS.**

The REALITY protocol (often called XTLS REALITY) is an advanced obfuscation transport implemented in the [XTLS/Xray-core](https://github.com/XTLS/Xray-core) repository. It enables clients to masquerade as legitimate HTTPS traffic by "stealing" real browser TLS fingerprints while simultaneously establishing a cryptographically authenticated tunnel between client and server.

## The Six-Step REALITY Handshake

The protocol operates by intercepting and modifying the standard TLS 1.3 handshake without breaking compatibility. Here is the exact sequence implemented in the source code:

### 1. Selecting the Browser Fingerprint

The process begins in [`transport/internet/reality/reality.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/reality/reality.go) at lines 133-137, where the client calls `tls.GetFingerprint(config.Fingerprint)`:

```go
fingerprint := tls.GetFingerprint(config.Fingerprint)

```

The user configures this via the `fingerprint` field (e.g., `"chrome"`, `"firefox"`, or `"randomized"`). This instructs the uTLS library to replicate the exact `ClientHello` layout of that browser—including cipher suites, extensions, order, GREASE values, and padding.

### 2. Injecting Metadata into the Session ID

After `utls.UClient` creates the TLS connection, Xray rewrites the **Session ID** field of the `ClientHello` (lines 41-49 in [`reality.go`](https://github.com/XTLS/Xray-core/blob/main/reality.go)). The 32-byte Session ID structure contains:

- **Bytes 0-2**: Xray version bytes
- **Mid section**: Current Unix timestamp
- **End section**: The user-defined `short-id` (used for server-side routing)

The Session ID is a free-form 32-byte blob in TLS 1.3, allowing Xray to encode authentication metadata without breaking TLS format compliance.

### 3. Deriving the Shared Secret

Once the server responds with its `ServerHello`, the client performs an **X25519** (or ML-KEM) Elliptic Curve Diffie-Hellman operation using the server's public key (`config.PublicKey`) and the `KeyShare` value offered by the server (lines 52-66):

```go
sharedSecret, err := curve25519.X25519(privateKey, serverKeyShare)

```

The raw shared secret is then fed to **HKDF-SHA256** with the client's `ClientHello.random[:20]` and the label `"REALITY"` (line 67). This produces a 32-byte **AuthKey** that only the client and server can compute, as the server's private key never traverses the network.

### 4. AEAD Encryption of Session Data

Using `crypto.NewAesGcm(AuthKey)`, the client seals the first 16 bytes of the Session ID with the remaining portion of `ClientHello.random` serving as the nonce (lines 70-75). The ciphertext overwrites the original Session ID in the `ClientHello.raw` buffer:

```go
aesgcm, _ := cipher.NewGCM(block)
ciphertext := aesgcm.Seal(nil, nonce, sessionID[:16], nil)
copy(sessionID[:16], ciphertext)

```

This step ensures that while the TLS structure matches a real browser, the payload contains encrypted authentication material.

### 5. Server-Side Verification

In `UConn.VerifyPeerCertificate` (lines 76-115 of [`reality.go`](https://github.com/XTLS/Xray-core/blob/main/reality.go)), the server validates the client by:

1. Extracting the client's public key from the leaf certificate
2. Computing `HMAC-SHA512(AuthKey, pubKey)`
3. Verifying this matches the certificate's signature

If the configuration includes `Mldsa65Verify`, the server additionally checks an ML-DSA-65 signature over the same HMAC. This cryptographic proof confirms the client possesses the shared secret derived from the pre-configured public key.

### 6. Graceful Fallback Handling

If verification fails, Xray optionally launches a spider goroutine (starting at line 86) that makes harmless HTTP requests to the destination. This provides plausible deniability by mimicking typical web browsing behavior rather than dropping the connection abruptly.

## How TLS Fingerprint Stealing Works

The "fingerprint stealing" mechanism relies on the **uTLS** library's ability to clone real browser handshakes. Rather than generating a synthetic fingerprint, Xray passes a `ClientHelloID` (such as `chrome`) to `utls.UClient`, which constructs a binary-identical `ClientHello` to what the actual browser would send.

Critically, all REALITY modifications—including Session ID injection and AEAD encryption—occur **after** the `ClientHello` has been constructed. This means:

- **Cipher suites**, **extensions**, **GREASE values**, and **padding** match the selected browser exactly
- **Passive observers** (including Deep Packet Inspection systems) see only a standard TLS 1.3 handshake
- **No additional protocol extensions** are added that might trigger detection

The result is traffic that appears indistinguishable from the chosen browser while containing hidden authentication data accessible only to the REALITY server.

## Implementation and Configuration

### JSON Configuration Example

To deploy REALITY in Xray-core, configure the outbound stream settings as follows:

```json
{
  "outbounds": [
    {
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "example.com",
            "port": 443,
            "users": [{ "id": "YOUR-UUID", "encryption": "none" }]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "reality",
        "realitySettings": {
          "publicKey": "d8f5a2e3…",
          "shortId": "abcd1234",
          "fingerprint": "chrome",
          "serverName": "example.com"
        }
      }
    }
  ]
}

```

The `fingerprint` field determines which browser signature to steal, while `publicKey` contains the server's X25519 public key used for the ECDH exchange.

### Programmatic Implementation in Go

For developers integrating REALITY directly:

```go
package main

import (
    "context"
    "log"
    "time"

    "github.com/xtls/xray-core/common/net"
    "github.com/xtls/xray-core/transport/internet/reality"
    "github.com/xtls/xray-core/transport/internet/reality/config"
)

func main() {
    dest := net.ParseDestination("tcp:example.com:443")
    raw, _ := net.DialTCP(dest)

    cfg := &config.Config{
        Fingerprint: "chrome",
        ServerName:  "example.com",
        PublicKey:   []byte{0x02, 0x5a},
        ShortId:     []byte{0xab, 0xcd, 0x12, 0x34},
        Show:        true,
    }

    conn, err := reality.UClient(raw, cfg, context.Background(), dest)
    if err != nil {
        log.Fatalf("REALITY handshake failed: %v", err)
    }
    defer conn.Close()
    
    _ = conn.SetDeadline(time.Now().Add(5 * time.Second))
}

```

The `reality.UClient` function (defined in [`transport/internet/reality/reality.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/reality/reality.go)) orchestrates the entire process: fingerprint selection, `ClientHello` construction, Session ID manipulation, and cryptographic verification.

## Key Source Files

| File | Purpose |
|------|---------|
| [`transport/internet/reality/reality.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/reality/reality.go) | Core implementation including `UClient`, `VerifyPeerCertificate`, ECDH, HKDF, and AEAD operations |
| [`transport/internet/reality/config.pb.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/reality/config.pb.go) | Protocol buffer definitions for the Config struct (public key, short-id, fingerprint) |
| [`transport/internet/tls/tls.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/tls/tls.go) | Registry of available uTLS fingerprints (`PresetFingerprints`, `ModernFingerprints`) |
| [`transport/internet/tcp/hub.go`](https://github.com/XTLS/Xray-core/blob/main/transport/internet/tcp/hub.go) | Server-side invocation of `reality.Server` for inbound connections (lines 115-122) |
| [`infra/conf/transport_internet.go`](https://github.com/XTLS/Xray-core/blob/main/infra/conf/transport_internet.go) | JSON/YAML configuration parsing and validation (lines 653-700) |

## Summary

- **REALITY** is a TLS 1.3 obfuscation layer that authenticates peers while mimicking legitimate browser traffic.
- **Fingerprint stealing** works by copying real browser `ClientHello` structures via uTLS, then modifying only the Session ID field after construction.
- **Authentication** uses X25519/ML-KEM ECDH to derive a shared secret, which encrypts routing metadata inside the Session ID via AES-GCM.
- **Server verification** checks HMAC-SHA512 signatures against the client certificate, optionally strengthened with ML-DSA-65.
- **Implementation** requires only a public key and fingerprint selection in Xray-core configuration files.

## Frequently Asked Questions

### How does REALITY steal TLS fingerprints without detection?

REALITY uses the uTLS library to replicate the exact binary layout of a real browser's `ClientHello`, including cipher suites, extensions, and GREASE values. Because all REALITY-specific modifications (Session ID encryption) occur after the initial `ClientHello` construction, passive network observers see only a standard TLS handshake that matches the selected browser signature—typically Chrome or Firefox—making the traffic indistinguishable from normal HTTPS browsing.

### What encryption algorithms secure the REALITY handshake?

The protocol uses **X25519** (or **ML-KEM** for post-quantum variants) for Elliptic Curve Diffie-Hellman key exchange, **HKDF-SHA256** for key derivation using the label `"REALITY"`, and **AES-GCM** for AEAD encryption of the Session ID. Server authentication optionally employs **ML-DSA-65** signatures over HMAC-SHA512 digests when configured for post-quantum resistance.

### Can REALITY traffic be blocked by standard DPI systems?

Standard Deep Packet Inspection systems that rely on TLS fingerprint analysis typically cannot distinguish REALITY traffic from legitimate browser connections because the outer fingerprint matches perfectly. However, active probing or sophisticated behavioral analysis might still identify patterns, though the optional spider fallback mechanism (making HTTP requests on verification failure) provides additional deniability by mimicking regular web browsing behavior.

### What is the purpose of the short-id in REALITY configuration?

The `short-id` is an 8-byte routing identifier embedded within the encrypted Session ID (as implemented in lines 41-49 of [`reality.go`](https://github.com/XTLS/Xray-core/blob/main/reality.go)). It allows the server to route connections to different internal services or identify specific users immediately upon decrypting the Session ID, before the full TLS handshake completes and without transmitting additional identifiable metadata in plaintext.