golang/go · error

crypto/cipher: use of GCM with arbitrary IVs is not allowed

Error message

crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce

What it means

When FIPS 140-only mode is enforced (the toolchain was built with GOEXPERIMENT=fips140 and the process opted in via GOFIPS=1, or the fips140-only toggle is otherwise active), cipher.NewGCM refuses to construct a GCM AEAD with caller-controlled nonces. FIPS 140-3 guidance requires either random nonces or a counter-based construction, supplied by NewGCMWithRandomNonce.

Source

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

	"crypto/internal/fips140/alias"
	"crypto/internal/fips140only"
	"crypto/subtle"
	"errors"
	"internal/byteorder"
)

const (
	gcmBlockSize         = 16
	gcmStandardNonceSize = 12
	gcmTagSize           = 16
	gcmMinimumTagSize    = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.
)

// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode
// with the standard nonce length.
func NewGCM(cipher Block) (AEAD, error) {
	if fips140only.Enforced() {
		return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
	}
	return newGCM(cipher, gcmStandardNonceSize, gcmTagSize)
}

// NewGCMWithNonceSize returns the given 128-bit, block cipher wrapped in Galois
// Counter Mode, which accepts nonces of the given length. The length must not
// be zero.
//
// Only use this function if you require compatibility with an existing
// cryptosystem that uses non-standard nonce lengths. All other users should use
// [NewGCM], which is faster and more resistant to misuse.
func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
	if fips140only.Enforced() {
		return nil, errors.New("crypto/cipher: use of GCM with arbitrary IVs is not allowed in FIPS 140-only mode, use NewGCMWithRandomNonce")
	}
	return newGCM(cipher, size, gcmTagSize)
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Switch to cipher.NewGCMWithRandomNonce(block), which generates a random 96-bit nonce per Seal call.
  2. If you need deterministic encryption for compatibility, run the binary with FIPS-only mode disabled (GOFIPS=0 or do not opt in) — but verify this is acceptable to your compliance posture.
  3. Refactor wire formats that previously transmitted nonce separately so they accept the prepended-random-nonce layout produced by NewGCMWithRandomNonce.
  4. If you must keep arbitrary IVs for protocol compatibility, document a compensating control (e.g., a separate audit log) per your FIPS security policy.

Example fix

// before
a, err := cipher.NewGCM(block) // fails in FIPS-only mode

// after
a, err := cipher.NewGCMWithRandomNonce(block)
if err != nil { return err }
ct := a.Seal(nil, nil, plaintext, nil) // nonce generated + prepended
Defensive patterns

Strategy: type-guard

Validate before calling

// Decide at construction time based on whether FIPS-only mode is on.
// (You usually know this from build/deploy flags.)
func newAEAD(block cipher.Block) (cipher.AEAD, error) {
    if fipsEnabled() {
        return cipher.NewGCMWithRandomNonce(block)
    }
    return cipher.NewGCM(block)
}

Type guard

func isAESBlock(b cipher.Block) bool {
    _, ok := b.(*aes.Block)
    return ok
}

Try / catch

a, err := cipher.NewGCM(block)
if err != nil {
    if strings.Contains(err.Error(), "FIPS 140-only mode") {
        a, err = cipher.NewGCMWithRandomNonce(block)
        if err != nil { return err }
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: Calling cipher.NewGCM(block) while fips140only.Enforced() returns true. The check fires before any AEAD is allocated, so the error is returned directly from the constructor.

Common situations: Running a Go FIPS build in a regulated environment (US federal, healthcare, finance), upgrading a service that previously used arbitrary-IV GCM to a FIPS-only toolchain, or shipping a binary in a container whose base image set GOFIPS=1.

Related errors


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