XTLS/Xray-core · error
decrypt shared secret: %w
Error message
decrypt shared secret: %w
What it means
RSA PKCS#1 v1.5 decryption of the client-encrypted shared secret failed. The client encrypts a 16-byte AES shared secret with the server's public key from the encryption request; the server decrypts with its private key using rsa.DecryptPKCS1v15. Failure means the ciphertext was not produced with the matching public key, is malformed, or was tampered with.
Source
Thrown at transport/internet/finalmask/xmc/server.go:191
)
pkt, err = readPacket(c.reader)
if err != nil {
return fmt.Errorf("read encrypt response: %w", err)
}
if pkt.packetID != 0x01 {
return fmt.Errorf("bad encrypt response packet id")
}
err = pkt.readFields(&encryptedSharedSecret, &encryptedVerifyToken)
if err != nil {
return fmt.Errorf("read encrypt response: %w", err)
}
sharedSecret, err = rsa.DecryptPKCS1v15(rand.Reader, c.rsaPrivateKey, encryptedSharedSecret)
if err != nil {
return fmt.Errorf("decrypt shared secret: %w", err)
}
if len(sharedSecret) != 16 {
return fmt.Errorf("bad shared secret length: %d", len(sharedSecret))
}
decryptedVerifyToken, err = rsa.DecryptPKCS1v15(rand.Reader, c.rsaPrivateKey, encryptedVerifyToken)
if err != nil {
return fmt.Errorf("decrypt verify token: %w", err)
}
if len(decryptedVerifyToken) < 4 || !bytes.Equal(verifyToken, decryptedVerifyToken[:4]) {
return fmt.Errorf("verify token mismatch")
}
c.reader, err = newCryptoReader(c.reader, sharedSecret)
if err != nil {
return fmt.Errorf("new crypto reader: %w", err)
}View on GitHub (pinned to 7d214f8b09)
Solutions
- Verify the RSA keypair is self-consistent: check rsaPrivateKey.PublicKey equals the rsaPublicKey sent in the encryption request.
- Log (at debug) len(encryptedSharedSecret) versus the private key modulus size — mismatches immediately reveal truncation or a foreign key.
- If key rotation happened, restart or drain old client sessions so every client gets the current public key.
- Treat repeated failures from one source as hostile: rate-limit or ban, do not retry the handshake with the same key.
Example fix
// before
sharedSecret, err = rsa.DecryptPKCS1v15(rand.Reader, c.rsaPrivateKey, encryptedSharedSecret)
if err != nil {
return fmt.Errorf("decrypt shared secret: %w", err)
}
// after: include ciphertext size for diagnosis
sharedSecret, err := rsa.DecryptPKCS1v15(rand.Reader, c.rsaPrivateKey, encryptedSharedSecret)
if err != nil {
return fmt.Errorf("decrypt shared secret (ct len %d, key bits %d): %w",
len(encryptedSharedSecret), c.rsaPrivateKey.N.BitLen(), err)
} Defensive patterns
Strategy: validation
Validate before calling
// before decrypting, sanity-check ciphertext length against the key
if len(encryptedSharedSecret) != c.rsaPrivateKey.Size() {
return fmt.Errorf("shared secret ciphertext has wrong size %d (want %d)",
len(encryptedSharedSecret), c.rsaPrivateKey.Size())
} Try / catch
sharedSecret, err := rsa.DecryptPKCS1v15(rand.Reader, key, ct)
if err != nil {
// do not distinguish error types in logs: RSA error details are a padding-oracle side channel
return errors.New("encryption handshake rejected")
} Prevention
- Validate ciphertext length equals the private-key modulus size before calling DecryptPKCS1v15.
- Keep one RSA keypair per server process and serve it consistently to avoid stale-key clients.
- Return a generic error to the peer; never echo decryption error details.
When it happens
Trigger: The client encrypted the secret with a different/stale public key (server key rotated between connections), the ciphertext array is not exactly the key modulus size or is empty/truncated, a malicious client sends random bytes to probe the key, or the server's rsaPrivateKey does not correspond to rsaPublicKey in the connection config.
Common situations: Server RSA keypair regenerated while old clients replayed a cached key; client and server disagree on the key because a proxy rewrites the encryption request; fuzzing/attack traffic; a client library that pads or segments the secret incorrectly.
Related errors
- decrypt verify token: %w
- derive minecraft rsa key: %w
- server public key mismatch
- parse server public key: %w
- parse server public key: not rsa
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/101929ddefebd917.
Report an issue: GitHub.