XTLS/Xray-core · error
new crypto reader: %w
Error message
new crypto reader: %w
What it means
Constructing the decrypting stream cipher (newCryptoReader) over the connection reader with the negotiated shared secret failed. This wraps the AES/CFB8 (Minecraft standard) stream initialization — with a 16-byte secret the only realistic failure paths are an AES cipher construction error from a wrong key length or an error from the underlying reader wrapping. Given the 16-byte check upstream, seeing this error is rare.
Source
Thrown at transport/internet/finalmask/xmc/server.go:208
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)
}
c.writer, err = newCryptoWriter(c.writer, sharedSecret)
if err != nil {
return fmt.Errorf("new crypto writer: %w", err)
}
// verify password
receivedPassword := decryptedVerifyToken[4:]
if subtle.ConstantTimeCompare(receivedPassword, []byte(c.password)) != 1 {
writeDisconnectPacket(c.writer, `{"type":"translatable","translate":"multiplayer.disconnect.authservers_down"}`)
return fmt.Errorf("bad password")
}
if !found {
if err = writeDisconnectPacket(c.writer, `{"text":"You are not white-listed on this server!"}`); err != nil {
return fmt.Errorf("write unknown login profile disconnect: %w", err)
}View on GitHub (pinned to 7d214f8b09)
Solutions
- If you see this in production, diff recent changes to the shared-secret length validation and newCryptoReader's key handling.
- Add an assertion/test that newCryptoReader accepts any 16-byte key.
- Treat as fatal for the connection; do not fall back to plaintext.
Defensive patterns
Strategy: validation
Validate before calling
if len(sharedSecret) != 16 {
return fmt.Errorf("bad shared secret length: %d", len(sharedSecret))
} Try / catch
if _, err := newCryptoReader(c.reader, sharedSecret); err != nil {
// with a validated 16-byte key this is a code bug, not a runtime condition: fail loudly
return fmt.Errorf("new crypto reader: %w", err)
} Prevention
- Keep the 16-byte length check directly upstream of newCryptoReader/newCryptoWriter.
- Unit-test newCryptoReader with random 16-byte keys so regressions surface in CI, not prod.
- Never fall back to a plaintext reader on failure.
When it happens
Trigger: sharedSecret passed with an unexpected length despite the earlier check (only possible via code drift), aes.NewCipher failing on a non-16/24/32-byte key, or an error returned by a wrapper around c.reader at construction time.
Common situations: Almost exclusively a code-regression symptom: someone relaxed the length check or changed the cipher mode/key derivation; in a healthy build this branch is effectively unreachable.
Related errors
- new crypto writer: %w
- new crypto reader: %w
- new crypto writer: %w
- bad shared secret length: %d
- shadowsocks 2022 (multi-user): only blake3-aes-*-gcm methods
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/bafb49e8501480da.
Report an issue: GitHub.