golang/go · error

crypto/cipher: incorrect nonce length given to SetNoncePrefi

Error message

crypto/cipher: incorrect nonce length given to SetNoncePrefixAndMask

What it means

Returned by GCMWithXORCounterNonce.SetNoncePrefixAndMask (the XOR-counter nonce variant used by QUIC) when the supplied nonce is not exactly gcmStandardNonceSize (12) bytes. The first 4 bytes are the fixed prefix and the last 8 bytes are the XOR mask, so a 12-byte input is mandatory.

Source

Thrown at src/crypto/internal/fips140/aes/gcm/gcm_nonces.go:231

	g      GCM
	ready  bool
	prefix uint32
	mask   uint64
	next   uint64
}

// SetNoncePrefixAndMask sets the fixed prefix and XOR mask for the nonces used
// in Seal. It must be called before the first call to Seal.
//
// The first 32 bits of nonce are used as the fixed prefix, and the last 64 bits
// are used as the XOR mask.
//
// Note that Seal expects the nonce to be already XOR'd with the mask. The mask
// is provided here only to allow Seal to enforce that the counter is strictly
// increasing.
func (g *GCMWithXORCounterNonce) SetNoncePrefixAndMask(nonce []byte) error {
	if len(nonce) != gcmStandardNonceSize {
		return errors.New("crypto/cipher: incorrect nonce length given to SetNoncePrefixAndMask")
	}
	if g.ready {
		return errors.New("crypto/cipher: SetNoncePrefixAndMask called twice or after first Seal")
	}
	g.prefix = byteorder.BEUint32(nonce[:4])
	g.mask = byteorder.BEUint64(nonce[4:])
	g.ready = true
	return nil
}

func (g *GCMWithXORCounterNonce) NonceSize() int { return gcmStandardNonceSize }

func (g *GCMWithXORCounterNonce) Overhead() int { return gcmTagSize }

// Seal implements the [cipher.AEAD] interface, checking that the nonce prefix
// is stable and that the counter is strictly increasing.
//
// It is not safe for concurrent use.

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure the IV is exactly 12 bytes (gcmStandardNonceSize).
  2. Prefer NewGCMForQUIC(cipher, iv) and validate iv length at the call site.
  3. If the source material is shorter/longer, derive a 12-byte value via HKDF rather than padding naively.

Example fix

// before
g.SetNoncePrefixAndMask(connID) // connID may be 8 or 20 bytes
// after
iv := make([]byte, 12)
hkdf.Expand(h, secret, []byte("quic iv")).Read(iv)
g.SetNoncePrefixAndMask(iv)
Defensive patterns

Strategy: validation

Validate before calling

func validQUICNonce(iv []byte) bool { return len(iv) == 12 }

if !validQUICNonce(iv) { return errors.New("QUIC IV must be 12 bytes") }
g, err := gcm.NewGCMForQUIC(block, iv)

Type guard

// n/a

Try / catch

if err := g.SetNoncePrefixAndMask(iv); err != nil {
    return fmt.Errorf("set nonce prefix: %w", err)
}

Prevention

When it happens

Trigger: Calling g.SetNoncePrefixAndMask(iv) with len(iv) != 12, or indirectly via NewGCMForQUIC(cipher, iv) with a wrong-length iv.

Common situations: Passing a QUIC connection ID-derived IV that was not padded/truncated to 12 bytes; passing a 16-byte AES-GCM IV by mistake; config-derived IV whose length varies.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/e73c0da5f185e9e9. Report an issue: GitHub.