golang/go · error

cipher: incorrect tag size given to GCM

Error message

cipher: incorrect tag size given to GCM

What it means

newGCMFallback (the generic GCM implementation used when the cipher is not AES) validates that tagSize is within [gcmMinimumTagSize=12, gcmBlockSize=16]. Values outside this range — including the natural-seeming 8 or 32 — are rejected because NIST SP 800-38D only permits final-authentication-tag lengths of 128, 120, 112, 104, 96, 64, and 32 bits, and the Go generic path restricts further to the 96..128-bit subset.

Source

Thrown at src/crypto/cipher/gcm.go:205

	}

	_, err := g.GCM.Open(out[:0], nonce, ciphertext, additionalData)
	if err != nil {
		return nil, err
	}
	return ret, nil
}

// gcmAble is an interface implemented by ciphers that have a specific optimized
// implementation of GCM. crypto/aes doesn't use this anymore, and we'd like to
// eventually remove it.
type gcmAble interface {
	NewGCM(nonceSize, tagSize int) (AEAD, error)
}

func newGCMFallback(cipher Block, nonceSize, tagSize int) (AEAD, error) {
	if tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize {
		return nil, errors.New("cipher: incorrect tag size given to GCM")
	}
	if nonceSize <= 0 {
		return nil, errors.New("cipher: the nonce can't have zero length")
	}
	if cipher, ok := cipher.(gcmAble); ok {
		return cipher.NewGCM(nonceSize, tagSize)
	}
	if cipher.BlockSize() != gcmBlockSize {
		return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
	}
	return &gcmFallback{cipher: cipher, nonceSize: nonceSize, tagSize: tagSize}, nil
}

// gcmFallback is only used for non-AES ciphers, which regrettably we
// theoretically support. It's a copy of the generic implementation from
// crypto/internal/fips140/aes/gcm/gcm_generic.go, refer to that file for more details.
type gcmFallback struct {
	cipher    Block

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Use one of {12, 13, 14, 15, 16} for tagSize.
  2. Default to NewGCM (tag size 16) unless you have a measured bandwidth constraint; 12 bytes is the minimum.
  3. If you truly need an 8-byte tag, you are outside GCM's allowed set — use a separate MAC construction.

Example fix

// before
a, err := cipher.NewGCMWithTagSize(block, 8) // "incorrect tag size"

// after
a, err := cipher.NewGCMWithTagSize(block, 12) // minimum allowed
Defensive patterns

Strategy: validation

Validate before calling

func validGCMTagSize(n int) error {
    const (
        gcmMinimumTagSize = 12
        gcmBlockSize      = 16
    )
    if n < gcmMinimumTagSize || n > gcmBlockSize {
        return fmt.Errorf("tag size %d outside [%d, %d]", n, gcmMinimumTagSize, gcmBlockSize)
    }
    return nil
}

Try / catch

a, err := cipher.NewGCMWithTagSize(block, tag)
if err != nil && strings.Contains(err.Error(), "incorrect tag size") {
    // Fall back to the standard 16-byte tag.
    a, err = cipher.NewGCM(block)
}

Prevention

When it happens

Trigger: Calling cipher.NewGCMWithTagSize(block, tagSize) with tagSize < 12 or > 16, where block is not *aes.Block (so newGCMFallback runs). On AES the same range is enforced inside gcm.New and surfaces a similar error.

Common situations: Trying to shorten the tag to 8 bytes for bandwidth, or extending it to 32 bytes for stronger (but unsupported) authentication; misreading the spec and assuming any positive length works.

Related errors


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