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

  1. If you see this in production, diff recent changes to the shared-secret length validation and newCryptoReader's key handling.
  2. Add an assertion/test that newCryptoReader accepts any 16-byte key.
  3. 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

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


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/bafb49e8501480da. Report an issue: GitHub.