ginuerzh/gost · error

ciphertext too short

Error message

ciphertext too short

What it means

decrypt for QUIC packets requires the ciphertext blob to carry at least a GCM nonce prefix; if the received datagram is shorter than gcm.NonceSize(), there is no room for the nonce and authentication cannot proceed, so it fails early with this error.

Source

Thrown at quic.go:333

	}

	return gcm.Seal(nonce, nonce, data, nil), nil
}

func (conn *quicCipherConn) decrypt(data []byte) ([]byte, error) {
	c, err := aes.NewCipher(conn.key)
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(c)
	if err != nil {
		return nil, err
	}

	nonceSize := gcm.NonceSize()
	if len(data) < nonceSize {
		return nil, errors.New("ciphertext too short")
	}

	nonce, ciphertext := data[:nonceSize], data[nonceSize:]
	return gcm.Open(nil, nonce, ciphertext, nil)
}

func tlsConfigQUICALPN(tlsConfig *tls.Config) *tls.Config {
	if tlsConfig == nil {
		panic("quic: tlsconfig is nil")
	}
	tlsConfigQUIC := tlsConfig.Clone()
	tlsConfigQUIC.NextProtos = []string{"http/3", "quic/v1"}
	return tlsConfigQUIC
}

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Verify the peer is actually the expected QUIC service using the same key/encryption scheme
  2. Check network path for datagram truncation (MTU, buggy NAT, fragmentation)
  3. Log and drop the offending datagram; a single bad packet doesn't require reconnecting
  4. Confirm both sides use the same cipher configuration (nonce size)

Example fix

// before
n, addr, err := conn.ReadFrom(buf) // assume all data is decryptable
// after
n, addr, err := conn.ReadFrom(buf)
if err != nil { continue }
if n < gcmStandardNonceSize { continue } // drop too-short packets before decrypt
Defensive patterns

Strategy: validation

Validate before calling

if n < gcmStandardNonceSize {
    continue // drop too-short datagram before decrypting
}

Try / catch

data, err := decrypt(buf[:n])
if err != nil {
    log.Log("dropping undecryptable packet:", err)
    continue
}

Prevention

When it happens

Trigger: ReadFrom receives a UDP datagram whose payload length is less than the AES-GCM nonce size after the packet is routed to decrypt — i.e. a truncated, empty, or non-encrypted packet.

Common situations: Random internet UDP noise/scanning hitting the QUIC port, an MTU/truncation issue, or a peer not using the expected encryption.

Related errors


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/10067f3c83160f71. Report an issue: GitHub.