golang/go · error

crypto/cipher: use of GCM with non-AES ciphers is not…

Error message

crypto/cipher: use of GCM with non-AES ciphers is not allowed in FIPS 140-only mode

What it means

Inside newGCM (the internal constructor shared by NewGCM/NewGCMWithNonceSize/NewGCMWithTagSize), a type assertion checks that cipher is *aes.Block. If it is not and FIPS-only mode is on, the constructor refuses: FIPS 140-3 only certifies AES-based GCM. The non-AES fallback (newGCMFallback) is unreachable in FIPS-only mode.

Solutions

  1. Construct the block with aes.NewCipher(key) so the value passed to NewGCM* is *aes.Block.
  2. Drop non-AES cipher support entirely — GCM is only NIST-approved for AES anyway.
  3. For test stubs, gate the non-AES path behind a build tag that disables FIPS-only in tests.

Example fix

// before
block, _ := des.NewCipher(key) // non-AES
a, err := cipher.NewGCM(block) // "non-AES ciphers is not allowed"

// after
block, _ := aes.NewCipher(aesKey)
a, err := cipher.NewGCMWithRandomNonce(block)
Defensive patterns

Strategy: type-guard

Validate before calling

func newAEADFIPS(block cipher.Block) (cipher.AEAD, error) {
    if _, ok := block.(*aes.Block); !ok {
        return nil, errors.New("FIPS GCM requires an *aes.Block; construct with aes.NewCipher")
    }
    return cipher.NewGCMWithRandomNonce(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 && strings.Contains(err.Error(), "non-AES ciphers") {
    aesBlock, _ := aes.NewCipher(aesKey)
    a, err = cipher.NewGCMWithRandomNonce(aesBlock)
}

Prevention

When it happens

Trigger: Calling any NewGCM* constructor with a Block that is not *aes.Block (e.g., a *des.NonceSize, a *camellia block, or a custom Block implementation) while FIPS-only mode is enforced. Reachable when a caller smuggles a non-AES block through the Block interface.

Common situations: Generic encryption wrappers that accept cipher.Block and feed it to NewGCM; legacy code paths that still construct DES/Blowfish blocks; testing stubs that implement Block but are not AES.

Related errors


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

Appendix: source

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

// Counter Mode, which generates tags with the given length.
//
// Tag sizes between 12 and 16 bytes are allowed.
//
// Only use this function if you require compatibility with an existing
// cryptosystem that uses non-standard tag lengths. All other users should use
// [NewGCM], which is more resistant to misuse.
func NewGCMWithTagSize(cipher Block, tagSize 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, gcmStandardNonceSize, tagSize)
}

func newGCM(cipher Block, nonceSize, tagSize int) (AEAD, error) {
	c, ok := cipher.(*aes.Block)
	if !ok {
		if fips140only.Enforced() {
			return nil, errors.New("crypto/cipher: use of GCM with non-AES ciphers is not allowed in FIPS 140-only mode")
		}
		return newGCMFallback(cipher, nonceSize, tagSize)
	}
	// We don't return gcm.New directly, because it would always return a non-nil
	// AEAD interface value with type *gcm.GCM even if the *gcm.GCM is nil.
	g, err := gcm.New(c, nonceSize, tagSize)
	if err != nil {
		return nil, err
	}
	return g, nil
}

// NewGCMWithRandomNonce returns the given cipher wrapped in Galois Counter
// Mode, with randomly-generated nonces. The cipher must have been created by
// [crypto/aes.NewCipher].
//
// It generates a random 96-bit nonce, which is prepended to the ciphertext by Seal,
// and is extracted from the ciphertext by Open. The NonceSize of the AEAD is zero,

View on GitHub (pinned to b6b368adc5)