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

  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.