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.

Solutions

  1. 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).
  2. Re-sync credentials after a password rotation and redeploy both sides.
  3. Log addr on mismatch to detect probing clients, but do not echo which side mismatched.
  4. 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

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


AI-assisted analysis of txthinking/brook@5cd13ef3b1 (2026-09-06). Data as JSON: /api/errors/64f664e90a2c1aa3. Report an issue: GitHub.

Appendix: 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)