txthinking/brook · error
Password is wrong
Error message
Password is wrong
What it means
Handle compares the caller-supplied password p against the first 32 bytes of the packet b. If bytes.Compare(p, b[:32]) != 0 the embedded credential does not match the expected password, so authentication fails and the connection setup is aborted with this error.
Source
Thrown at simplepacketserverconn.go:45
type SimplePacketServerConnFactory struct {
Conns map[string]*PacketConn
Lock *sync.Mutex
}
func NewSimplePacketServerConnFactory() *SimplePacketServerConnFactory {
return &SimplePacketServerConnFactory{
Conns: make(map[string]*PacketConn),
Lock: &sync.Mutex{},
}
}
func (f *SimplePacketServerConnFactory) Handle(addr *net.UDPAddr, b, p []byte, w func([]byte) (int, error), timeout int) (net.Conn, []byte, error) {
if len(b) < 32+4 {
return nil, nil, errors.New("data too small")
}
if bytes.Compare(p, b[:32]) != 0 {
return nil, nil, errors.New("Password is wrong")
}
i := int64(binary.BigEndian.Uint32(b[32 : 32+4]))
if time.Now().Unix()-i > 60 {
return nil, nil, errors.New("Expired request")
}
a, h, p, err := socks5.ParseBytesAddress(b[32+4:])
if err != nil {
return nil, nil, err
}
dst := socks5.ToAddress(a, h, p)
f.Lock.Lock()
c, ok := f.Conns[addr.String()+dst]
f.Lock.Unlock()
if ok {
_ = c.In(b[32+4+1+len(h)+2:])
return nil, nil, nil
}
f.Lock.Lock()View on GitHub (pinned to 5cd13ef3b1)
Solutions
- Verify the client's configured password exactly matches the server's 32-byte key (same bytes, same padding — exactly 32 bytes, no trailing NUL/newline mismatch).
- Re-sync credentials after a password rotation and redeploy both sides.
- Log addr on mismatch to detect probing clients, but do not echo which side mismatched.
- Hash/compare with a constant-time comparison (e.g. subtle.ConstantTimeCompare or hmac.Equal) if you control the code, and confirm key derivation is identical on both ends.
Example fix
// before (client) copy(buf, []byte(password)) // may be shorter/longer than 32 bytes // after key := sha256.Sum256([]byte(password)) // deterministic 32 bytes copy(buf, key[:])
Defensive patterns
Strategy: validation
Validate before calling
func passwordBytes(pw string) ([32]byte, error) {
var k [32]byte
b := []byte(pw)
if len(b) > 32 { return k, errors.New("password longer than 32 bytes") }
copy(k[:], b)
return k, nil
} Type guard
func is32ByteKey(b []byte) bool { return len(b) == 32 } Try / catch
conn, rest, err := factory.Handle(addr, b, password, w, timeout)
if err != nil {
if strings.Contains(err.Error(), "Password is wrong") {
return fmt.Errorf("authentication failed for %s: check shared key", addr)
}
return err
} Prevention
- Derive the 32-byte key deterministically (e.g. SHA-256 of the secret) on both sides.
- Rotate credentials atomically across client and server.
- Strip no/whitespace and encoding variations from configured passwords before use.
- Rate-limit or drop sources with repeated password mismatches.
- Use constant-time comparison if you control the comparison code.
When it happens
Trigger: Calling Handle where p (expected password) differs byte-for-byte from b[:32] (password embedded in the packet): client configured with the wrong password, encoding/padding differences, or a stale password after a server-side rotation.
Common situations: Password rotated on the server but not the client (or vice versa); trailing newline/whitespace or non-zero padding differences in the 32-byte field; clients pointing at the wrong server deployment; attackers probing the UDP endpoint.
Related errors
- socks5 server requires a clear IP for UDP, only port is not
- socks5 server requires a clear IP for UDP, only port is not
- Expired request
- invalid packet. length: ${len} address: ${a} ${h} ${p}
- quic max datagram size is 1197
AI-assisted analysis of txthinking/brook@5cd13ef3b1 (2026-09-06).
Data as JSON: /api/errors/64f664e90a2c1aa3.
Report an issue: GitHub.