{"record":{"id":"f9f391232728b0e1","repo":"XTLS/Xray-core","slug":"new-crypto-writer-w-f9f391","errorCode":null,"errorMessage":"new crypto writer: %w","messagePattern":"new crypto writer: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/internet/finalmask/xmc/server.go","lineNumber":213,"sourceCode":"\t\t}\n\n\t\tdecryptedVerifyToken, err = rsa.DecryptPKCS1v15(rand.Reader, c.rsaPrivateKey, encryptedVerifyToken)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"decrypt verify token: %w\", err)\n\t\t}\n\n\t\tif len(decryptedVerifyToken) < 4 || !bytes.Equal(verifyToken, decryptedVerifyToken[:4]) {\n\t\t\treturn fmt.Errorf(\"verify token mismatch\")\n\t\t}\n\n\t\tc.reader, err = newCryptoReader(c.reader, sharedSecret)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"new crypto reader: %w\", err)\n\t\t}\n\n\t\tc.writer, err = newCryptoWriter(c.writer, sharedSecret)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"new crypto writer: %w\", err)\n\t\t}\n\n\t\t// verify password\n\t\treceivedPassword := decryptedVerifyToken[4:]\n\n\t\tif subtle.ConstantTimeCompare(receivedPassword, []byte(c.password)) != 1 {\n\t\t\twriteDisconnectPacket(c.writer, `{\"type\":\"translatable\",\"translate\":\"multiplayer.disconnect.authservers_down\"}`)\n\t\t\treturn fmt.Errorf(\"bad password\")\n\t\t}\n\t\tif !found {\n\t\t\tif err = writeDisconnectPacket(c.writer, `{\"text\":\"You are not white-listed on this server!\"}`); err != nil {\n\t\t\t\treturn fmt.Errorf(\"write unknown login profile disconnect: %w\", err)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"unknown login profile\")\n\t\t}\n\n\t\tloginName := String(profile.Username)\n\t\tpropertyCount := Varint(1)","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/server.go#L195-L231","documentation":"Constructing the encrypting stream cipher (newCryptoWriter) over the connection writer with the negotiated shared secret failed. Symmetric with the crypto reader: it initializes AES/CFB8 in encrypt direction with the same 16-byte shared secret. Because the reader was already constructed with the identical key one line earlier, a failure here indicates a writer-side wrapping problem or code drift, not a bad secret.","triggerScenarios":"newCryptoWriter's internal aes.NewCipher or writer-wrapping returns an error; only reachable through code drift since the same key just succeeded in newCryptoReader.","commonSituations":"Custom transports replacing c.writer with something that errors when wrapped; refactors that changed newCryptoWriter's key handling independently of the reader.","solutions":["Diff newCryptoWriter against newCryptoReader — the key path should be identical; any asymmetry is the bug.","Unit-test both constructors with the same random 16-byte key.","On failure, tear down the whole connection (it is half-encrypted and unusable)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if len(sharedSecret) != 16 {\n    return fmt.Errorf(\"bad shared secret length: %d\", len(sharedSecret))\n}","typeGuard":null,"tryCatchPattern":"if _, err := newCryptoWriter(c.writer, sharedSecret); err != nil {\n    // reader already succeeded with this key; writer failure is a bug — tear down the connection\n    return fmt.Errorf(\"new crypto writer: %w\", err)\n}","preventionTips":["Construct reader and writer back-to-back with the same key, as the current code does.","Share one cipher-construction helper between reader and writer so they cannot drift.","On any crypto-layer construction failure, close the connection fully — half-encrypted sessions are unusable."],"tags":["crypto","aes","stream-cipher","unreachable-in-practice"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}